chirp-0.3.1/ 0000755 0000161 0177776 00000000000 12130403637 014014 5 ustar jenkins nogroup 0000000 0000000 chirp-0.3.1/chirp.xsd 0000644 0000161 0000750 00000002446 11717005656 014217 0 ustar jenkins 0000000 0000000
chirp-0.3.1/PKG-INFO 0000644 0000161 0177776 00000000263 12130403637 015112 0 ustar jenkins nogroup 0000000 0000000 Metadata-Version: 1.0
Name: chirp
Version: 0.3.1
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN
chirp-0.3.1/setup.py 0000644 0000161 0177776 00000010760 12066005671 015536 0 ustar jenkins nogroup 0000000 0000000 import sys
import os
from chirp import CHIRP_VERSION
from chirp import *
import chirp
def staticify_chirp_module():
import chirp
init = file("chirp/__init__.py", "w")
print >>init, "CHIRP_VERSION = \"%s\"" % CHIRP_VERSION
print >>init, "__all__ = %s\n" % str(chirp.__all__)
init.close()
print "Set chirp.py::__all__ = %s" % str(chirp.__all__)
def win32_build():
from distutils.core import setup
import py2exe
try:
# if this doesn't work, try import modulefinder
import py2exe.mf as modulefinder
import win32com
for p in win32com.__path__[1:]:
modulefinder.AddPackagePath("win32com", p)
for extra in ["win32com.shell"]: #,"win32com.mapi"
__import__(extra)
m = sys.modules[extra]
for p in m.__path__[1:]:
modulefinder.AddPackagePath(extra, p)
except ImportError:
# no build path setup, no worries.
pass
staticify_chirp_module()
opts = {
"py2exe" : {
"includes" : "pango,atk,gobject,cairo,pangocairo,win32gui,win32com,win32com.shell,email.iterators,email.generator,gio",
"compressed" : 1,
"optimize" : 2,
"bundle_files" : 3,
# "packages" : ""
}
}
mods = []
for mod in chirp.__all__:
mods.append("chirp.%s" % mod)
opts["py2exe"]["includes"] += ("," + ",".join(mods))
setup(
zipfile=None,
windows=[{'script' : "chirpw",
'icon_resources': [(0x0004, 'share/chirp.ico')],
}],
options=opts)
def macos_build():
from setuptools import setup
import shutil
APP = ['chirp-%s.py' % CHIRP_VERSION]
shutil.copy("chirpw", APP[0])
DATA_FILES = [('../Frameworks',
['/opt/local/lib/libpangox-1.0.dylib']),
('../Resources/', ['/opt/local/lib/pango']),
]
OPTIONS = {'argv_emulation': True, "includes" : "gtk,atk,pangocairo,cairo"}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)
EXEC = 'bash ./build/macos/make_pango.sh /opt/local dist/chirp-%s.app' % CHIRP_VERSION
#print "exec string: %s" % EXEC
os.system(EXEC)
def default_build():
from distutils.core import setup
from glob import glob
os.system("make -C locale clean all")
desktop_files = glob("share/*.desktop")
#form_files = glob("forms/*.x?l")
image_files = glob("images/*")
_locale_files = glob("locale/*/LC_MESSAGES/CHIRP.mo")
stock_configs = glob("stock_configs/*")
locale_files = []
for f in _locale_files:
locale_files.append(("share/chirp/%s" % os.path.dirname(f), [f]))
print "LOC: %s" % str(locale_files)
xsd_files = glob("chirp*.xsd")
setup(
name="chirp",
packages=["chirp", "chirpui"],
version=CHIRP_VERSION,
scripts=["chirpw"],
data_files=[('share/applications', desktop_files),
('share/chirp/images', image_files),
('share/chirp', xsd_files),
('share/doc/chirp', ['COPYING']),
('share/pixmaps', ['share/chirp.png']),
('share/man/man1', ["share/chirpw.1"]),
('share/chirp/stock_configs', stock_configs),
] + locale_files)
def rpttool_build():
from distutils.core import setup
setup(name="rpttool",
packages=["chirp"],
version="0.3",
scripts=["rpttool"],
description="A frequency tool for ICOM D-STAR Repeaters",
data_files=[('/usr/sbin', ["tools/icomsio.sh"])],
)
def nuke_manifest(*files):
for i in ["MANIFEST", "MANIFEST.in"]:
if os.path.exists(i):
os.remove(i)
if not files:
return
f = file("MANIFEST.in", "w")
for fn in files:
print >>f, fn
f.close()
if sys.platform == "darwin":
macos_build()
elif sys.platform == "win32":
win32_build()
else:
if os.path.exists("rpttool"):
nuke_manifest("include tools/icomsio.sh", "include README.rpttool")
rpttool_build()
if os.path.exists("chirpui"):
nuke_manifest("include *.xsd",
"include share/*.desktop",
"include share/chirp.png",
"include share/*.1",
"include stock_configs/*",
"include COPYING")
default_build()
chirp-0.3.1/stock_configs/ 0000755 0000161 0177776 00000000000 12130403637 016647 5 ustar jenkins nogroup 0000000 0000000 chirp-0.3.1/stock_configs/US Calling Frequencies.csv 0000644 0000161 0000750 00000000576 11717005656 022057 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,URCALL,RPT1CALL,RPT2CALL
1,6m Call,52.525000,-,0.500000,,88.5,88.5,023,NN,FM,5.00,,,,,
2,2m Call,146.520000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
3,220 Call,223.500000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
4,70cm Call,446.000000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
chirp-0.3.1/stock_configs/US 60 meter channels (Dial).csv 0000644 0000161 0000750 00000000665 11717005656 022324 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,URCALL,RPT1CALL,RPT2CALL
1,60m CH1,5.330500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
2,60m CH2,3.346500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
3,60m CH3,5.357000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
4,60m CH4,5.371500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
5,60m CH5,5.403500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
chirp-0.3.1/stock_configs/Marine VHF Channels.csv 0000644 0000161 0000750 00000010166 12023560646 021267 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
0,MVHF L1,155.500000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
1,MVHF L2,155.525000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
2,MVHF F1,155.625000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
3,MVHF F2,155.775000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
4,MVHF F3,155.825000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
5,MVHF K06,156.300000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
6,MVHF K67,156.375000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
7,MVHF K08,156.400000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
8,MVHF K68,156.425000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
9,MVHF K09,156.450000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
10,MVHF K69,156.475000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
11,MVHF K10,156.500000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
12,MDSC K70,156.525000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
13,MVHF K11,156.550000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
14,MVHF K71,156.575000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
15,MVHF K12,156.600000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
16,MVHF K72,156.625000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
17,MVHF K13,156.650000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
18,MVHF K73,156.675000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
19,MVHF K14,156.700000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
20,MVHF K74,156.725000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
21,MVHF K15,156.750000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
22,MVHF K16,156.800000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
23,MVHF K17,156.850000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
24,MVHF K77,156.875000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
25,MVHF K60,160.625000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
26,MVHF K01,160.650000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
27,MVHF K61,160.675000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
28,MVHF K02,160.700000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
29,MVHF K62,160.725000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
30,MVHF K03,160.750000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
31,MVHF K63,160.775000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
32,MVHF K04,160.800000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
33,MVHF K64,160.825000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
34,MVHF K05,160.850000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
35,MVHF K65,160.875000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
36,MVHF K66,160.925000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
37,MVHF K07,160.950000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
38,MVHF K18,161.500000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
39,MVHF K78,161.525000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
40,MVHF K19,161.550000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
41,MVHF K79,161.575000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
42,MVHF K20,161.600000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,,
43,MVHF K80,161.625000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
44,MVHF K21,161.650000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
45,MVHF K81,161.675000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
46,MVHF K22,161.700000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
47,MVHF K82,161.725000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
48,MVHF K23,161.750000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
49,MVHF K83,161.775000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
50,MVHF K24,161.800000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
51,MVHF K84,161.825000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
52,MVHF K25,161.850000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
53,MVHF K85,161.875000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
54,MVHF K26,161.900000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
55,MVHF K86,161.925000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
56,MVHF K27,161.950000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
57,MAIS K87,161.975000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
58,MVHF K28,162.000000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
59,MAIS K88,162.025000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
chirp-0.3.1/stock_configs/US 60 meter channels (Center).csv 0000644 0000161 0000750 00000000665 11717005656 022673 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,URCALL,RPT1CALL,RPT2CALL
1,60m CH1,5.332000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
2,60m CH2,5.348000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
3,60m CH3,5.358500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
4,60m CH4,5.373000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
5,60m CH5,5.405000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
chirp-0.3.1/stock_configs/NOAA Weather Alert.csv 0000644 0000161 0000750 00000000712 12023560646 021056 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
1,NOAA1,162.4,,0,,88.5,88.5,23,NN,FM,5,,,,,
2,NOAA2,162.425,,0,,88.5,88.5,23,NN,FM,5,,,,,
3,NOAA3,162.45,,0,,88.5,88.5,23,NN,FM,5,,,,,
4,NOAA4,162.475,,0,,88.5,88.5,23,NN,FM,5,,,,,
5,NOAA5,162.5,,0,,88.5,88.5,23,NN,FM,5,,,,,
6,NOAA6,162.525,,0,,88.5,88.5,23,NN,FM,5,,,,,
7,NOAA7,162.55,,0,,88.5,88.5,23,NN,FM,5,,,,,
chirp-0.3.1/stock_configs/US MURS Channels.csv 0000644 0000161 0000750 00000000712 12023560646 020542 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
1,MURS 1,151.820000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,,
2,MURS 2,151.880000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,,
3,MURS 3,151.940000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,,
4,Blue Dot,154.570000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
5,Green Dot,154.600000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
chirp-0.3.1/stock_configs/EU LPD and PMR Channels.csv 0000644 0000161 0000750 00000011560 12023560646 021522 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
1,LPD 01,433.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
2,LPD 02,433.100000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
3,LPD 03,433.125000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
4,LPD 04,433.150000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
5,LPD 05,433.175000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
6,LPD 06,433.200000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
7,LPD 07,433.225000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
8,LPD 08,433.250000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
9,LPD 09,433.275000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
10,LPD 10,433.300000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
11,LPD 11,433.325000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
12,LPD 12,433.350000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
13,LPD 13,433.375000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
14,LPD 14,433.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
15,LPD 15,433.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
16,LPD 16,433.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
17,LPD 17,433.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
18,LPD 18,433.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
19,LPD 19,433.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
20,LPD 20,433.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
21,LPD 21,433.575000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
22,LPD 22,433.600000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
23,LPD 23,433.625000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
24,LPD 24,433.650000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
25,LPD 25,433.675000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
26,LPD 26,433.700000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
27,LPD 27,433.725000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
28,LPD 28,433.750000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
29,LPD 29,433.775000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
30,LPD 30,433.800000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
31,LPD 31,433.825000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
32,LPD 32,433.850000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
33,LPD 33,433.875000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
34,LPD 34,433.900000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
35,LPD 35,433.925000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
36,LPD 36,433.950000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
37,LPD 37,433.975000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
38,LPD 38,434.000000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
39,LPD 39,434.025000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
40,LPD 40,434.050000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
41,LPD 41,434.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
42,LPD 42,434.100000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
43,LPD 43,434.125000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
44,LPD 44,434.150000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
45,LPD 45,434.175000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
46,LPD 46,434.200000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
47,LPD 47,434.225000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
48,LPD 48,434.250000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
49,LPD 49,434.275000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
50,LPD 50,434.300000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
51,LPD 51,434.325000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
52,LPD 52,434.350000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
53,LPD 53,434.375000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
54,LPD 54,434.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
55,LPD 55,434.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
56,LPD 56,434.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
57,LPD 57,434.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
58,LPD 58,434.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
59,LPD 59,434.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
60,LPD 60,434.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
61,LPD 61,434.575000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
62,LPD 62,434.600000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
63,LPD 63,434.625000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
64,LPD 64,434.650000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
65,LPD 65,434.675000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
66,LPD 66,434.700000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
67,LPD 67,434.725000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
68,LPD 68,434.750000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
69,LPD 69,434.775000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
71,PMR 1,446.006250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
72,PMR 2,446.018750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
73,PMR 3,446.031250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
74,PMR 4,446.043750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
75,PMR 5,446.056250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
76,PMR 6,446.068750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
77,PMR 7,446.081250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
78,PMR 8,446.093750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
chirp-0.3.1/stock_configs/US FRS and GMRS Channels.csv 0000644 0000161 0000750 00000002754 12046141665 021673 0 ustar jenkins 0000000 0000000 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
1,FRS1,462.562500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
2,FRS2,462.587500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
3,FRS3,462.612500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
4,FRS4,462.637500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
5,FRS5,462.662500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
6,FRS6,462.687500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
7,FRS7,462.712500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
8,FRS8,467.562500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
9,FRS9,467.587500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
10,FRS10,467.612500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
11,FRS11,467.637500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
12,FRS12,467.662500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
13,FRS13,467.687500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
14,FRS14,467.712500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
15,GMRS1,462.550000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
16,GMRS2,462.575000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
17,GMRS3,462.600000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
18,GMRS4,462.625000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
19,GMRS5,462.650000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
20,GMRS6,462.675000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
21,GMRS7,462.700000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
22,GMRS8,462.725000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
chirp-0.3.1/COPYING 0000644 0000161 0000750 00000104513 11717005656 013423 0 ustar jenkins 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
chirp-0.3.1/setup.cfg 0000644 0000161 0000750 00000000223 11717005656 014202 0 ustar jenkins 0000000 0000000 [bdist_rpm]
requires = pyserial
packager = Dan Smith
description = A frequency tool for Icom D-STAR Repeaters
vendor = KK7DS
chirp-0.3.1/chirp_memory.xsd 0000644 0000161 0000750 00000010024 11717005656 015576 0 ustar jenkins 0000000 0000000
chirp-0.3.1/chirpui/ 0000755 0000161 0177776 00000000000 12130403637 015457 5 ustar jenkins nogroup 0000000 0000000 chirp-0.3.1/chirpui/dstaredit.py 0000644 0000161 0177776 00000013366 12130403635 020023 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
from chirpui import common, miscwidgets
WIDGETW = 80
WIDGETH = 30
class CallsignEditor(gtk.HBox):
__gsignals__ = {
"changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
}
def _cs_changed(self, listw, callid):
if callid == 0 and self.first_fixed:
return False
self.emit("changed")
return True
def make_list(self, width):
cols = [ (gobject.TYPE_INT, ""),
(gobject.TYPE_INT, ""),
(gobject.TYPE_STRING, _("Callsign")),
]
self.listw = miscwidgets.KeyedListWidget(cols)
self.listw.show()
self.listw.set_editable(1, True)
self.listw.connect("item-set", self._cs_changed)
rend = self.listw.get_renderer(1)
rend.set_property("family", "Monospace")
rend.set_property("width-chars", width)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add_with_viewport(self.listw)
sw.show()
return sw
def __init__(self, first_fixed=False, width=8):
gtk.HBox.__init__(self, False, 2)
self.first_fixed = first_fixed
self.listw = None
self.pack_start(self.make_list(width), 1, 1, 1)
def set_callsigns(self, calls):
if self.first_fixed:
st = 1
else:
st = 0
values = []
i = 1
for call in calls[st:]:
self.listw.set_item(i, i, call)
i += 1
def get_callsigns(self):
calls = []
keys = self.listw.get_keys()
for key in keys:
id, idx, call = self.listw.get_item(key)
calls.append(call)
if self.first_fixed:
calls.insert(0, "")
return calls
class DStarEditor(common.Editor):
def __cs_changed(self, cse):
job = None
print "Callsigns: %s" % cse.get_callsigns()
if cse == self.editor_ucall:
job = common.RadioJob(None,
"set_urcall_list",
cse.get_callsigns())
print "Set urcall"
elif cse == self.editor_rcall:
job = common.RadioJob(None,
"set_repeater_call_list",
cse.get_callsigns())
print "Set rcall"
elif cse == self.editor_mcall:
job = common.RadioJob(None,
"set_mycall_list",
cse.get_callsigns())
if job:
print "Submitting job to update call lists"
self.rthread.submit(job)
self.emit("changed")
def make_callsigns(self):
box = gtk.HBox(True, 2)
fixed = self.rthread.radio.get_features().has_implicit_calls
frame = gtk.Frame(_("Your callsign"))
self.editor_ucall = CallsignEditor(first_fixed=fixed)
self.editor_ucall.set_size_request(-1, 200)
self.editor_ucall.show()
frame.add(self.editor_ucall)
frame.show()
box.pack_start(frame, 1, 1, 0)
frame = gtk.Frame(_("Repeater callsign"))
self.editor_rcall = CallsignEditor(first_fixed=fixed)
self.editor_rcall.set_size_request(-1, 200)
self.editor_rcall.show()
frame.add(self.editor_rcall)
frame.show()
box.pack_start(frame, 1, 1, 0)
frame = gtk.Frame(_("My callsign"))
self.editor_mcall = CallsignEditor()
self.editor_mcall.set_size_request(-1, 200)
self.editor_mcall.show()
frame.add(self.editor_mcall)
frame.show()
box.pack_start(frame, 1, 1, 0)
box.show()
return box
def focus(self):
if self.loaded:
return
self.loaded = True
print "Loading callsigns..."
def set_ucall(calls):
self.editor_ucall.set_callsigns(calls)
self.editor_ucall.connect("changed", self.__cs_changed)
def set_rcall(calls):
self.editor_rcall.set_callsigns(calls)
self.editor_rcall.connect("changed", self.__cs_changed)
def set_mcall(calls):
self.editor_mcall.set_callsigns(calls)
self.editor_mcall.connect("changed", self.__cs_changed)
job = common.RadioJob(set_ucall, "get_urcall_list")
job.set_desc(_("Downloading URCALL list"))
self.rthread.submit(job)
job = common.RadioJob(set_rcall, "get_repeater_call_list")
job.set_desc(_("Downloading RPTCALL list"))
self.rthread.submit(job)
job = common.RadioJob(set_mcall, "get_mycall_list")
job.set_desc(_("Downloading MYCALL list"))
self.rthread.submit(job)
def __init__(self, rthread):
common.Editor.__init__(self)
self.rthread = rthread
self.loaded = False
self.editor_ucall = self.editor_rcall = None
vbox = gtk.VBox(False, 2)
vbox.pack_start(self.make_callsigns(), 0, 0, 0)
tmp = gtk.Label("")
tmp.show()
vbox.pack_start(tmp, 1, 1, 1)
self.root = vbox
chirp-0.3.1/chirpui/inputdialog.py 0000644 0000161 0000750 00000011242 11717005656 016720 0 ustar jenkins 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
from miscwidgets import make_choice
from chirpui import reporting
class TextInputDialog(gtk.Dialog):
def respond_ok(self, _):
self.response(gtk.RESPONSE_OK)
def __init__(self, **args):
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK)
gtk.Dialog.__init__(self, buttons=buttons, **args)
self.label = gtk.Label()
self.label.set_size_request(300, 100)
# pylint: disable-msg=E1101
self.vbox.pack_start(self.label, 1, 1, 0)
self.text = gtk.Entry()
self.text.connect("activate", self.respond_ok, None)
# pylint: disable-msg=E1101
self.vbox.pack_start(self.text, 1, 1, 0)
self.label.show()
self.text.show()
class ChoiceDialog(gtk.Dialog):
editable = False
def __init__(self, choices, **args):
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK)
gtk.Dialog.__init__(self, buttons=buttons, **args)
self.label = gtk.Label()
self.label.set_size_request(300, 100)
# pylint: disable-msg=E1101
self.vbox.pack_start(self.label, 1, 1, 0)
self.label.show()
try:
default = choices[0]
except IndexError:
default = None
self.choice = make_choice(sorted(choices), self.editable, default)
# pylint: disable-msg=E1101
self.vbox.pack_start(self.choice, 1, 1, 0)
self.choice.show()
self.set_default_response(gtk.RESPONSE_OK)
class EditableChoiceDialog(ChoiceDialog):
editable = True
def __init__(self, choices, **args):
ChoiceDialog.__init__(self, choices, **args)
self.choice.child.set_activates_default(True)
class ExceptionDialog(gtk.MessageDialog):
def __init__(self, exception, **args):
gtk.MessageDialog.__init__(self, buttons=gtk.BUTTONS_OK,
type=gtk.MESSAGE_ERROR, **args)
self.set_property("text", _("An error has occurred"))
self.format_secondary_text(str(exception))
import traceback
import sys
reporting.report_exception(traceback.format_exc(limit=30))
print "--- Exception Dialog: %s ---" % exception
traceback.print_exc(limit=100, file=sys.stdout)
print "----------------------------"
class FieldDialog(gtk.Dialog):
def __init__(self, **kwargs):
if "buttons" not in kwargs.keys():
kwargs["buttons"] = (gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
self.__fields = {}
self.set_default_response(gtk.RESPONSE_OK)
gtk.Dialog.__init__(self, **kwargs)
def response(self, _):
print "Blocking response"
return
def add_field(self, label, widget, validator=None):
box = gtk.HBox(True, 2)
lab = gtk.Label(label)
lab.show()
widget.set_size_request(150, -1)
widget.show()
box.pack_start(lab, 0, 0, 0)
box.pack_start(widget, 0, 0, 0)
box.show()
# pylint: disable-msg=E1101
self.vbox.pack_start(box, 0, 0, 0)
self.__fields[label] = widget
def get_field(self, label):
return self.__fields.get(label, None)
class OverwriteDialog(gtk.MessageDialog):
def __init__(self, filename):
gtk.Dialog.__init__(self,
buttons=(_("Overwrite"), gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
self.set_property("text", _("File Exists"))
text = \
_("The file {name} already exists. "
"Do you want to overwrite it?").format(name=filename)
self.format_secondary_text(text)
if __name__ == "__main__":
# pylint: disable-msg=C0103
d = FieldDialog(buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK))
d.add_field("Foo", gtk.Entry())
d.add_field("Bar", make_choice(["A", "B"]))
d.run()
gtk.main()
d.destroy()
chirp-0.3.1/chirpui/common.py 0000644 0000161 0177776 00000025246 12130403635 017330 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
import pango
import threading
import time
import os
import traceback
from chirp import errors
from chirpui import reporting
class Editor(gobject.GObject):
__gsignals__ = {
'changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
'usermsg' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
}
root = None
def __init__(self):
gobject.GObject.__init__(self)
self._focused = False
def is_focused(self):
return self._focused
def focus(self):
self._focused = True
def unfocus(self):
self._focused = False
def copy_selection(self, cut=False):
pass
def paste_selection(self):
pass
def hotkey(self, action):
pass
gobject.type_register(Editor)
def DBG(*args):
if False:
print " ".join(args)
VERBOSE = False
class RadioJob:
def __init__(self, cb, func, *args, **kwargs):
self.cb = cb
self.cb_args = ()
self.func = func
self.args = args
self.kwargs = kwargs
self.desc = "Working"
self.target = None
self.tb = traceback.format_stack()
def __str__(self):
return "RadioJob(%s,%s,%s)" % (self.func, self.args, self.kwargs)
def set_desc(self, desc):
self.desc = desc
def set_cb_args(self, *args):
self.cb_args = args
def set_target(self, target):
self.target = target
def _execute(self, target, func):
try:
DBG("Running %s (%s %s)" % (self.func,
str(self.args),
str(self.kwargs)))
if VERBOSE:
print self.desc
result = func(*self.args, **self.kwargs)
except errors.InvalidMemoryLocation, e:
result = e
except Exception, e:
print "Exception running RadioJob: %s" % e
log_exception()
print "Job Args: %s" % str(self.args)
print "Job KWArgs: %s" % str(self.kwargs)
print "Job Called from:%s%s" % (os.linesep, "".join(self.tb[:-1]))
result = e
if self.cb:
gobject.idle_add(self.cb, result, *self.cb_args)
def execute(self, radio):
if not self.target:
self.target = radio
try:
func = getattr(self.target, self.func)
except AttributeError, e:
print "No such radio function `%s' in %s" % (self.func,
self.target)
return
self._execute(self.target, func)
class RadioThread(threading.Thread, gobject.GObject):
__gsignals__ = {
"status" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
}
def __init__(self, radio):
threading.Thread.__init__(self)
gobject.GObject.__init__(self)
self.__queue = {}
self.__counter = threading.Semaphore(0)
self.__enabled = True
self.__lock = threading.Lock()
self.__runlock = threading.Lock()
self.radio = radio
def _qlock(self):
self.__lock.acquire()
def _qunlock(self):
self.__lock.release()
def _qsubmit(self, job, priority):
if not self.__queue.has_key(priority):
self.__queue[priority] = []
self.__queue[priority].append(job)
self.__counter.release()
def _queue_clear_below(self, priority):
for i in range(0, priority):
if self.__queue.has_key(i) and len(self.__queue[i]) != 0:
return False
return True
def _qlock_when_idle(self, priority=10):
while True:
DBG("Attempting queue lock (%i)" % len(self.__queue))
self._qlock()
if self._queue_clear_below(priority):
return
self._qunlock()
time.sleep(0.1)
# This is the external lock, which stops any threads from running
# so that the radio can be operated synchronously
def lock(self):
self.__runlock.acquire()
def unlock(self):
self.__runlock.release()
def submit(self, job, priority=0):
self._qlock()
self._qsubmit(job, priority)
self._qunlock()
def flush(self, priority=None):
self._qlock()
if priority is None:
for i in self.__queue.keys():
self.__queue[i] = []
else:
self.__queue[priority] = []
self._qunlock()
def stop(self):
self.flush()
self.__counter.release()
self.__enabled = False
def status(self, msg):
jobs = 0
for i in dict(self.__queue):
jobs += len(self.__queue[i])
gobject.idle_add(self.emit, "status", "[%i] %s" % (jobs, msg))
def _queue_pop(self, priority):
try:
return self.__queue[priority].pop(0)
except IndexError:
return None
def run(self):
last_job_desc = "idle"
while self.__enabled:
DBG("Waiting for a job")
if last_job_desc:
self.status(_("Completed") + " " + last_job_desc + \
" (" + _("idle") + ")")
self.__counter.acquire()
self._qlock()
for i in sorted(self.__queue.keys()):
job = self._queue_pop(i)
if job:
DBG("Running job at priority %i" % i)
break
self._qunlock()
if job:
self.lock()
self.status(job.desc)
job.execute(self.radio)
last_job_desc = job.desc
self.unlock()
print "RadioThread exiting"
def log_exception():
import traceback
import sys
reporting.report_exception(traceback.format_exc(limit=30))
print "-- Exception: --"
traceback.print_exc(limit=30, file=sys.stdout)
print "------"
def show_error(msg, parent=None):
d = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, parent=parent,
type=gtk.MESSAGE_ERROR)
d.set_property("text", msg)
if not parent:
d.set_position(gtk.WIN_POS_CENTER_ALWAYS)
d.run()
d.destroy()
def ask_yesno_question(msg, parent=None):
d = gtk.MessageDialog(buttons=gtk.BUTTONS_YES_NO, parent=parent,
type=gtk.MESSAGE_QUESTION)
d.set_property("text", msg)
if not parent:
d.set_position(gtk.WIN_POS_CENTER_ALWAYS)
r = d.run()
d.destroy()
return r == gtk.RESPONSE_YES
def combo_select(box, value):
store = box.get_model()
iter = store.get_iter_first()
while iter:
if store.get(iter, 0)[0] == value:
box.set_active_iter(iter)
return True
iter = store.iter_next(iter)
return False
def _add_text(d, text):
v = gtk.TextView()
v.get_buffer().set_text(text)
v.set_editable(False)
v.set_cursor_visible(False)
v.show()
sw = gtk.ScrolledWindow()
sw.add(v)
sw.show()
d.vbox.pack_start(sw, 1,1,1)
return v
def show_error_text(msg, text, parent=None):
d = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, parent=parent,
type=gtk.MESSAGE_ERROR)
d.set_property("text", msg)
_add_text(d, text)
if not parent:
d.set_position(gtk.WIN_POS_CENTER_ALWAYS)
d.set_size_request(600, 400)
d.run()
d.destroy()
def show_warning(msg, text,
parent=None, buttons=None, title="Warning",
can_squelch=False):
if buttons is None:
buttons = gtk.BUTTONS_OK
d = gtk.MessageDialog(buttons=buttons,
parent=parent,
type=gtk.MESSAGE_WARNING)
d.set_title(title)
d.set_property("text", msg)
l = gtk.Label(_("Details") + ":")
l.show()
d.vbox.pack_start(l, 0, 0, 0)
l = gtk.Label(_("Proceed?"))
l.show()
d.get_action_area().pack_start(l, 0, 0, 0)
d.get_action_area().reorder_child(l, 0)
textview = _add_text(d, text)
textview.set_wrap_mode(gtk.WRAP_WORD)
if not parent:
d.set_position(gtk.WIN_POS_CENTER_ALWAYS)
if can_squelch:
cb = gtk.CheckButton(_("Do not show this next time"))
cb.show()
d.vbox.pack_start(cb, 0, 0, 0)
d.set_size_request(600, 400)
r = d.run()
d.destroy()
if can_squelch:
return r, cb.get_active()
return r
def simple_diff(a, b):
lines_a = a.split(os.linesep)
lines_b = b.split(os.linesep)
diff = ""
for i in range(0, len(lines_a)):
if lines_a[i] != lines_b[i]:
diff += "-%s%s" % (lines_a[i], os.linesep)
diff += "+%s%s" % (lines_b[i], os.linesep)
else:
diff += " %s%s" % (lines_a[i], os.linesep)
return diff
# A quick hacked up tool to show a blob of text in a dialog window
# using fixed-width fonts. It also highlights lines that start with
# a '-' in red bold font and '+' with blue bold font.
def show_diff_blob(title, result):
d = gtk.Dialog(title=title,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK))
b = gtk.TextBuffer()
tags = b.get_tag_table()
for color in ["red", "blue", "green", "grey"]:
tag = gtk.TextTag(color)
tag.set_property("foreground", color)
tags.add(tag)
tag = gtk.TextTag("bold")
tag.set_property("weight", pango.WEIGHT_BOLD)
tags.add(tag)
lines = result.split(os.linesep)
for line in lines:
if line.startswith("-"):
tags = ("red", "bold")
elif line.startswith("+"):
tags = ("blue", "bold")
else:
tags = ()
b.insert_with_tags_by_name(b.get_end_iter(), line + os.linesep, *tags)
v = gtk.TextView(b)
fontdesc = pango.FontDescription("Courier 11")
v.modify_font(fontdesc)
v.set_editable(False)
v.show()
s = gtk.ScrolledWindow()
s.add(v)
s.show()
d.vbox.pack_start(s, 1, 1, 1)
d.set_size_request(600, 400)
d.run()
d.destroy()
chirp-0.3.1/chirpui/shiftdialog.py 0000644 0000161 0177776 00000011246 12106644073 020336 0 ustar jenkins nogroup 0000000 0000000 #
# Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
import threading
from chirp import errors, chirp_common
class ShiftDialog(gtk.Dialog):
def __init__(self, rthread, parent=None):
gtk.Dialog.__init__(self,
title=_("Shift"),
buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
self.rthread = rthread
self.__prog = gtk.ProgressBar()
self.__prog.show()
self.__labl = gtk.Label("")
self.__labl.show()
self.vbox.pack_start(self.__prog, 1, 1, 1)
self.vbox.pack_start(self.__labl, 0, 0, 0)
self.quiet = False
self.thread = None
self.set_response_sensitive(gtk.RESPONSE_OK, False)
def _status(self, msg, prog):
self.__labl.set_text(msg)
self.__prog.set_fraction(prog)
def status(self, msg, prog):
gobject.idle_add(self._status, msg, prog)
def _shift_memories(self, delta, memories):
count = 0.0
for i in memories:
src = i.number
dst = src + delta
print "Moving %i to %i" % (src, dst)
self.status(_("Moving {src} to {dst}").format(src=src,
dst=dst),
count / len(memories))
i.number = dst
self.rthread.radio.set_memory(i)
count += 1.0
return int(count)
def _get_mems_until_hole(self, start, endokay=False):
mems = []
llimit, ulimit = self.rthread.radio.get_features().memory_bounds
pos = start
while pos <= ulimit:
self.status(_("Looking for a free spot ({number})").format(\
number=pos), 0)
try:
mem = self.rthread.radio.get_memory(pos)
if mem.empty:
break
except errors.InvalidMemoryLocation:
break
mems.append(mem)
pos += 1
if pos > ulimit and not endokay:
raise errors.InvalidMemoryLocation(_("No space to insert a row"))
print "Found a hole: %i" % pos
return mems
def _insert_hole(self, start):
mems = self._get_mems_until_hole(start)
mems.reverse()
if mems:
ret = self._shift_memories(1, mems)
if ret:
# Clear the hole we made
self.rthread.radio.erase_memory(start)
return ret
else:
print "No memory list?"
return 0
def _delete_hole(self, start):
mems = self._get_mems_until_hole(start+1, endokay=True)
if mems:
count = self._shift_memories(-1, mems)
self.rthread.radio.erase_memory(count+start)
return count
else:
print "No memory list?"
return 0
def finished(self):
if self.quiet:
gobject.idle_add(self.response, gtk.RESPONSE_OK)
else:
gobject.idle_add(self.set_response_sensitive, gtk.RESPONSE_OK, True)
def threadfn(self, newhole, func):
self.status("Waiting for radio to become available", 0)
self.rthread.lock()
try:
count = func(newhole)
except errors.InvalidMemoryLocation, e:
self.status(str(e), 0)
self.finished()
return
self.rthread.unlock()
self.status(_("Moved {count} memories").format(count=count), 1)
self.finished()
def insert(self, newhole, quiet=False):
self.quiet = quiet
self.thread = threading.Thread(target=self.threadfn,
args=(newhole,self._insert_hole))
self.thread.start()
gtk.Dialog.run(self)
def delete(self, newhole, quiet=False):
self.quiet = quiet
self.thread = threading.Thread(target=self.threadfn,
args=(newhole,self._delete_hole))
self.thread.start()
gtk.Dialog.run(self)
chirp-0.3.1/chirpui/editorset.py 0000644 0000161 0177776 00000031577 12130403635 020046 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import os
import gtk
import gobject
from chirp import chirp_common, directory, generic_csv, generic_xml
from chirpui import memedit, dstaredit, bankedit, common, importdialog
from chirpui import inputdialog, reporting, settingsedit
class EditorSet(gtk.VBox):
__gsignals__ = {
"want-close" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
"status" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
"usermsg": (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
"editor-selected" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
}
def __init__(self, source, parent_window=None, filename=None, tempname=None):
gtk.VBox.__init__(self, True, 0)
self.parent_window = parent_window
if isinstance(source, str):
self.filename = source
self.radio = directory.get_radio_by_image(self.filename)
elif isinstance(source, chirp_common.Radio):
self.radio = source
self.filename = filename or tempname or source.VARIANT
else:
raise Exception("Unknown source type")
self.rthread = common.RadioThread(self.radio)
self.rthread.setDaemon(True)
self.rthread.start()
self.rthread.connect("status", lambda e, m: self.emit("status", m))
self.tabs = gtk.Notebook()
self.tabs.connect("switch-page", self.tab_selected)
self.tabs.set_tab_pos(gtk.POS_LEFT)
self.editors = {
"memedit" : None,
"dstar" : None,
"bank_names" : None,
"bank_members" : None,
"settings" : None,
}
if isinstance(self.radio, chirp_common.IcomDstarSupport):
self.editors["memedit"] = memedit.DstarMemoryEditor(self.rthread)
self.editors["dstar"] = dstaredit.DStarEditor(self.rthread)
else:
self.editors["memedit"] = memedit.MemoryEditor(self.rthread)
self.editors["memedit"].connect("usermsg",
lambda e, m: self.emit("usermsg", m))
rf = self.radio.get_features()
if rf.has_bank:
self.editors["bank_members"] = \
bankedit.BankMembershipEditor(self.rthread, self)
if rf.has_bank_names:
self.editors["bank_names"] = bankedit.BankNameEditor(self.rthread)
if rf.has_settings:
self.editors["settings"] = settingsedit.SettingsEditor(self.rthread)
lab = gtk.Label(_("Memories"))
self.tabs.append_page(self.editors["memedit"].root, lab)
self.editors["memedit"].root.show()
if self.editors["dstar"]:
lab = gtk.Label(_("D-STAR"))
self.tabs.append_page(self.editors["dstar"].root, lab)
self.editors["dstar"].root.show()
self.editors["dstar"].connect("changed", self.dstar_changed)
if self.editors["bank_names"]:
lab = gtk.Label(_("Bank Names"))
self.tabs.append_page(self.editors["bank_names"].root, lab)
self.editors["bank_names"].root.show()
self.editors["bank_names"].connect("changed", self.banks_changed)
if self.editors["bank_members"]:
lab = gtk.Label(_("Banks"))
self.tabs.append_page(self.editors["bank_members"].root, lab)
self.editors["bank_members"].root.show()
self.editors["bank_members"].connect("changed", self.banks_changed)
if self.editors["settings"]:
lab = gtk.Label(_("Settings"))
self.tabs.append_page(self.editors["settings"].root, lab)
self.editors["settings"].root.show()
self.pack_start(self.tabs)
self.tabs.show()
# pylint: disable-msg=E1101
self.editors["memedit"].connect("changed", self.editor_changed)
self.label = self.text_label = None
self.make_label()
self.modified = (tempname is not None)
if tempname:
self.filename = tempname
self.update_tab()
def make_label(self):
self.label = gtk.HBox(False, 0)
self.text_label = gtk.Label("")
self.text_label.show()
self.label.pack_start(self.text_label, 1, 1, 1)
button = gtk.Button("X")
button.set_relief(gtk.RELIEF_NONE)
button.connect("clicked", lambda x: self.emit("want-close"))
button.show()
self.label.pack_start(button, 0, 0, 0)
self.label.show()
def update_tab(self):
fn = os.path.basename(self.filename)
if self.modified:
text = "%s*" % fn
else:
text = fn
self.text_label.set_text(self.radio.get_name() + ": " + text)
def save(self, fname=None):
if not fname:
fname = self.filename
if not os.path.exists(self.filename):
return # Probably before the first "Save as"
else:
self.filename = fname
self.rthread.lock()
try:
self.radio.save(fname)
except:
self.rthread.unlock()
raise
self.rthread.unlock()
self.modified = False
self.update_tab()
def dstar_changed(self, *args):
print "D-STAR editor changed"
memedit = self.editors["memedit"]
dstared = self.editors["dstar"]
memedit.set_urcall_list(dstared.editor_ucall.get_callsigns())
memedit.set_repeater_list(dstared.editor_rcall.get_callsigns())
memedit.prefill()
if not isinstance(self.radio, chirp_common.LiveRadio):
self.modified = True
self.update_tab()
def banks_changed(self, *args):
print "Banks changed"
if self.editors["bank_members"]:
self.editors["bank_members"].banks_changed()
if not isinstance(self.radio, chirp_common.LiveRadio):
self.modified = True
self.update_tab()
def editor_changed(self, *args):
if not isinstance(self.radio, chirp_common.LiveRadio):
self.modified = True
self.update_tab()
if self.editors["bank_members"]:
self.editors["bank_members"].memories_changed()
def get_tab_label(self):
return self.label
def is_modified(self):
return self.modified
def _do_import_locked(self, dlgclass, src_radio, dst_rthread):
# An import/export action needs to be done in the absence of any
# other queued changes. So, we make sure that nothing else is
# staged for the thread and lock it up. Then we use the hidden
# interface to queue our own changes before opening it up to the
# rest of the world.
dst_rthread._qlock_when_idle(5) # Suspend job submission when idle
dialog = dlgclass(src_radio, dst_rthread.radio, self.parent_window)
r = dialog.run()
dialog.hide()
if r != gtk.RESPONSE_OK:
dst_rthread._qunlock()
return
count = dialog.do_import(dst_rthread)
print "Imported %i" % count
dst_rthread._qunlock()
if count > 0:
self.editor_changed()
gobject.idle_add(self.editors["memedit"].prefill)
return count
def choose_sub_device(self, radio):
devices = radio.get_sub_devices()
choices = [x.VARIANT for x in devices]
d = inputdialog.ChoiceDialog(choices)
d.label.set_text(_("The {vendor} {model} has multiple "
"independent sub-devices").format( \
vendor=radio.VENDOR, model=radio.MODEL) + os.linesep + \
_("Choose one to import from:"))
r = d.run()
chosen = d.choice.get_active_text()
d.destroy()
if r == gtk.RESPONSE_CANCEL:
raise Exception(_("Cancelled"))
for d in devices:
if d.VARIANT == chosen:
return d
raise Exception(_("Internal Error"))
def do_import(self, filen):
try:
src_radio = directory.get_radio_by_image(filen)
except Exception, e:
common.show_error(e)
return
if isinstance(src_radio, chirp_common.NetworkSourceRadio):
ww = importdialog.WaitWindow("Querying...", self.parent_window)
ww.show()
def status(status):
ww.set(float(status.cur) / float(status.max))
try:
src_radio.status_fn = status
src_radio.do_fetch()
except Exception, e:
common.show_error(e)
ww.hide()
return
ww.hide()
try:
if src_radio.get_features().has_sub_devices:
src_radio = self.choose_sub_device(src_radio)
except Exception, e:
common.show_error(e)
return
if len(src_radio.errors) > 0:
_filen = os.path.basename(filen)
common.show_error_text(_("There were errors while opening {file}. "
"The affected memories will not "
"be importable!").format(file=_filen),
"\r\n".join(src_radio.errors))
try:
count = self._do_import_locked(importdialog.ImportDialog,
src_radio,
self.rthread)
reporting.report_model_usage(src_radio, "importsrc", True)
except Exception, e:
common.log_exception()
common.show_error(_("There was an error during "
"import: {error}").format(error=e))
def do_export(self, filen):
try:
if filen.lower().endswith(".csv"):
dst_radio = generic_csv.CSVRadio(filen)
elif filen.lower().endswith(".chirp"):
dst_radio = generic_xml.XMLRadio(filen)
else:
raise Exception(_("Unsupported file type"))
except Exception, e:
common.log_exception()
common.show_error(e)
return
dst_rthread = common.RadioThread(dst_radio)
dst_rthread.setDaemon(True)
dst_rthread.start()
try:
count = self._do_import_locked(importdialog.ExportDialog,
self.rthread.radio,
dst_rthread)
except Exception, e:
common.log_exception()
common.show_error(_("There was an error during "
"export: {error}").format(error=e),
self.parent_window)
return
if count <= 0:
return
# Wait for thread queue to complete
dst_rthread._qlock_when_idle()
try:
dst_radio.save(filename=filen)
except Exception, e:
common.log_exception()
common.show_error(_("There was an error during "
"export: {error}").format(error=e),
self)
def prime(self):
mem = chirp_common.Memory()
mem.freq = 146010000
def cb(*args):
gobject.idle_add(self.editors["memedit"].prefill)
job = common.RadioJob(cb, "set_memory", mem)
job.set_desc(_("Priming memory"))
self.rthread.submit(job)
def tab_selected(self, notebook, foo, pagenum):
widget = notebook.get_nth_page(pagenum)
for k,v in self.editors.items():
if v and v.root == widget:
v.focus()
self.emit("editor-selected", k)
elif v:
v.unfocus()
def set_read_only(self, read_only=True):
self.editors["memedit"].set_read_only(read_only)
def get_read_only(self):
return self.editors["memedit"].get_read_only()
def prepare_close(self):
self.editors["memedit"].prepare_close()
def get_current_editor(self):
for e in self.editors.values():
if e and self.tabs.page_num(e.root) == self.tabs.get_current_page():
return e
raise Exception("No editor selected?")
chirp-0.3.1/chirpui/memedit.py 0000644 0000161 0177776 00000155127 12130403635 017466 0 ustar jenkins nogroup 0000000 0000000 #
# Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
if __name__ == "__main__":
import sys
sys.path.insert(0, "..")
import threading
import gtk
import pango
from gobject import TYPE_INT, \
TYPE_DOUBLE as TYPE_FLOAT, \
TYPE_STRING, \
TYPE_BOOLEAN, \
TYPE_PYOBJECT, \
TYPE_INT64
import gobject
import pickle
import os
from chirpui import common, shiftdialog, miscwidgets, config, memdetail
from chirp import chirp_common, errors, directory, import_logic
def handle_toggle(_, path, store, col):
store[path][col] = not store[path][col]
def handle_ed(_, iter, new, store, col):
old, = store.get(iter, col)
if old != new:
store.set(iter, col, new)
return True
else:
return False
class ValueErrorDialog(gtk.MessageDialog):
def __init__(self, exception, **args):
gtk.MessageDialog.__init__(self, buttons=gtk.BUTTONS_OK, **args)
self.set_property("text", _("Invalid value for this field"))
self.format_secondary_text(str(exception))
def iter_prev(store, iter):
row = store.get_path(iter)[0]
if row == 0:
return None
return store.get_iter((row - 1,))
class MemoryEditor(common.Editor):
cols = [
(_("Loc") , TYPE_INT, gtk.CellRendererText, ),
(_("Frequency") , TYPE_INT64, gtk.CellRendererText, ),
(_("Name") , TYPE_STRING, gtk.CellRendererText, ),
(_("Tone Mode") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Tone") , TYPE_FLOAT, gtk.CellRendererCombo, ),
(_("ToneSql") , TYPE_FLOAT, gtk.CellRendererCombo, ),
(_("DTCS Code") , TYPE_INT, gtk.CellRendererCombo, ),
(_("DTCS Rx Code") , TYPE_INT, gtk.CellRendererCombo, ),
(_("DTCS Pol") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Cross Mode") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Duplex") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Offset") , TYPE_INT64, gtk.CellRendererText, ),
(_("Mode") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Power") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Tune Step") , TYPE_FLOAT, gtk.CellRendererCombo, ),
(_("Skip") , TYPE_STRING, gtk.CellRendererCombo, ),
(_("Comment") , TYPE_STRING, gtk.CellRendererText, ),
("_filled" , TYPE_BOOLEAN, None, ),
("_hide_cols" , TYPE_PYOBJECT,None, ),
("_extd" , TYPE_STRING, None, ),
]
defaults = {
_("Name") : "",
_("Frequency") : 146010000,
_("Tone") : 88.5,
_("ToneSql") : 88.5,
_("DTCS Code") : 23,
_("DTCS Rx Code") : 23,
_("DTCS Pol") : "NN",
_("Cross Mode") : "Tone->Tone",
_("Duplex") : "",
_("Offset") : 0,
_("Mode") : "FM",
_("Power") : "",
_("Tune Step") : 5.0,
_("Tone Mode") : "",
_("Skip") : "",
_("Comment") : "",
}
choices = {
_("Tone") : chirp_common.TONES,
_("ToneSql") : chirp_common.TONES,
_("DTCS Code") : sorted(chirp_common.DTCS_CODES +
chirp_common.DTCS_EXTRA_CODES),
_("DTCS Rx Code") : sorted(chirp_common.DTCS_CODES +
chirp_common.DTCS_EXTRA_CODES),
_("DTCS Pol") : ["NN", "NR", "RN", "RR"],
_("Mode") : chirp_common.MODES,
_("Power") : [],
_("Duplex") : ["", "-", "+", "split", "off"],
_("Tune Step") : chirp_common.TUNING_STEPS,
_("Tone Mode") : ["", "Tone", "TSQL", "DTCS"],
_("Cross Mode") : chirp_common.CROSS_MODES,
}
def ed_name(self, _, __, new, ___):
return self.rthread.radio.filter_name(new)
def ed_offset(self, _, path, new, __):
return chirp_common.parse_freq(new)
def ed_freq(self, _foo, path, new, colnum):
iter = self.store.get_iter(path)
prev, = self.store.get(iter, colnum)
def set_offset(path, offset):
if offset > 0:
dup = "+"
elif offset == 0:
dup = ""
else:
dup = "-"
offset *= -1
if offset:
self.store.set(iter, self.col(_("Offset")), offset)
self.store.set(iter, self.col(_("Duplex")), dup)
def set_ts(ts):
self.store.set(iter, self.col(_("Tune Step")), ts)
def get_ts(path):
return self.store.get(iter, self.col(_("Tune Step")))[0]
try:
new = chirp_common.parse_freq(new)
except ValueError, e:
print e
new = None
if not self._features.has_nostep_tuning:
set_ts(chirp_common.required_step(new))
if new and self._config.get_bool("autorpt") and new != prev:
try:
band = chirp_common.freq_to_band(new)
set_offset(path, 0)
for lo, hi, offset in chirp_common.STD_OFFSETS[band]:
if new > lo and new < hi:
set_offset(path, offset)
break
except Exception, e:
pass
return new
def ed_loc(self, _, path, new, __):
iter = self.store.get_iter(path)
curloc, = self.store.get(iter, self.col(_("Loc")))
job = common.RadioJob(None, "erase_memory", curloc)
job.set_desc(_("Erasing memory {loc}").format(loc=curloc))
self.rthread.submit(job)
self.need_refresh = True
return new
def ed_duplex(self, _foo1, path, new, _foo2):
if new == "":
return # Fast path outta here
iter = self.store.get_iter(path)
freq, = self.store.get(iter, self.col(_("Frequency")))
if new == "split":
# If we're going to split mode, use the current
# RX frequency as the default TX frequency
self.store.set(iter, self.col("Offset"), freq)
else:
band = int(freq / 100000000)
if chirp_common.STD_OFFSETS.has_key(band):
offset = chirp_common.STD_OFFSETS[band][0][2]
else:
offset = 0
self.store.set(iter, self.col(_("Offset")), abs(offset))
return new
def _get_cols_to_hide(self, iter):
tmode, duplex, cmode = self.store.get(iter,
self.col(_("Tone Mode")),
self.col(_("Duplex")),
self.col(_("Cross Mode")))
hide = []
txmode, rxmode = cmode.split("->")
if tmode == "Tone":
hide += [self.col(_("ToneSql")),
self.col(_("DTCS Code")),
self.col(_("DTCS Rx Code")),
self.col(_("DTCS Pol")),
self.col(_("Cross Mode"))]
elif tmode == "TSQL":
if self._features.has_ctone:
hide += [self.col(_("Tone"))]
hide += [self.col(_("DTCS Code")),
self.col(_("DTCS Rx Code")),
self.col(_("DTCS Pol")),
self.col(_("Cross Mode"))]
elif tmode == "DTCS":
hide += [self.col(_("Tone")),
self.col(_("ToneSql")),
self.col(_("Cross Mode")),
self.col(_("DTCS Rx Code"))]
elif tmode == "" or tmode == "(None)":
hide += [self.col(_("Tone")),
self.col(_("ToneSql")),
self.col(_("DTCS Code")),
self.col(_("DTCS Rx Code")),
self.col(_("DTCS Pol")),
self.col(_("Cross Mode"))]
elif tmode == "Cross":
if txmode != "Tone":
hide += [self.col(_("Tone"))]
if txmode != "DTCS":
hide += [self.col(_("DTCS Code"))]
if rxmode != "Tone":
hide += [self.col(_("ToneSql"))]
if rxmode != "DTCS":
hide += [self.col(_("DTCS Rx Code"))]
if "DTCS" not in cmode:
hide += [self.col(_("DTCS Pol"))]
if duplex == "" or duplex == "(None)":
hide += [self.col(_("Offset"))]
return hide
def maybe_hide_cols(self, iter):
hide_cols = self._get_cols_to_hide(iter)
self.store.set(iter, self.col("_hide_cols"), hide_cols)
def edited(self, rend, path, new, cap):
if self.read_only:
common.show_error(_("Unable to make changes to this model"))
return
iter = self.store.get_iter(path)
if not self.store.get(iter, self.col("_filled"))[0] \
and self.store.get(iter, self.col(_("Frequency")))[0] == 0:
print _("Editing new item, taking defaults")
self.insert_new(iter)
colnum = self.col(cap)
funcs = {
_("Loc") : self.ed_loc,
_("Name") : self.ed_name,
_("Frequency") : self.ed_freq,
_("Duplex") : self.ed_duplex,
_("Offset") : self.ed_offset,
}
if funcs.has_key(cap):
new = funcs[cap](rend, path, new, colnum)
if new is None:
print _("Bad value for {col}: {val}").format(col=cap, val=new)
return
if self.store.get_column_type(colnum) == TYPE_INT:
new = int(new)
elif self.store.get_column_type(colnum) == TYPE_FLOAT:
new = float(new)
elif self.store.get_column_type(colnum) == TYPE_BOOLEAN:
new = bool(new)
elif self.store.get_column_type(colnum) == TYPE_STRING:
if new == "(None)":
new = ""
if not handle_ed(rend, iter, new, self.store, self.col(cap)) and \
cap != _("Frequency"):
# No change was made
# For frequency, we make an exception, since the handler might
# have altered the duplex. That needs to be fixed.
return
mem = self._get_memory(iter)
msgs = self.rthread.radio.validate_memory(mem)
if msgs:
common.show_error(_("Error setting memory") + \
"\r\n\r\n".join(msgs))
self.prefill()
return
mem.empty = False
job = common.RadioJob(self._set_memory_cb, "set_memory", mem)
job.set_desc(_("Writing memory {number}").format(number=mem.number))
self.rthread.submit(job)
self.store.set(iter, self.col("_filled"), True)
self.maybe_hide_cols(iter)
persist_defaults = [_("Power"), _("Frequency"), _("Mode")]
if cap in persist_defaults:
self.defaults[cap] = new
def _render(self, colnum, val, iter=None, hide=[]):
if colnum in hide and self.hide_unused:
return ""
if colnum == self.col(_("Frequency")):
val = chirp_common.format_freq(val)
elif colnum in [self.col(_("DTCS Code")), self.col(_("DTCS Rx Code"))]:
val = "%03i" % int(val)
elif colnum == self.col(_("Offset")):
val = chirp_common.format_freq(val)
elif colnum in [self.col(_("Tone")), self.col(_("ToneSql"))]:
val = "%.1f" % val
elif colnum in [self.col(_("Tone Mode")), self.col(_("Duplex"))]:
if not val:
val = "(None)"
elif colnum == self.col(_("Loc")) and iter is not None:
extd, = self.store.get(iter, self.col("_extd"))
if extd:
val = extd
return val
def render(self, _, rend, model, iter, colnum):
val, hide = model.get(iter, colnum, self.col("_hide_cols"))
val = self._render(colnum, val, iter, hide or [])
rend.set_property("text", "%s" % val)
def insert_new(self, iter, loc=None):
line = []
for key, val in self.defaults.items():
line.append(self.col(key))
line.append(val)
if not loc:
loc, = self.store.get(iter, self.col(_("Loc")))
self.store.set(iter,
0, loc,
*tuple(line))
return self._get_memory(iter)
def insert_easy(self, store, _iter, delta):
if delta < 0:
iter = store.insert_before(_iter)
else:
iter = store.insert_after(_iter)
newpos, = store.get(_iter, self.col(_("Loc")))
newpos += delta
print "Insert easy: %i" % delta
mem = self.insert_new(iter, newpos)
job = common.RadioJob(None, "set_memory", mem)
job.set_desc(_("Writing memory {number}").format(number=mem.number))
self.rthread.submit(job)
def insert_hard(self, store, _iter, delta, warn=True):
if isinstance(self.rthread.radio, chirp_common.LiveRadio) and warn:
txt = _("This operation requires moving all subsequent channels "
"by one spot until an empty location is reached. This "
"can take a LONG time. Are you sure you want to do this?")
if not common.ask_yesno_question(txt):
return False # No change
if delta <= 0:
iter = _iter
else:
iter = store.iter_next(_iter)
pos, = store.get(iter, self.col("Loc"))
sd = shiftdialog.ShiftDialog(self.rthread)
if delta == 0:
sd.delete(pos)
sd.destroy()
self.prefill()
else:
sd.insert(pos)
sd.destroy()
job = common.RadioJob(lambda x: self.prefill(), "erase_memory", pos)
job.set_desc(_("Adding memory {number}").format(number=pos))
self.rthread.submit(job)
return True # We changed memories
def _delete_rows(self, paths):
to_remove = []
for path in paths:
iter = self.store.get_iter(path)
cur_pos, = self.store.get(iter, self.col("Loc"))
to_remove.append(cur_pos)
self.store.set(iter, self.col("_filled"), False)
job = common.RadioJob(None, "erase_memory", cur_pos)
job.set_desc(_("Erasing memory {number}").format(number=cur_pos))
self.rthread.submit(job)
def handler(mem):
if not isinstance(mem, Exception):
if not mem.empty or self.show_empty:
gobject.idle_add(self.set_memory, mem)
job = common.RadioJob(handler, "get_memory", cur_pos)
job.set_desc(_("Getting memory {number}").format(number=cur_pos))
self.rthread.submit(job)
if not self.show_empty:
# We need to actually remove the rows from the store
# now, but carefully! Get a list of deleted locations
# in order and proceed from the first path in the list
# until we run out of rows or we've removed all the
# desired ones.
to_remove.sort()
to_remove.reverse()
iter = self.store.get_iter(paths[0])
while to_remove and iter:
pos, = self.store.get(iter, self.col(_("Loc")))
if pos in to_remove:
to_remove.remove(pos)
if not self.store.remove(iter):
break # This was the last row
else:
iter = self.store.iter_next(iter)
return True # We changed memories
def _delete_rows_and_shift(self, paths):
iter = self.store.get_iter(paths[0])
starting_loc, = self.store.get(iter, self.col(_("Loc")))
for i in range(0, len(paths)):
sd = shiftdialog.ShiftDialog(self.rthread)
sd.delete(starting_loc, quiet=True)
sd.destroy()
self.prefill()
return True # We changed memories
def _move_up_down(self, paths, action):
if action.endswith("up"):
delta = -1
donor_path = paths[-1]
victim_path = paths[0]
else:
delta = 1
donor_path = paths[0]
victim_path = paths[-1]
try:
victim_path = (victim_path[0] + delta,)
if victim_path[0] < 0:
raise ValueError()
donor_loc = self.store.get(self.store.get_iter(donor_path),
self.col(_("Loc")))[0]
victim_loc = self.store.get(self.store.get_iter(victim_path),
self.col(_("Loc")))[0]
except ValueError:
self.emit("usermsg", "No room to %s" % (action.replace("_", " ")))
return False # No change
class Context:
pass
ctx = Context()
ctx.victim_mem = None
ctx.donor_loc = donor_loc
ctx.done_count = 0
ctx.path_count = len(paths)
# Steps:
# 1. Grab the victim (the one that will need to be saved and moved
# from the front to the back or back to the front) and save it
# 2. Grab each memory along the way, storing it in the +delta
# destination location after we get it
# 3. If we're the final move, then schedule storing the victim
# in the hole we created
def update_selection():
sel = self.view.get_selection()
sel.unselect_all()
for path in paths:
gobject.idle_add(sel.select_path, (path[0]+delta,))
def save_victim(mem, ctx):
ctx.victim_mem = mem
def store_victim(mem, dest):
old = mem.number
mem.number = dest
job = common.RadioJob(None, "set_memory", mem)
job.set_desc(\
_("Moving memory from {old} to {new}").format(old=old,
new=dest))
self.rthread.submit(job)
self._set_memory(self.store.get_iter(donor_path), mem)
update_selection()
def move_mem(mem, delta, ctx, iter):
old = mem.number
mem.number += delta
job = common.RadioJob(None, "set_memory", mem)
job.set_desc(\
_("Moving memory from {old} to {new}").format(old=old,
new=old+delta))
self.rthread.submit(job)
self._set_memory(iter, mem)
ctx.done_count += 1
if ctx.done_count == ctx.path_count:
store_victim(ctx.victim_mem, ctx.donor_loc)
job = common.RadioJob(lambda m: save_victim(m, ctx),
"get_memory", victim_loc)
job.set_desc(_("Getting memory {number}").format(number=victim_loc))
self.rthread.submit(job)
for i in range(len(paths)):
path = paths[i]
if delta > 0:
dest = i+1
else:
dest = i-1
if dest < 0 or dest >= len(paths):
dest = victim_path
else:
dest = paths[dest]
iter = self.store.get_iter(path)
loc, = self.store.get(iter, self.col(_("Loc")))
job = common.RadioJob(move_mem, "get_memory", loc)
job.set_cb_args(delta, ctx, self.store.get_iter(dest))
job.set_desc("Getting memory %i" % loc)
self.rthread.submit(job)
return True # We (scheduled some) change to the memories
def _exchange_memories(self, paths):
if len(paths) != 2:
self.emit("usermsg", "Select two memories first")
return False
loc_a, = self.store.get(self.store.get_iter(paths[0]),
self.col(_("Loc")))
loc_b, = self.store.get(self.store.get_iter(paths[1]),
self.col(_("Loc")))
def store_mem(mem, dst):
src = mem.number
mem.number = dst
job = common.RadioJob(None, "set_memory", mem)
job.set_desc(_("Moving memory from {old} to {new}").format(old=src,
new=dst))
self.rthread.submit(job)
if dst == loc_a:
self.prefill()
job = common.RadioJob(lambda m: store_mem(m, loc_b),
"get_memory", loc_a)
job.set_desc(_("Getting memory {number}").format(number=loc_a))
self.rthread.submit(job)
job = common.RadioJob(lambda m: store_mem(m, loc_a),
"get_memory", loc_b)
job.set_desc(_("Getting memory {number}").format(number=loc_b))
self.rthread.submit(job)
# We (scheduled some) change to the memories
return True
def _show_raw(self, cur_pos):
def idle_show_raw(result):
gobject.idle_add(common.show_diff_blob,
_("Raw memory {number}").format(number=cur_pos),
result)
job = common.RadioJob(idle_show_raw, "get_raw_memory", cur_pos)
job.set_desc(_("Getting raw memory {number}").format(number=cur_pos))
self.rthread.submit(job)
def _diff_raw(self, paths):
if len(paths) != 2:
common.show_error(_("You can only diff two memories!"))
return
loc_a = self.store.get(self.store.get_iter(paths[0]),
self.col(_("Loc")))[0]
loc_b = self.store.get(self.store.get_iter(paths[1]),
self.col(_("Loc")))[0]
raw = {}
def diff_raw(which, result):
raw[which] = _("Memory {number}").format(number=which) + \
os.linesep + result
if len(raw.keys()) == 2:
diff = common.simple_diff(raw[loc_a], raw[loc_b])
gobject.idle_add(common.show_diff_blob,
_("Diff of {a} and {b}").format(a=loc_a,
b=loc_b),
diff)
job = common.RadioJob(lambda r: diff_raw(loc_a, r),
"get_raw_memory", loc_a)
job.set_desc(_("Getting raw memory {number}").format(number=loc_a))
self.rthread.submit(job)
job = common.RadioJob(lambda r: diff_raw(loc_b, r),
"get_raw_memory", loc_b)
job.set_desc(_("Getting raw memory {number}").format(number=loc_b))
self.rthread.submit(job)
def edit_memory(self, memory):
dlg = memdetail.MemoryDetailEditor(self._features, memory)
r = dlg.run()
if r == gtk.RESPONSE_OK:
self.need_refresh = True
mem = dlg.get_memory()
mem.name = self.rthread.radio.filter_name(mem.name)
job = common.RadioJob(self._set_memory_cb, "set_memory", mem)
job.set_desc(_("Writing memory {number}").format(number=mem.number))
self.rthread.submit(job)
self.emit("changed")
dlg.destroy()
def mh(self, _action, store, paths):
action = _action.get_name()
iter = store.get_iter(paths[0])
cur_pos, = store.get(iter, self.col(_("Loc")))
require_contiguous = ["delete_s", "move_up", "move_dn"]
if action in require_contiguous:
last = paths[0][0]
for path in paths[1:]:
if path[0] != last+1:
self.emit("usermsg", _("Memories must be contiguous"))
return
last = path[0]
changed = False
if action == "insert_next":
changed = self.insert_hard(store, iter, 1)
elif action == "insert_prev":
changed = self.insert_hard(store, iter, -1)
elif action == "delete":
changed = self._delete_rows(paths)
elif action == "delete_s":
changed = self._delete_rows_and_shift(paths)
elif action in ["move_up", "move_dn"]:
changed = self._move_up_down(paths, action)
elif action == "exchange":
changed = self._exchange_memories(paths)
elif action in ["cut", "copy"]:
changed = self.copy_selection(action=="cut")
elif action == "paste":
changed = self.paste_selection()
elif action == "devshowraw":
self._show_raw(cur_pos)
elif action == "devdiffraw":
self._diff_raw(paths)
elif action == "edit":
job = common.RadioJob(self.edit_memory, "get_memory", cur_pos)
self.rthread.submit(job)
if changed:
self.emit("changed")
def hotkey(self, action):
if self._in_editing:
# Don't forward potentially-dangerous hotkeys to the menu
# handler if we're editing a cell right now
return
self.emit("usermsg", "")
(store, paths) = self.view.get_selection().get_selected_rows()
if len(paths) == 0:
return
self.mh(action, store, paths)
def make_context_menu(self):
if self._config.get_bool("developer", "state"):
devmenu = """
"""
else:
devmenu = ""
menu_xml = """
%s
""" % devmenu
(store, paths) = self.view.get_selection().get_selected_rows()
issingle = len(paths) == 1
istwo = len(paths) == 2
actions = [
("edit", _("Edit")),
("insert_prev", _("Insert row above")),
("insert_next", _("Insert row below")),
("delete", issingle and _("Delete") or _("Delete all")),
("delete_s", _("Delete (and shift up)")),
("move_up", _("Move up")),
("move_dn", _("Move down")),
("exchange", _("Exchange memories")),
("cut", _("Cut")),
("copy", _("Copy")),
("paste", _("Paste")),
("devshowraw", _("Show Raw Memory")),
("devdiffraw", _("Diff Raw Memories")),
]
no_multiple = ["insert_prev", "insert_next", "paste", "devshowraw"]
only_two = ["devdiffraw", "exchange"]
ag = gtk.ActionGroup("Menu")
for name, label in actions:
a = gtk.Action(name, label, "", 0)
a.connect("activate", self.mh, store, paths)
if name in no_multiple:
a.set_sensitive(issingle)
if name in only_two:
a.set_sensitive(istwo)
ag.add_action(a)
if issingle:
iter = store.get_iter(paths[0])
cur_pos, = store.get(iter, self.col(_("Loc")))
if cur_pos == self._features.memory_bounds[1]:
ag.get_action("delete_s").set_sensitive(False)
uim = gtk.UIManager()
uim.insert_action_group(ag, 0)
uim.add_ui_from_string(menu_xml)
return uim.get_widget("/Menu")
def click_cb(self, view, event):
self.emit("usermsg", "")
if event.button != 3:
return False
menu = self.make_context_menu()
menu.popup(None, None, None, event.button, event.time)
return True
def get_column_visible(self, col):
column = self.view.get_column(col)
return column.get_visible()
def set_column_visible(self, col, visible):
column = self.view.get_column(col)
column.set_visible(visible)
def cell_editing_started(self, rend, event, path):
self._in_editing = True
def cell_editing_stopped(self, *args):
self._in_editing = False
def make_editor(self):
types = tuple([x[1] for x in self.cols])
self.store = gtk.ListStore(*types)
self.view = gtk.TreeView(self.store)
self.view.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
self.view.set_rules_hint(True)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add(self.view)
filled = self.col("_filled")
default_col_order = [x for x,y,z in self.cols if z]
try:
col_order = self._config.get("column_order_%s" % \
self.__class__.__name__).split(",")
if len(col_order) != len(default_col_order):
raise Exception()
for i in col_order:
if i not in default_col_order:
raise Exception()
except Exception, e:
print e
col_order = default_col_order
non_editable = ["Loc"]
unsupported_cols = self.get_unsupported_columns()
visible_cols = self.get_columns_visible()
cols = {}
i = 0
for _cap, _type, _rend in self.cols:
if not _rend:
continue
rend = _rend()
rend.connect('editing-started', self.cell_editing_started)
rend.connect('editing-canceled', self.cell_editing_stopped)
rend.connect('edited', self.cell_editing_stopped)
if _type == TYPE_BOOLEAN:
#rend.set_property("activatable", True)
#rend.connect("toggled", handle_toggle, self.store, i)
col = gtk.TreeViewColumn(_cap, rend, active=i, sensitive=filled)
elif _rend == gtk.CellRendererCombo:
if isinstance(self.choices[_cap], gtk.ListStore):
choices = self.choices[_cap]
else:
choices = gtk.ListStore(TYPE_STRING, TYPE_STRING)
for choice in self.choices[_cap]:
choices.append([choice, self._render(i, choice)])
rend.set_property("model", choices)
rend.set_property("text-column", 1)
rend.set_property("editable", True)
rend.set_property("has-entry", False)
rend.connect("edited", self.edited, _cap)
col = gtk.TreeViewColumn(_cap, rend, text=i, sensitive=filled)
col.set_cell_data_func(rend, self.render, i)
else:
rend.set_property("editable", _cap not in non_editable)
rend.connect("edited", self.edited, _cap)
col = gtk.TreeViewColumn(_cap, rend, text=i, sensitive=filled)
col.set_cell_data_func(rend, self.render, i)
col.set_reorderable(True)
col.set_sort_column_id(i)
col.set_resizable(True)
col.set_min_width(1)
col.set_visible(not _cap.startswith("_") and
_cap in visible_cols and
not _cap in unsupported_cols)
cols[_cap] = col
i += 1
for cap in col_order:
self.view.append_column(cols[cap])
self.store.set_sort_column_id(self.col(_("Loc")), gtk.SORT_ASCENDING)
self.view.show()
sw.show()
self.view.connect("button_press_event", self.click_cb)
return sw
def col(self, caption):
try:
return self._cached_cols[caption]
except KeyError:
raise Exception(_("Internal Error: Column {name} not found").format(name=caption))
def prefill(self):
self.store.clear()
self._rows_in_store = 0
lo = int(self.lo_limit_adj.get_value())
hi = int(self.hi_limit_adj.get_value())
def handler(mem, number):
if not isinstance(mem, Exception):
if not mem.empty or self.show_empty:
gobject.idle_add(self.set_memory, mem)
else:
mem = chirp_common.Memory()
mem.number = number
mem.name = "ERROR"
mem.empty = True
gobject.idle_add(self.set_memory, mem)
for i in range(lo, hi+1):
job = common.RadioJob(handler, "get_memory", i)
job.set_desc(_("Getting memory {number}").format(number=i))
job.set_cb_args(i)
self.rthread.submit(job, 2)
if self.show_special:
for i in self._features.valid_special_chans:
job = common.RadioJob(handler, "get_memory", i)
job.set_desc(_("Getting channel {chan}").format(chan=i))
job.set_cb_args(i)
self.rthread.submit(job, 2)
def _set_memory(self, iter, memory):
self.store.set(iter,
self.col("_filled"), not memory.empty,
self.col(_("Loc")), memory.number,
self.col("_extd"), memory.extd_number,
self.col(_("Name")), memory.name,
self.col(_("Frequency")), memory.freq,
self.col(_("Tone Mode")), memory.tmode,
self.col(_("Tone")), memory.rtone,
self.col(_("ToneSql")), memory.ctone,
self.col(_("DTCS Code")), memory.dtcs,
self.col(_("DTCS Rx Code")), memory.rx_dtcs,
self.col(_("DTCS Pol")), memory.dtcs_polarity,
self.col(_("Cross Mode")), memory.cross_mode,
self.col(_("Duplex")), memory.duplex,
self.col(_("Offset")), memory.offset,
self.col(_("Mode")), memory.mode,
self.col(_("Power")), memory.power or "",
self.col(_("Tune Step")), memory.tuning_step,
self.col(_("Skip")), memory.skip,
self.col(_("Comment")), memory.comment)
hide = self._get_cols_to_hide(iter)
self.store.set(iter, self.col("_hide_cols"), hide)
def set_memory(self, memory):
iter = self.store.get_iter_first()
while iter is not None:
loc, = self.store.get(iter, self.col(_("Loc")))
if loc == memory.number:
return self._set_memory(iter, memory)
iter = self.store.iter_next(iter)
iter = self.store.append()
self._rows_in_store += 1
self._set_memory(iter, memory)
def clear_memory(self, number):
iter = self.store.get_iter_first()
while iter:
loc, = self.store.get(iter, self.col(_("Loc")))
if loc == number:
print "Deleting %i" % number
# FIXME: Make the actual remove happen on callback
self.store.remove(iter)
job = common.RadioJob(None, "erase_memory", number)
job.set_desc(_("Erasing memory {number}").format(number=number))
self.rthread.submit()
break
iter = self.store.iter_next(iter)
def _set_mem_vals(self, mem, vals, iter):
power_levels = {"" : None}
for i in self._features.valid_power_levels:
power_levels[str(i)] = i
mem.freq = vals[self.col(_("Frequency"))]
mem.number = vals[self.col(_("Loc"))]
mem.extd_number = vals[self.col("_extd")]
mem.name = vals[self.col(_("Name"))]
mem.vfo = 0
mem.rtone = vals[self.col(_("Tone"))]
mem.ctone = vals[self.col(_("ToneSql"))]
mem.dtcs = vals[self.col(_("DTCS Code"))]
mem.rx_dtcs = vals[self.col(_("DTCS Rx Code"))]
mem.tmode = vals[self.col(_("Tone Mode"))]
mem.cross_mode = vals[self.col(_("Cross Mode"))]
mem.dtcs_polarity = vals[self.col(_("DTCS Pol"))]
mem.duplex = vals[self.col(_("Duplex"))]
mem.offset = vals[self.col(_("Offset"))]
mem.mode = vals[self.col(_("Mode"))]
mem.power = power_levels[vals[self.col(_("Power"))]]
mem.tuning_step = vals[self.col(_("Tune Step"))]
mem.skip = vals[self.col(_("Skip"))]
mem.comment = vals[self.col(_("Comment"))]
mem.empty = not vals[self.col("_filled")]
def _get_memory(self, iter):
vals = self.store.get(iter, *range(0, len(self.cols)))
mem = chirp_common.Memory()
self._set_mem_vals(mem, vals, iter)
return mem
def _limit_key(self, which):
if which not in ["lo", "hi"]:
raise Exception(_("Internal Error: Invalid limit {number").format(number=which))
return "%s_%s" % (directory.radio_class_id(self.rthread.radio.__class__),
which)
def _store_limit(self, sb, which):
self._config.set_int(self._limit_key(which), int(sb.get_value()))
def make_controls(self, min, max):
hbox = gtk.HBox(False, 2)
lab = gtk.Label(_("Memory range:"))
lab.show()
hbox.pack_start(lab, 0, 0, 0)
lokey = self._limit_key("lo")
hikey = self._limit_key("hi")
lostart = self._config.is_defined(lokey) and \
self._config.get_int(lokey) or min
histart = self._config.is_defined(hikey) and \
self._config.get_int(hikey) or 25
self.lo_limit_adj = gtk.Adjustment(lostart, min, max-1, 1, 10)
lo = gtk.SpinButton(self.lo_limit_adj)
lo.connect("value-changed", self._store_limit, "lo")
lo.show()
hbox.pack_start(lo, 0, 0, 0)
lab = gtk.Label(" - ")
lab.show()
hbox.pack_start(lab, 0, 0, 0)
self.hi_limit_adj = gtk.Adjustment(histart, min+1, max, 1, 10)
hi = gtk.SpinButton(self.hi_limit_adj)
hi.connect("value-changed", self._store_limit, "hi")
hi.show()
hbox.pack_start(hi, 0, 0, 0)
refresh = gtk.Button(_("Go"))
refresh.show()
refresh.connect("clicked", lambda x: self.prefill())
hbox.pack_start(refresh, 0, 0, 0)
def activate_go(widget):
refresh.clicked()
def set_hi(widget, event):
loval = self.lo_limit_adj.get_value()
hival = self.hi_limit_adj.get_value()
if loval >= hival:
self.hi_limit_adj.set_value(loval + 25)
lo.connect_after("focus-out-event", set_hi)
lo.connect_after("activate", activate_go)
hi.connect_after("activate", activate_go)
sep = gtk.VSeparator()
sep.show()
sep.set_size_request(20, -1)
hbox.pack_start(sep, 0, 0, 0)
showspecial = gtk.CheckButton(_("Special Channels"))
showspecial.set_active(self.show_special)
showspecial.connect("toggled",
lambda x: self.set_show_special(x.get_active()))
showspecial.show()
hbox.pack_start(showspecial, 0, 0, 0)
showempty = gtk.CheckButton(_("Show Empty"))
showempty.set_active(self.show_empty);
showempty.connect("toggled",
lambda x: self.set_show_empty(x.get_active()))
showempty.show()
hbox.pack_start(showempty, 0, 0, 0)
hbox.show()
return hbox
def set_show_special(self, show):
self.show_special = show
self.prefill()
self._config.set_bool("show_special", show)
def set_show_empty(self, show):
self.show_empty = show
self.prefill()
self._config.set_bool("hide_empty", not show)
def set_read_only(self, read_only):
self.read_only = read_only
def get_read_only(self):
return self.read_only
def set_hide_unused(self, hide_unused):
self.hide_unused = hide_unused
self.prefill()
self._config.set_bool("hide_unused", hide_unused)
def __cache_columns(self):
# We call self.col() a lot. Caching the name->column# lookup
# makes a significant performance improvement
self._cached_cols = {}
i = 0
for x in self.cols:
self._cached_cols[x[0]] = i
i += 1
def get_unsupported_columns(self):
maybe_hide = [
("has_dtcs", _("DTCS Code")),
("has_rx_dtcs", _("DTCS Rx Code")),
("has_dtcs_polarity", _("DTCS Pol")),
("has_mode", _("Mode")),
("has_offset", _("Offset")),
("has_name", _("Name")),
("has_tuning_step", _("Tune Step")),
("has_name", _("Name")),
("has_ctone", _("ToneSql")),
("has_cross", _("Cross Mode")),
("has_comment", _("Comment")),
("valid_tmodes", _("Tone Mode")),
("valid_tmodes", _("Tone")),
("valid_duplexes", _("Duplex")),
("valid_skips", _("Skip")),
("valid_power_levels", _("Power")),
]
unsupported = []
for feature, colname in maybe_hide:
if feature.startswith("has_"):
supported = self._features[feature]
print "%s supported: %s" % (colname, supported)
elif feature.startswith("valid_"):
supported = len(self._features[feature]) != 0
if not supported:
unsupported.append(colname)
return unsupported
def get_columns_visible(self):
unsupported = self.get_unsupported_columns()
driver = directory.radio_class_id(self.rthread.radio.__class__)
user_visible = self._config.get(driver, "memedit_columns")
if user_visible:
user_visible = user_visible.split(",")
else:
# No setting for this radio, so assume all
user_visible = [x[0] for x in self.cols if x not in unsupported]
return user_visible
def __init__(self, rthread):
common.Editor.__init__(self)
self.rthread = rthread
self.defaults = dict(self.defaults)
self._config = config.get("memedit")
self.allowed_bands = [144, 440]
self.count = 100
self.show_special = self._config.get_bool("show_special")
self.show_empty = not self._config.get_bool("hide_empty")
self.hide_unused = self._config.get_bool("hide_unused")
self.read_only = False
self.need_refresh = False
self._in_editing = False
self.lo_limit_adj = self.hi_limit_adj = None
self.store = self.view = None
self.__cache_columns()
self._features = self.rthread.radio.get_features()
(min, max) = self._features.memory_bounds
self.choices[_("Mode")] = self._features["valid_modes"]
self.choices[_("Tone Mode")] = self._features["valid_tmodes"]
self.choices[_("Cross Mode")] = self._features["valid_cross_modes"]
self.choices[_("Skip")] = self._features["valid_skips"]
self.choices[_("Power")] = [str(x) for x in
self._features["valid_power_levels"]]
self.choices[_("DTCS Pol")] = self._features["valid_dtcs_pols"]
if self._features["valid_power_levels"]:
self.defaults[_("Power")] = self._features["valid_power_levels"][0]
self.choices[_("Duplex")] = list(self._features.valid_duplexes)
if self.defaults[_("Mode")] not in self._features.valid_modes:
self.defaults[_("Mode")] = self._features.valid_modes[0]
vbox = gtk.VBox(False, 2)
vbox.pack_start(self.make_controls(min, max), 0, 0, 0)
vbox.pack_start(self.make_editor(), 1, 1, 1)
vbox.show()
self.prefill()
self.choices["Mode"] = self._features.valid_modes
self.root = vbox
self.prefill()
# Run low priority jobs to get the rest of the memories
hi = int(self.hi_limit_adj.get_value())
for i in range(hi, max+1):
job = common.RadioJob(None, "get_memory", i)
job.set_desc(_("Getting memory {number}").format(number=i))
self.rthread.submit(job, 10)
def _set_memory_cb(self, result):
if isinstance(result, Exception):
# FIXME: This can't be in the thread
dlg = ValueErrorDialog(result)
dlg.run()
dlg.destroy()
self.prefill()
elif self.need_refresh:
self.prefill()
self.need_refresh = False
self.emit('changed')
def copy_selection(self, cut=False):
(store, paths) = self.view.get_selection().get_selected_rows()
maybe_cut = []
selection = []
for path in paths:
iter = store.get_iter(path)
mem = self._get_memory(iter)
selection.append(mem.dupe())
maybe_cut.append((iter, mem))
if cut:
for iter, mem in maybe_cut:
mem.empty = True
job = common.RadioJob(self._set_memory_cb,
"erase_memory", mem.number)
job.set_desc(_("Cutting memory {number}").format(number=mem.number))
self.rthread.submit(job)
self._set_memory(iter, mem)
result = pickle.dumps((self._features, selection))
clipboard = gtk.Clipboard(selection="PRIMARY")
clipboard.set_text(result)
return cut # Only changed if we did a cut
def _paste_selection(self, clipboard, text, data):
if not text:
return
(store, paths) = self.view.get_selection().get_selected_rows()
if len(paths) > 1:
common.show_error("To paste, select only the starting location")
return
iter = store.get_iter(paths[0])
always = False
try:
src_features, mem_list = pickle.loads(text)
except Exception:
print "Paste failed to unpickle"
return
if (paths[0][0] + len(mem_list)) > self._rows_in_store:
common.show_error(_("Unable to paste {src} memories into "
"{dst} rows. Increase the memory bounds "
"or show empty memories.").format(\
src=len(mem_list),
dst=(self._rows_in_store - paths[0][0])))
return
for mem in mem_list:
if mem.empty:
iter = self.store.iter_next(iter)
continue
loc, filled = store.get(iter,
self.col(_("Loc")), self.col("_filled"))
if filled and not always:
d = miscwidgets.YesNoDialog(title=_("Overwrite?"),
buttons=(gtk.STOCK_YES, 1,
gtk.STOCK_NO, 2,
gtk.STOCK_CANCEL, 3,
"All", 4))
d.set_text(_("Overwrite location {number}?").format(number=loc))
r = d.run()
d.destroy()
if r == 4:
always = True
elif r == 3:
break
elif r == 2:
iter = store.iter_next(iter)
continue
mem.name = self.rthread.radio.filter_name(mem.name)
src_number = mem.number
mem.number = loc
try:
mem = import_logic.import_mem(self.rthread.radio,
src_features,
mem)
except import_logic.DestNotCompatible:
msgs = self.rthread.radio.validate_memory(mem)
errs = [x for x in msgs if isinstance(x,
chirp_common.ValidationError)]
if errs:
d = miscwidgets.YesNoDialog(title=_("Incompatible Memory"),
buttons=(gtk.STOCK_OK, 1,
gtk.STOCK_CANCEL, 2))
d.set_text(_("Pasted memory {number} is not compatible with "
"this radio because:").format(number=src_number) +\
os.linesep + os.linesep.join(msgs))
r = d.run()
d.destroy()
if r == 2:
break
else:
iter = store.iter_next(iter)
continue
self._set_memory(iter, mem)
iter = store.iter_next(iter)
job = common.RadioJob(self._set_memory_cb, "set_memory", mem)
job.set_desc(_("Writing memory {number}").format(number=mem.number))
self.rthread.submit(job)
def paste_selection(self):
clipboard = gtk.Clipboard(selection="PRIMARY")
clipboard.request_text(self._paste_selection)
def prepare_close(self):
cols = self.view.get_columns()
self._config.set("column_order_%s" % self.__class__.__name__,
",".join([x.get_title() for x in cols]))
class DstarMemoryEditor(MemoryEditor):
def _get_cols_to_hide(self, iter):
hide = MemoryEditor._get_cols_to_hide(self, iter)
mode, = self.store.get(iter, self.col(_("Mode")))
if mode != "DV":
hide += [self.col("URCALL"),
self.col("RPT1CALL"),
self.col("RPT2CALL")]
return hide
def render(self, null, rend, model, iter, colnum):
MemoryEditor.render(self, null, rend, model, iter, colnum)
vals = model.get(iter, *tuple(range(0, len(self.cols))))
val = vals[colnum]
def _enabled(sensitive):
rend.set_property("sensitive", sensitive)
def d_unless_mode(mode):
_enabled(vals[self.col(_("Mode"))] == mode)
_dv_columns = [_("URCALL"), _("RPT1CALL"), _("RPT2CALL"),
_("Digital Code")]
dv_columns = [self.col(x) for x in _dv_columns]
if colnum in dv_columns:
d_unless_mode("DV")
def _get_memory(self, iter):
vals = self.store.get(iter, *range(0, len(self.cols)))
if vals[self.col(_("Mode"))] != "DV":
return MemoryEditor._get_memory(self, iter)
mem = chirp_common.DVMemory()
MemoryEditor._set_mem_vals(self, mem, vals, iter)
mem.dv_urcall = vals[self.col(_("URCALL"))]
mem.dv_rpt1call = vals[self.col(_("RPT1CALL"))]
mem.dv_rpt2call = vals[self.col(_("RPT2CALL"))]
mem.dv_code = vals[self.col(_("Digital Code"))]
return mem
def __init__(self, rthread):
# I think self.cols is "static" or "unbound" or something else
# like that and += modifies the type, not self (how bizarre)
self.cols = list(self.cols)
new_cols = [("URCALL", TYPE_STRING, gtk.CellRendererCombo),
("RPT1CALL", TYPE_STRING, gtk.CellRendererCombo),
("RPT2CALL", TYPE_STRING, gtk.CellRendererCombo),
("Digital Code", TYPE_INT, gtk.CellRendererText),
]
for col in new_cols:
index = self.cols.index(("_filled", TYPE_BOOLEAN, None))
self.cols.insert(index, col)
self.choices = dict(self.choices)
self.defaults = dict(self.defaults)
self.choices["URCALL"] = gtk.ListStore(TYPE_STRING, TYPE_STRING)
self.choices["RPT1CALL"] = gtk.ListStore(TYPE_STRING, TYPE_STRING)
self.choices["RPT2CALL"] = gtk.ListStore(TYPE_STRING, TYPE_STRING)
self.defaults["URCALL"] = ""
self.defaults["RPT1CALL"] = ""
self.defaults["RPT2CALL"] = ""
self.defaults["Digital Code"] = 0
MemoryEditor.__init__(self, rthread)
def ucall_cb(calls):
self.defaults["URCALL"] = calls[0]
for call in calls:
self.choices["URCALL"].append((call, call))
if self._features.requires_call_lists:
ujob = common.RadioJob(ucall_cb, "get_urcall_list")
ujob.set_desc(_("Downloading URCALL list"))
rthread.submit(ujob)
def rcall_cb(calls):
self.defaults["RPT1CALL"] = calls[0]
self.defaults["RPT2CALL"] = calls[0]
for call in calls:
self.choices["RPT1CALL"].append((call, call))
self.choices["RPT2CALL"].append((call, call))
if self._features.requires_call_lists:
rjob = common.RadioJob(rcall_cb, "get_repeater_call_list")
rjob.set_desc(_("Downloading RPTCALL list"))
rthread.submit(rjob)
_dv_columns = ["URCALL", "RPT1CALL", "RPT2CALL", "Digital Code"]
if not self._features.requires_call_lists:
for i in _dv_columns:
if not self.choices.has_key(i):
continue
column = self.view.get_column(self.col(i))
rend = column.get_cell_renderers()[0]
rend.set_property("has-entry", True)
for i in _dv_columns:
col = self.view.get_column(self.col(i))
rend = col.get_cell_renderers()[0]
rend.set_property("family", "Monospace")
def set_urcall_list(self, urcalls):
store = self.choices["URCALL"]
store.clear()
for call in urcalls:
store.append((call, call))
def set_repeater_list(self, repeaters):
for listname in ["RPT1CALL", "RPT2CALL"]:
store = self.choices[listname]
store.clear()
for call in repeaters:
store.append((call, call))
def _set_memory(self, iter, memory):
MemoryEditor._set_memory(self, iter, memory)
if isinstance(memory, chirp_common.DVMemory):
self.store.set(iter,
self.col("URCALL"), memory.dv_urcall,
self.col("RPT1CALL"), memory.dv_rpt1call,
self.col("RPT2CALL"), memory.dv_rpt2call,
self.col("Digital Code"), memory.dv_code,
)
else:
self.store.set(iter,
self.col("URCALL"), "",
self.col("RPT1CALL"), "",
self.col("RPT2CALL"), "",
self.col("Digital Code"), 0,
)
class ID800MemoryEditor(DstarMemoryEditor):
pass
chirp-0.3.1/chirpui/config.py 0000644 0000161 0177776 00000006436 12130403635 017305 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2011 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
from chirp import platform
from ConfigParser import ConfigParser
import os
class ChirpConfig:
def __init__(self, basepath, name="chirp.config"):
self.__basepath = basepath
self.__name = name
self._default_section = "global"
self.__config = ConfigParser()
cfg = os.path.join(basepath, name)
if os.path.exists(cfg):
self.__config.read(cfg)
def save(self):
cfg = os.path.join(self.__basepath, self.__name)
cfg_file = file(cfg, "w")
self.__config.write(cfg_file)
cfg_file.close()
def get(self, key, section):
if not self.__config.has_section(section):
return None
if not self.__config.has_option(section, key):
return None
return self.__config.get(section, key)
def set(self, key, value, section):
if not self.__config.has_section(section):
self.__config.add_section(section)
self.__config.set(section, key, value)
def is_defined(self, key, section):
return self.__config.has_option(section, key)
class ChirpConfigProxy:
def __init__(self, config, section="global"):
self._config = config
self._section = section
def get(self, key, section=None):
return self._config.get(key, section or self._section)
def set(self, key, value, section=None):
return self._config.set(key, value, section or self._section)
def get_int(self, key, section=None):
try:
return int(self.get(key, section))
except ValueError:
return 0
def set_int(self, key, value, section=None):
if not isinstance(value, int):
raise ValueError("Value is not an integer")
self.set(key, "%i" % value, section)
def get_float(self, key, section=None):
try:
return float(self.get(key, section))
except ValueError:
return 0
def set_float(self, key, value, section=None):
if not isinstance(value, float):
raise ValueError("Value is not an integer")
self.set(key, "%i" % value, section)
def get_bool(self, key, section=None):
return self.get(key, section) == "True"
def set_bool(self, key, value, section=None):
self.set(key, str(bool(value)), section)
def is_defined(self, key, section=None):
return self._config.is_defined(key, section or self._section)
_CONFIG = None
def get(section="global"):
global _CONFIG
p = platform.get_platform()
if not _CONFIG:
_CONFIG = ChirpConfig(p.config_dir())
return ChirpConfigProxy(_CONFIG, section)
chirp-0.3.1/chirpui/__init__.py 0000644 0000161 0000750 00000001256 11717005656 016144 0 ustar jenkins 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
chirp-0.3.1/chirpui/miscwidgets.py 0000644 0000161 0000750 00000052041 11717005656 016725 0 ustar jenkins 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
import pango
import os
from chirp import platform
class KeyedListWidget(gtk.HBox):
__gsignals__ = {
"item-selected" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_STRING,)),
"item-toggled" : (gobject.SIGNAL_ACTION,
gobject.TYPE_BOOLEAN,
(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)),
"item-set" : (gobject.SIGNAL_ACTION,
gobject.TYPE_BOOLEAN,
(gobject.TYPE_STRING,)),
}
def _toggle(self, rend, path, colnum):
if self.__toggle_connected:
self.__store[path][colnum] = not self.__store[path][colnum]
iter = self.__store.get_iter(path)
id, = self.__store.get(iter, 0)
self.emit("item-toggled", id, self.__store[path][colnum])
def _edited(self, rend, path, new, colnum):
iter = self.__store.get_iter(path)
key, oldval = self.__store.get(iter, 0, colnum)
self.__store.set(iter, colnum, new)
if not self.emit("item-set", key):
self.__store.set(iter, colnum, oldval)
def _mouse(self, view, event):
x, y = event.get_coords()
path = self.__view.get_path_at_pos(int(x), int(y))
if path:
self.__view.set_cursor_on_cell(path[0])
sel = self.get_selected()
if sel:
self.emit("item-selected", sel)
def _make_view(self):
colnum = -1
for typ, cap in self.columns:
colnum += 1
if colnum == 0:
continue # Key column
if typ in [gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_FLOAT]:
rend = gtk.CellRendererText()
rend.set_property("ellipsize", pango.ELLIPSIZE_END)
column = gtk.TreeViewColumn(cap, rend, text=colnum)
elif typ in [gobject.TYPE_BOOLEAN]:
rend = gtk.CellRendererToggle()
rend.connect("toggled", self._toggle, colnum)
column = gtk.TreeViewColumn(cap, rend, active=colnum)
else:
raise Exception("Unsupported type %s" % typ)
column.set_sort_column_id(colnum)
self.__view.append_column(column)
self.__view.connect("button_press_event", self._mouse)
def set_item(self, key, *values):
iter = self.__store.get_iter_first()
while iter:
id, = self.__store.get(iter, 0)
if id == key:
self.__store.insert_after(iter, row=(id,)+values)
self.__store.remove(iter)
return
iter = self.__store.iter_next(iter)
self.__store.append(row=(key,) + values)
self.emit("item-set", key)
def get_item(self, key):
iter = self.__store.get_iter_first()
while iter:
vals = self.__store.get(iter, *tuple(range(len(self.columns))))
if vals[0] == key:
return vals
iter = self.__store.iter_next(iter)
return None
def del_item(self, key):
iter = self.__store.get_iter_first()
while iter:
id, = self.__store.get(iter, 0)
if id == key:
self.__store.remove(iter)
return True
iter = self.__store.iter_next(iter)
return False
def has_item(self, key):
return self.get_item(key) is not None
def get_selected(self):
try:
(store, iter) = self.__view.get_selection().get_selected()
return store.get(iter, 0)[0]
except Exception, e:
print "Unable to find selected: %s" % e
return None
def select_item(self, key):
if key is None:
sel = self.__view.get_selection()
sel.unselect_all()
return True
iter = self.__store.get_iter_first()
while iter:
if self.__store.get(iter, 0)[0] == key:
selection = self.__view.get_selection()
path = self.__store.get_path(iter)
selection.select_path(path)
return True
iter = self.__store.iter_next(iter)
return False
def get_keys(self):
keys = []
iter = self.__store.get_iter_first()
while iter:
key, = self.__store.get(iter, 0)
keys.append(key)
iter = self.__store.iter_next(iter)
return keys
def __init__(self, columns):
gtk.HBox.__init__(self, True, 0)
self.columns = columns
types = tuple([x for x,y in columns])
self.__store = gtk.ListStore(*types)
self.__view = gtk.TreeView(self.__store)
self.pack_start(self.__view, 1, 1, 1)
self.__toggle_connected = False
self._make_view()
self.__view.show()
def connect(self, signame, *args):
if signame == "item-toggled":
self.__toggle_connected = True
gtk.HBox.connect(self, signame, *args)
def set_editable(self, column, is_editable):
col = self.__view.get_column(column)
rend = col.get_cell_renderers()[0]
rend.set_property("editable", True)
rend.connect("edited", self._edited, column + 1)
def set_sort_column(self, column, value=None):
if not value:
value = column
col = self.__view.get_column(column)
col.set_sort_column_id(value)
def get_renderer(self, colnum):
return self.__view.get_column(colnum).get_cell_renderers()[0]
class ListWidget(gtk.HBox):
__gsignals__ = {
"click-on-list" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gtk.TreeView, gtk.gdk.Event)),
"item-toggled" : (gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,)),
}
store_type = gtk.ListStore
def mouse_cb(self, view, event):
self.emit("click-on-list", view, event)
# pylint: disable-msg=W0613
def _toggle(self, render, path, column):
self._store[path][column] = not self._store[path][column]
iter = self._store.get_iter(path)
vals = tuple(self._store.get(iter, *tuple(range(self._ncols))))
for cb in self.toggle_cb:
cb(*vals)
self.emit("item-toggled", vals)
def make_view(self, columns):
self._view = gtk.TreeView(self._store)
for _type, _col in columns:
if _col.startswith("__"):
continue
index = columns.index((_type, _col))
if _type == gobject.TYPE_STRING or \
_type == gobject.TYPE_INT or \
_type == gobject.TYPE_FLOAT:
rend = gtk.CellRendererText()
column = gtk.TreeViewColumn(_col, rend, text=index)
column.set_resizable(True)
rend.set_property("ellipsize", pango.ELLIPSIZE_END)
elif _type == gobject.TYPE_BOOLEAN:
rend = gtk.CellRendererToggle()
rend.connect("toggled", self._toggle, index)
column = gtk.TreeViewColumn(_col, rend, active=index)
else:
raise Exception("Unknown column type (%i)" % index)
column.set_sort_column_id(index)
self._view.append_column(column)
self._view.connect("button_press_event", self.mouse_cb)
def __init__(self, columns, parent=True):
gtk.HBox.__init__(self)
# pylint: disable-msg=W0612
col_types = tuple([x for x, y in columns])
self._ncols = len(col_types)
self._store = self.store_type(*col_types)
self._view = None
self.make_view(columns)
self._view.show()
if parent:
self.pack_start(self._view, 1, 1, 1)
self.toggle_cb = []
def packable(self):
return self._view
def add_item(self, *vals):
if len(vals) != self._ncols:
raise Exception("Need %i columns" % self._ncols)
args = []
i = 0
for val in vals:
args.append(i)
args.append(val)
i += 1
args = tuple(args)
iter = self._store.append()
self._store.set(iter, *args)
def _remove_item(self, model, path, iter, match):
vals = model.get(iter, *tuple(range(0, self._ncols)))
if vals == match:
model.remove(iter)
def remove_item(self, *vals):
if len(vals) != self._ncols:
raise Exception("Need %i columns" % self._ncols)
def remove_selected(self):
try:
(lst, iter) = self._view.get_selection().get_selected()
lst.remove(iter)
except Exception, e:
print "Unable to remove selected: %s" % e
def get_selected(self, take_default=False):
(lst, iter) = self._view.get_selection().get_selected()
if not iter and take_default:
iter = lst.get_iter_first()
return lst.get(iter, *tuple(range(self._ncols)))
def move_selected(self, delta):
(lst, iter) = self._view.get_selection().get_selected()
pos = int(lst.get_path(iter)[0])
try:
target = None
if delta > 0 and pos > 0:
target = lst.get_iter(pos-1)
elif delta < 0:
target = lst.get_iter(pos+1)
except Exception, e:
return False
if target:
return lst.swap(iter, target)
def _get_value(self, model, path, iter, lst):
lst.append(model.get(iter, *tuple(range(0, self._ncols))))
def get_values(self):
lst = []
self._store.foreach(self._get_value, lst)
return lst
def set_values(self, lst):
self._store.clear()
for i in lst:
self.add_item(*i)
class TreeWidget(ListWidget):
store_type = gtk.TreeStore
# pylint: disable-msg=W0613
def _toggle(self, render, path, column):
self._store[path][column] = not self._store[path][column]
iter = self._store.get_iter(path)
vals = tuple(self._store.get(iter, *tuple(range(self._ncols))))
piter = self._store.iter_parent(iter)
if piter:
parent = self._store.get(piter, self._key)[0]
else:
parent = None
for cb in self.toggle_cb:
cb(parent, *vals)
def __init__(self, columns, key, parent=True):
ListWidget.__init__(self, columns, parent)
self._key = key
def _add_item(self, piter, *vals):
args = []
i = 0
for val in vals:
args.append(i)
args.append(val)
i += 1
args = tuple(args)
iter = self._store.append(piter)
self._store.set(iter, *args)
def _iter_of(self, key, iter=None):
if not iter:
iter = self._store.get_iter_first()
while iter is not None:
_id = self._store.get(iter, self._key)[0]
if _id == key:
return iter
iter = self._store.iter_next(iter)
return None
def add_item(self, parent, *vals):
if len(vals) != self._ncols:
raise Exception("Need %i columns" % self._ncols)
if not parent:
self._add_item(None, *vals)
else:
iter = self._iter_of(parent)
if iter:
self._add_item(iter, *vals)
else:
raise Exception("Parent not found: %s", parent)
def _set_values(self, parent, vals):
if isinstance(vals, dict):
for key, val in vals.items():
iter = self._store.append(parent)
self._store.set(iter, self._key, key)
self._set_values(iter, val)
elif isinstance(vals, list):
for i in vals:
self._set_values(parent, i)
elif isinstance(vals, tuple):
self._add_item(parent, *vals)
else:
print "Unknown type: %s" % vals
def set_values(self, vals):
self._store.clear()
self._set_values(self._store.get_iter_first(), vals)
def del_item(self, parent, key):
iter = self._iter_of(key,
self._store.iter_children(self._iter_of(parent)))
if iter:
self._store.remove(iter)
else:
raise Exception("Item not found")
def get_item(self, parent, key):
iter = self._iter_of(key,
self._store.iter_children(self._iter_of(parent)))
if iter:
return self._store.get(iter, *(tuple(range(0, self._ncols))))
else:
raise Exception("Item not found")
def set_item(self, parent, *vals):
iter = self._iter_of(vals[self._key],
self._store.iter_children(self._iter_of(parent)))
if iter:
args = []
i = 0
for val in vals:
args.append(i)
args.append(val)
i += 1
self._store.set(iter, *(tuple(args)))
else:
raise Exception("Item not found")
class ProgressDialog(gtk.Window):
def __init__(self, title, parent=None):
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
self.set_modal(True)
self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self.set_title(title)
if parent:
self.set_transient_for(parent)
self.set_resizable(False)
vbox = gtk.VBox(False, 2)
self.label = gtk.Label("")
self.label.set_size_request(100, 50)
self.label.show()
self.pbar = gtk.ProgressBar()
self.pbar.show()
vbox.pack_start(self.label, 0, 0, 0)
vbox.pack_start(self.pbar, 0, 0, 0)
vbox.show()
self.add(vbox)
def set_text(self, text):
self.label.set_text(text)
self.queue_draw()
while gtk.events_pending():
gtk.main_iteration_do(False)
def set_fraction(self, frac):
self.pbar.set_fraction(frac)
self.queue_draw()
while gtk.events_pending():
gtk.main_iteration_do(False)
class LatLonEntry(gtk.Entry):
def __init__(self, *args):
gtk.Entry.__init__(self, *args)
self.connect("changed", self.format)
def format(self, entry):
string = entry.get_text()
if string is None:
return
deg = u"\u00b0"
while " " in string:
if "." in string:
break
elif deg not in string:
string = string.replace(" ", deg)
elif "'" not in string:
string = string.replace(" ", "'")
elif '"' not in string:
string = string.replace(" ", '"')
else:
string = string.replace(" ", "")
entry.set_text(string)
def parse_dd(self, string):
return float(string)
def parse_dm(self, string):
string = string.strip()
string = string.replace(' ', ' ')
(_degrees, _minutes) = string.split(' ', 2)
degrees = int(_degrees)
minutes = float(_minutes)
return degrees + (minutes / 60.0)
def parse_dms(self, string):
string = string.replace(u"\u00b0", " ")
string = string.replace('"', ' ')
string = string.replace("'", ' ')
string = string.replace(' ', ' ')
string = string.strip()
items = string.split(' ')
if len(items) > 3:
raise Exception("Invalid format")
elif len(items) == 3:
deg = items[0]
mns = items[1]
sec = items[2]
elif len(items) == 2:
deg = items[0]
mns = items[1]
sec = 0
elif len(items) == 1:
deg = items[0]
mns = 0
sec = 0
else:
deg = 0
mns = 0
sec = 0
degrees = int(deg)
minutes = int(mns)
seconds = float(sec)
return degrees + (minutes / 60.0) + (seconds / 3600.0)
def value(self):
string = self.get_text()
try:
return self.parse_dd(string)
except:
try:
return self.parse_dm(string)
except:
try:
return self.parse_dms(string)
except Exception, e:
print "DMS: %s" % e
raise Exception("Invalid format")
def validate(self):
try:
self.value()
return True
except:
return False
class YesNoDialog(gtk.Dialog):
def __init__(self, title="", parent=None, buttons=None):
gtk.Dialog.__init__(self, title=title, parent=parent, buttons=buttons)
self._label = gtk.Label("")
self._label.show()
# pylint: disable-msg=E1101
self.vbox.pack_start(self._label, 1, 1, 1)
def set_text(self, text):
self._label.set_text(text)
def make_choice(options, editable=True, default=None):
if editable:
sel = gtk.combo_box_entry_new_text()
else:
sel = gtk.combo_box_new_text()
for opt in options:
sel.append_text(opt)
if default:
try:
idx = options.index(default)
sel.set_active(idx)
except:
pass
return sel
class FilenameBox(gtk.HBox):
__gsignals__ = {
"filename-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
}
def do_browse(self, _, dir):
if self.filename.get_text():
start = os.path.dirname(self.filename.get_text())
else:
start = None
if dir:
fn = platform.get_platform().gui_select_dir(start)
else:
fn = platform.get_platform().gui_save_file(start, types=self.types)
if fn:
self.filename.set_text(fn)
def do_changed(self, _):
self.emit("filename_changed")
def __init__(self, find_dir=False, types=[]):
gtk.HBox.__init__(self, False, 0)
self.types = types
self.filename = gtk.Entry()
self.filename.show()
self.pack_start(self.filename, 1, 1, 1)
browse = gtk.Button("...")
browse.show()
self.pack_start(browse, 0, 0, 0)
self.filename.connect("changed", self.do_changed)
browse.connect("clicked", self.do_browse, find_dir)
def set_filename(self, fn):
self.filename.set_text(fn)
def get_filename(self):
return self.filename.get_text()
def make_pixbuf_choice(options, default=None):
store = gtk.ListStore(gtk.gdk.Pixbuf, gobject.TYPE_STRING)
box = gtk.ComboBox(store)
cell = gtk.CellRendererPixbuf()
box.pack_start(cell, True)
box.add_attribute(cell, "pixbuf", 0)
cell = gtk.CellRendererText()
box.pack_start(cell, True)
box.add_attribute(cell, "text", 1)
_default = None
for pic, value in options:
iter = store.append()
store.set(iter, 0, pic, 1, value)
if default == value:
_default = options.index((pic, value))
if _default:
box.set_active(_default)
return box
def test():
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
lst = ListWidget([(gobject.TYPE_STRING, "Foo"),
(gobject.TYPE_BOOLEAN, "Bar")])
lst.add_item("Test1", True)
lst.set_values([("Test2", True), ("Test3", False)])
lst.show()
win.add(lst)
win.show()
win1 = ProgressDialog("foo")
win1.show()
win2 = gtk.Window(gtk.WINDOW_TOPLEVEL)
lle = LatLonEntry()
lle.show()
win2.add(lle)
win2.show()
win3 = gtk.Window(gtk.WINDOW_TOPLEVEL)
lst = TreeWidget([(gobject.TYPE_STRING, "Id"),
(gobject.TYPE_STRING, "Value")],
1)
#l.add_item(None, "Foo", "Bar")
#l.add_item("Foo", "Bar", "Baz")
lst.set_values({"Fruit" : [("Apple", "Red"), ("Orange", "Orange")],
"Pizza" : [("Cheese", "Simple"), ("Pepperoni", "Yummy")]})
lst.add_item("Fruit", "Bananna", "Yellow")
lst.show()
win3.add(lst)
win3.show()
def print_val(entry):
if entry.validate():
print "Valid: %s" % entry.value()
else:
print "Invalid"
lle.connect("activate", print_val)
lle.set_text("45 13 12")
try:
gtk.main()
except KeyboardInterrupt:
pass
print lst.get_values()
if __name__ == "__main__":
test()
chirp-0.3.1/chirpui/memdetail.py 0000644 0000161 0177776 00000027302 12130403635 017774 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2012 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import os
from chirp import chirp_common, settings
from chirpui import miscwidgets, common
POL = ["NN", "NR", "RN", "RR"]
class ValueEditor:
"""Base class"""
def __init__(self, features, memory, errfn, name, data=None):
self._features = features
self._memory = memory
self._errfn = errfn
self._name = name
self._widget = None
self._init(data)
def _init(self, data):
"""Type-specific initialization"""
def get_widget(self):
"""Returns the widget associated with this editor"""
return self._widget
def _mem_value(self):
"""Returns the raw value from the memory associated with this name"""
if self._name.startswith("extra_"):
return self._memory.extra[self._name.split("_", 1)[1]].value
else:
return getattr(self._memory, self._name)
def _get_value(self):
"""Returns the value from the widget that should be set in the memory"""
def update(self):
"""Updates the memory object with self._getvalue()"""
try:
newval = self._get_value()
except ValueError, e:
self._errfn(self._name, str(e))
return str(e)
if self._name.startswith("extra_"):
try:
self._memory.extra[self._name.split("_", 1)[1]].value = newval
except settings.InternalError, e:
self._errfn(self._name, str(e))
return str(e)
else:
try:
setattr(self._memory, self._name, newval)
except chirp_common.ImmutableValueError, e:
if getattr(self._memory, self._name) != self._get_value():
self._errfn(self._name, str(e))
return str(e)
except ValueError, e:
self._errfn(self._name, str(e))
return str(e)
all_msgs = self._features.validate_memory(self._memory)
errs = []
for msg in all_msgs:
if isinstance(msg, chirp_common.ValidationError):
errs.append(str(msg))
if errs:
self._errfn(self._name, errs)
else:
self._errfn(self._name, None)
class StringEditor(ValueEditor):
def _init(self, data):
self._widget = gtk.Entry(int(data))
self._widget.set_text(str(self._mem_value()))
self._widget.connect("changed", self.changed)
def _get_value(self):
return self._widget.get_text()
def changed(self, _widget):
self.update()
class ChoiceEditor(ValueEditor):
def _init(self, data):
self._widget = miscwidgets.make_choice([str(x) for x in data],
False,
str(self._mem_value()))
self._widget.connect("changed", self.changed)
def _get_value(self):
return self._widget.get_active_text()
def changed(self, _widget):
self.update()
class PowerChoiceEditor(ChoiceEditor):
def _init(self, data):
self._choices = data
ChoiceEditor._init(self, data)
def _get_value(self):
choice = self._widget.get_active_text()
for level in self._choices:
if str(level) == choice:
return level
raise Exception("Internal error: power level went missing")
class IntChoiceEditor(ChoiceEditor):
def _get_value(self):
return int(self._widget.get_active_text())
class FloatChoiceEditor(ChoiceEditor):
def _get_value(self):
return float(self._widget.get_active_text())
class FreqEditor(StringEditor):
def _init(self, data):
StringEditor._init(self, 0)
def _mem_value(self):
return chirp_common.format_freq(StringEditor._mem_value(self))
def _get_value(self):
return chirp_common.parse_freq(self._widget.get_text())
class BooleanEditor(ValueEditor):
def _init(self, data):
self._widget = gtk.CheckButton("Enabled")
self._widget.set_active(self._mem_value())
self._widget.connect("toggled", self.toggled)
def _get_value(self):
return self._widget.get_active()
def toggled(self, _widget):
self.update()
class OffsetEditor(FreqEditor):
pass
class MemoryDetailEditor(gtk.Dialog):
"""Detail editor for a memory"""
def _add(self, tab, row, name, editor, labeltxt):
label = gtk.Label(labeltxt)
img = gtk.Image()
label.show()
tab.attach(label, 0, 1, row, row+1)
editor.get_widget().show()
tab.attach(editor.get_widget(), 1, 2, row, row+1)
img.set_size_request(15, -1)
img.show()
tab.attach(img, 2, 3, row, row+1)
self._editors[name] = label, editor, img
def _set_doc(self, name, doc):
label, editor, _img = self._editors[name]
self._tips.set_tip(label, doc)
self._tips.set_tip(editor.get_widget(), doc)
def _make_ui(self):
tab = gtk.Table(len(self._order), 3, False)
self.vbox.pack_start(tab, 1, 1, 1)
tab.show()
row = 0
def _err(name, msg):
try:
_img = self._editors[name][2]
except KeyError:
print self._editors.keys()
if msg is None:
_img.clear()
self._tips.set_tip(_img, "")
else:
_img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_MENU)
self._tips.set_tip(_img, str(msg))
self._errors[self._order.index(name)] = msg is not None
self.set_response_sensitive(gtk.RESPONSE_OK,
True not in self._errors)
for name in self._order:
labeltxt, editorcls, data = self._elements[name]
editor = editorcls(self._features, self._memory,
_err, name, data)
self._add(tab, row, name, editor, labeltxt)
row += 1
for setting in self._memory.extra:
name = "extra_%s" % setting.get_name()
if isinstance(setting.value,
settings.RadioSettingValueBoolean):
editor = BooleanEditor(self._features, self._memory,
_err, name)
self._add(tab, row, name, editor, setting.get_shortname())
self._set_doc(name, setting.__doc__)
elif isinstance(setting.value,
settings.RadioSettingValueList):
editor = ChoiceEditor(self._features, self._memory,
_err, name, setting.value.get_options())
self._add(tab, row, name, editor, setting.get_shortname())
self._set_doc(name, setting.__doc__)
row += 1
self._order.append(name)
def __init__(self, features, memory, parent=None):
gtk.Dialog.__init__(self,
title=_("Edit Memory"
"#{num}").format(num=memory.number),
flags=gtk.DIALOG_MODAL,
parent=parent,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
self._tips = gtk.Tooltips()
self._features = features
self._memory = memory
self._editors = {}
self._elements = {
"freq" : (_("Frequency"), FreqEditor, None),
"name" : (_("Name"), StringEditor, features.valid_name_length),
"tmode" : (_("Tone Mode"), ChoiceEditor, features.valid_tmodes),
"rtone" : (_("Tone"), FloatChoiceEditor, chirp_common.TONES),
"ctone" : (_("ToneSql"), FloatChoiceEditor, chirp_common.TONES),
"dtcs" : (_("DTCS Code"), IntChoiceEditor,
chirp_common.DTCS_CODES),
"dtcs_polarity" : (_("DTCS Pol"), ChoiceEditor, POL),
"cross_mode" : (_("Cross mode"),
ChoiceEditor,
features.valid_cross_modes),
"duplex" : (_("Duplex"), ChoiceEditor, features.valid_duplexes),
"offset" : (_("Offset"), OffsetEditor, None),
"mode" : (_("Mode"), ChoiceEditor, features.valid_modes),
"tuning_step" : (_("Tune Step"),
FloatChoiceEditor,
features.valid_tuning_steps),
"skip" : (_("Skip"), ChoiceEditor, features.valid_skips),
"comment" : (_("Comment"), StringEditor, 256),
}
self._order = ["freq", "name", "tmode", "rtone", "ctone", "cross_mode",
"dtcs", "dtcs_polarity", "duplex", "offset",
"mode", "tuning_step", "skip", "comment"]
if self._features.has_rx_dtcs:
self._elements['rx_dtcs'] = (_("RX DTCS Code"),
IntChoiceEditor,
chirp_common.DTCS_CODES)
self._order.insert(self._order.index("dtcs") + 1, "rx_dtcs")
if self._features.valid_power_levels:
self._elements["power"] = (_("Power"),
PowerChoiceEditor,
features.valid_power_levels)
self._order.insert(self._order.index("skip"), "power")
self._make_ui()
self.set_default_size(400, -1)
hide_rules = [
("name", features.has_name),
("tmode", len(features.valid_tmodes) > 0),
("ctone", features.has_ctone),
("dtcs", features.has_dtcs),
("dtcs_polarity", features.has_dtcs_polarity),
("cross_mode", "Cross" in features.valid_tmodes),
("duplex", len(features.valid_duplexes) > 0),
("offset", features.has_offset),
("mode", len(features.valid_modes) > 0),
("tuning_step", features.has_tuning_step),
("skip", len(features.valid_skips) > 0),
("comment", features.has_comment),
]
for name, visible in hide_rules:
if not visible:
for widget in self._editors[name]:
if isinstance(widget, ValueEditor):
widget.get_widget().hide()
else:
widget.hide()
self._errors = [False] * len(self._order)
self.connect("response", self._validate)
def _validate(self, _dialog, response):
if response == gtk.RESPONSE_OK:
all_msgs = self._features.validate_memory(self._memory)
errors = []
for msg in all_msgs:
if isinstance(msg, chirp_common.ValidationError):
errors.append(msg)
if errors:
common.show_error_text(_("Memory validation failed:"),
os.linesep +
os.linesep.join(errors))
self.emit_stop_by_name('response')
def get_memory(self):
self._memory.empty = False
return self._memory
chirp-0.3.1/chirpui/importdialog.py 0000644 0000161 0177776 00000053712 12105270073 020531 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
import pango
from chirp import errors, chirp_common, generic_xml, import_logic
from chirpui import common
class WaitWindow(gtk.Window):
def __init__(self, msg, parent=None):
gtk.Window.__init__(self)
self.set_title("Please Wait")
self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
if parent:
self.set_transient_for(parent)
self.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
else:
self.set_position(gtk.WIN_POS_CENTER)
vbox = gtk.VBox(False, 2)
l = gtk.Label(msg)
l.show()
vbox.pack_start(l)
self.prog = gtk.ProgressBar()
self.prog.show()
vbox.pack_start(self.prog)
vbox.show()
self.add(vbox)
def grind(self):
while gtk.events_pending():
gtk.main_iteration(False)
self.prog.pulse()
def set(self, fraction):
while gtk.events_pending():
gtk.main_iteration(False)
self.prog.set_fraction(fraction)
class ImportMemoryBankJob(common.RadioJob):
def __init__(self, cb, dst_mem, src_radio, src_mem):
common.RadioJob.__init__(self, cb, None)
self.__dst_mem = dst_mem
self.__src_radio = src_radio
self.__src_mem = src_mem
def execute(self, radio):
import_logic.import_bank(radio, self.__src_radio,
self.__dst_mem, self.__src_mem)
if self.cb:
gobject.idle_add(self.cb, *self.cb_args)
class ImportDialog(gtk.Dialog):
def _check_for_dupe(self, location):
iter = self.__store.get_iter_first()
while iter:
imp, loc = self.__store.get(iter, self.col_import, self.col_nloc)
if imp and loc == location:
return True
iter = self.__store.iter_next(iter)
return False
def _toggle(self, rend, path, col):
iter = self.__store.get_iter(path)
imp, nloc = self.__store.get(iter, self.col_import, self.col_nloc)
if not imp and self._check_for_dupe(nloc):
d = gtk.MessageDialog(parent=self, buttons=gtk.BUTTONS_OK)
d.set_property("text",
_("Location {number} is already being imported. "
"Choose another value for 'New Location' "
"before selection 'Import'").format(\
number=nloc))
d.run()
d.destroy()
else:
self.__store[path][col] = not imp
def _render(self, _, rend, model, iter, colnum):
newloc, imp = model.get(iter, self.col_nloc, self.col_import)
lo,hi = self.dst_radio.get_features().memory_bounds
rend.set_property("text", "%i" % newloc)
if newloc in self.used_list and imp:
rend.set_property("foreground", "goldenrod")
rend.set_property("weight", pango.WEIGHT_BOLD)
elif newloc < lo or newloc > hi:
rend.set_property("foreground", "red")
rend.set_property("weight", pango.WEIGHT_BOLD)
else:
rend.set_property("foreground", "black")
rend.set_property("weight", pango.WEIGHT_NORMAL)
def _edited(self, rend, path, new, col):
iter = self.__store.get_iter(path)
if col == self.col_nloc:
nloc, = self.__store.get(iter, self.col_nloc)
try:
val = int(new)
except ValueError:
common.show_error(_("Invalid value. Must be an integer."))
return
if val == nloc:
return
if self._check_for_dupe(val):
d = gtk.MessageDialog(parent=self, buttons=gtk.BUTTONS_OK)
d.set_property("text",
_("Location {number} is already being "
"imported").format(number=val))
d.run()
d.destroy()
return
self.record_use_of(val)
elif col == self.col_name or col == self.col_comm:
val = str(new)
else:
return
self.__store.set(iter, col, val)
def get_import_list(self):
import_list = []
iter = self.__store.get_iter_first()
while iter:
old, new, name, comm, enb = self.__store.get(iter,
self.col_oloc,
self.col_nloc,
self.col_name,
self.col_comm,
self.col_import)
if enb:
import_list.append((old, new, name, comm))
iter = self.__store.iter_next(iter)
return import_list
def ensure_calls(self, dst_rthread, import_list):
rlist_changed = False
ulist_changed = False
if not isinstance(self.dst_radio, chirp_common.IcomDstarSupport):
return
ulist = self.dst_radio.get_urcall_list()
rlist = self.dst_radio.get_repeater_call_list()
for old, new in import_list:
mem = self.src_radio.get_memory(old)
if isinstance(mem, chirp_common.DVMemory):
if mem.dv_urcall not in ulist:
print "Adding %s to ucall list" % mem.dv_urcall
ulist.append(mem.dv_urcall)
ulist_changed = True
if mem.dv_rpt1call not in rlist:
print "Adding %s to rcall list" % mem.dv_rpt1call
rlist.append(mem.dv_rpt1call)
rlist_changed = True
if mem.dv_rpt2call not in rlist:
print "Adding %s to rcall list" % mem.dv_rpt2call
rlist.append(mem.dv_rpt2call)
rlist_changed = True
if ulist_changed:
job = common.RadioJob(None, "set_urcall_list", ulist)
job.set_desc(_("Updating URCALL list"))
dst_rthread._qsubmit(job, 0)
if rlist_changed:
job = common.RadioJob(None, "set_repeater_call_list", ulist)
job.set_desc(_("Updating RPTCALL list"))
dst_rthread._qsubmit(job, 0)
return
def _convert_power(self, dst_levels, src_levels, mem):
if not dst_levels:
mem.power = None
return
elif not mem.power:
# Source radio does not support power levels, so choose the
# first (highest) level from the destination radio.
mem.power = dst_levels[0]
return ""
# If both radios support power levels, we need to decide how to
# convert the source power level to a valid one for the destination
# radio. To do that, find the absolute level of the source value
# and calculate the different between it and all the levels of the
# destination, choosing the one that matches most closely.
deltas = [abs(mem.power - power) for power in dst_levels]
mem.power = dst_levels[deltas.index(min(deltas))]
def do_soft_conversions(self, dst_features, src_features, mem):
self._convert_power(dst_features.valid_power_levels,
src_features.valid_power_levels,
mem)
return mem
def do_import_banks(self):
try:
dst_banks = self.dst_radio.get_banks()
src_banks = self.src_radio.get_banks()
if not dst_banks or not src_banks:
raise Exception()
except Exception:
print "One or more of the radios doesn't support banks"
return
if not isinstance(self.dst_radio, generic_xml.XMLRadio) and \
len(dst_banks) != len(src_banks):
print "Source and destination radios have a different number of banks"
else:
self.dst_radio.set_banks(src_banks)
def do_import(self, dst_rthread):
i = 0
error_messages = {}
import_list = self.get_import_list()
src_features = self.src_radio.get_features()
for old, new, name, comm in import_list:
i += 1
print "%sing %i -> %i" % (self.ACTION, old, new)
src = self.src_radio.get_memory(old)
try:
mem = import_logic.import_mem(self.dst_radio,
src_features,
src,
{"number" : new,
"name" : name,
"comment": comm})
except import_logic.ImportError, e:
print e
error_messages[new] = str(e)
continue
job = common.RadioJob(None, "set_memory", mem)
job.set_desc(_("Setting memory {number}").format(number=mem.number))
dst_rthread._qsubmit(job, 0)
job = ImportMemoryBankJob(None, mem, self.src_radio, src)
job.set_desc(_("Importing bank information"))
dst_rthread._qsubmit(job, 0)
if error_messages.keys():
msg = _("Error importing memories:") + "\r\n"
for num, msgs in error_messages.items():
msg += "%s: %s" % (num, ",".join(msgs))
common.show_error(msg)
return i
def make_view(self):
editable = [self.col_nloc, self.col_name, self.col_comm]
self.__store = gtk.ListStore(gobject.TYPE_BOOLEAN, # Import
gobject.TYPE_INT, # Source loc
gobject.TYPE_INT, # Destination loc
gobject.TYPE_STRING, # Name
gobject.TYPE_STRING, # Frequency
gobject.TYPE_STRING, # Comment
gobject.TYPE_BOOLEAN,
gobject.TYPE_STRING)
self.__view = gtk.TreeView(self.__store)
self.__view.show()
tips = gtk.Tooltips()
for k in self.caps.keys():
t = self.types[k]
if t == gobject.TYPE_BOOLEAN:
rend = gtk.CellRendererToggle()
rend.connect("toggled", self._toggle, k)
column = gtk.TreeViewColumn(self.caps[k], rend,
active=k,
sensitive=self.col_okay,
activatable=self.col_okay)
else:
rend = gtk.CellRendererText()
if k in editable:
rend.set_property("editable", True)
rend.connect("edited", self._edited, k)
column = gtk.TreeViewColumn(self.caps[k], rend,
text=k,
sensitive=self.col_okay)
if k == self.col_nloc:
column.set_cell_data_func(rend, self._render, k)
if k in self.tips.keys():
print "Doing %s" % k
lab = gtk.Label(self.caps[k])
column.set_widget(lab)
tips.set_tip(lab, self.tips[k])
lab.show()
column.set_sort_column_id(k)
self.__view.append_column(column)
self.__view.set_tooltip_column(self.col_tmsg)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add(self.__view)
sw.show()
return sw
def __select_all(self, button, state):
iter = self.__store.get_iter_first()
while iter:
_state, okay, = self.__store.get(iter,
self.col_import,
self.col_okay)
if state is None:
_state = not _state and okay
else:
_state = state and okay
self.__store.set(iter, self.col_import, _state)
iter = self.__store.iter_next(iter)
def __incrnew(self, button, delta):
iter = self.__store.get_iter_first()
while iter:
pos = self.__store.get(iter, self.col_nloc)[0]
pos += delta
if pos < 0:
pos = 0
self.__store.set(iter, self.col_nloc, pos)
iter = self.__store.iter_next(iter)
def __autonew(self, button):
pos = self.dst_radio.get_features().memory_bounds[0]
iter = self.__store.get_iter_first()
while iter:
selected, okay = self.__store.get(iter,
self.col_import, self.col_okay)
if selected and okay:
self.__store.set(iter, self.col_nloc, pos)
pos += 1
iter = self.__store.iter_next(iter)
def __revrnew(self, button):
positions = []
iter = self.__store.get_iter_first()
while iter:
positions.append(self.__store.get(iter, self.col_nloc)[0])
iter = self.__store.iter_next(iter)
iter = self.__store.get_iter_first()
while iter:
self.__store.set(iter, self.col_nloc, positions.pop())
iter = self.__store.iter_next(iter)
def make_select(self):
hbox = gtk.HBox(True, 2)
all = gtk.Button(_("All"));
all.connect("clicked", self.__select_all, True)
all.set_size_request(50, 25)
all.show()
hbox.pack_start(all, 0, 0, 0)
none = gtk.Button(_("None"));
none.connect("clicked", self.__select_all, False)
none.set_size_request(50, 25)
none.show()
hbox.pack_start(none, 0, 0, 0)
inv = gtk.Button(_("Inverse"))
inv.connect("clicked", self.__select_all, None)
inv.set_size_request(50, 25)
inv.show()
hbox.pack_start(inv, 0, 0, 0)
frame = gtk.Frame(_("Select"))
frame.show()
frame.add(hbox)
hbox.show()
return frame
def make_adjust(self):
hbox = gtk.HBox(True, 2)
incr = gtk.Button("+100")
incr.connect("clicked", self.__incrnew, 100)
incr.set_size_request(50, 25)
incr.show()
hbox.pack_start(incr, 0, 0, 0)
incr = gtk.Button("+10")
incr.connect("clicked", self.__incrnew, 10)
incr.set_size_request(50, 25)
incr.show()
hbox.pack_start(incr, 0, 0, 0)
incr = gtk.Button("+1")
incr.connect("clicked", self.__incrnew, 1)
incr.set_size_request(50, 25)
incr.show()
hbox.pack_start(incr, 0, 0, 0)
decr = gtk.Button("-1")
decr.connect("clicked", self.__incrnew, -1)
decr.set_size_request(50, 25)
decr.show()
hbox.pack_start(decr, 0, 0, 0)
decr = gtk.Button("-10")
decr.connect("clicked", self.__incrnew, -10)
decr.set_size_request(50, 25)
decr.show()
hbox.pack_start(decr, 0, 0, 0)
decr = gtk.Button("-100")
decr.connect("clicked", self.__incrnew, -100)
decr.set_size_request(50, 25)
decr.show()
hbox.pack_start(decr, 0, 0, 0)
auto = gtk.Button(_("Auto"))
auto.connect("clicked", self.__autonew)
auto.set_size_request(50, 25)
auto.show()
hbox.pack_start(auto, 0, 0, 0)
revr = gtk.Button(_("Reverse"))
revr.connect("clicked", self.__revrnew)
revr.set_size_request(50, 25)
revr.show()
hbox.pack_start(revr, 0, 0, 0)
frame = gtk.Frame(_("Adjust New Location"))
frame.show()
frame.add(hbox)
hbox.show()
return frame
def make_options(self):
hbox = gtk.HBox(True, 2)
confirm = gtk.CheckButton(_("Confirm overwrites"))
confirm.connect("toggled", __set_confirm)
confirm.show()
hbox.pack_start(confirm, 0, 0, 0)
frame = gtk.Frame(_("Options"))
frame.add(hbox)
frame.show()
hbox.show()
return frame
def make_controls(self):
hbox = gtk.HBox(False, 2)
hbox.pack_start(self.make_select(), 0, 0, 0)
hbox.pack_start(self.make_adjust(), 0, 0, 0)
#hbox.pack_start(self.make_options(), 0, 0, 0)
hbox.show()
return hbox
def build_ui(self):
self.vbox.pack_start(self.make_view(), 1, 1, 1)
self.vbox.pack_start(self.make_controls(), 0, 0, 0)
def record_use_of(self, number):
lo, hi = self.dst_radio.get_features().memory_bounds
if number < lo or number > hi:
return
try:
mem = self.dst_radio.get_memory(number)
if mem and not mem.empty and number not in self.used_list:
self.used_list.append(number)
except errors.InvalidMemoryLocation:
print "Location %i empty or at limit of destination radio" % number
except errors.InvalidDataError, e:
print "Got error from radio, assuming %i beyond limits: %s" % \
(number, e)
def populate_list(self):
start, end = self.src_radio.get_features().memory_bounds
for i in range(start, end+1):
if end > 50 and i % (end/50) == 0:
self.ww.set(float(i) / end)
try:
mem = self.src_radio.get_memory(i)
except errors.InvalidMemoryLocation, e:
continue
except Exception, e:
self.__store.append(row=(False,
i,
i,
"ERROR",
chirp_common.format_freq(0),
"",
False,
str(e),
))
self.record_use_of(i)
continue
if mem.empty:
continue
self.ww.set(float(i) / end)
try:
msgs = self.dst_radio.validate_memory(
import_logic.import_mem(self.dst_radio,
self.src_radio.get_features(),
mem))
except import_logic.DestNotCompatible:
msgs = self.dst_radio.validate_memory(mem)
errs = [x for x in msgs if isinstance(x, chirp_common.ValidationError)]
if errs:
msg = _("Cannot be imported because") + ":\r\n"
msg += ",".join(errs)
else:
errs = []
msg = "Memory can be imported into target"
self.__store.append(row=(not bool(msgs),
mem.number,
mem.number,
mem.name,
chirp_common.format_freq(mem.freq),
mem.comment,
not bool(errs),
msg
))
self.record_use_of(mem.number)
TITLE = _("Import From File")
ACTION = _("Import")
def __init__(self, src_radio, dst_radio, parent=None):
gtk.Dialog.__init__(self,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
title=self.TITLE,
parent=parent)
self.col_import = 0
self.col_nloc = 1
self.col_oloc = 2
self.col_name = 3
self.col_freq = 4
self.col_comm = 5
self.col_okay = 6
self.col_tmsg = 7
self.caps = {
self.col_import : self.ACTION,
self.col_nloc : _("To"),
self.col_oloc : _("From"),
self.col_name : _("Name"),
self.col_freq : _("Frequency"),
self.col_comm : _("Comment"),
}
self.tips = {
self.col_nloc : _("Location memory will be imported into"),
self.col_oloc : _("Location of memory in the file being imported"),
}
self.types = {
self.col_import : gobject.TYPE_BOOLEAN,
self.col_oloc : gobject.TYPE_INT,
self.col_nloc : gobject.TYPE_INT,
self.col_name : gobject.TYPE_STRING,
self.col_freq : gobject.TYPE_STRING,
self.col_comm : gobject.TYPE_STRING,
self.col_okay : gobject.TYPE_BOOLEAN,
self.col_tmsg : gobject.TYPE_STRING,
}
self.src_radio = src_radio
self.dst_radio = dst_radio
self.used_list = []
self.not_used_list = []
self.build_ui()
self.set_default_size(600, 400)
self.ww = WaitWindow(_("Preparing memory list..."), parent=parent)
self.ww.show()
self.ww.grind()
self.populate_list()
self.ww.hide()
class ExportDialog(ImportDialog):
TITLE = _("Export To File")
ACTION = _("Export")
if __name__ == "__main__":
from chirpui import editorset
import sys
f = sys.argv[1]
rc = editorset.radio_class_from_file(f)
radio = rc(f)
d = ImportDialog(radio)
d.run()
print d.get_import_list()
chirp-0.3.1/chirpui/mainapp.py 0000644 0000161 0177776 00000166340 12130403635 017466 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
# Copyright 2012 Tom Hayward
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import os
import tempfile
import urllib
from glob import glob
import shutil
import time
import gtk
import gobject
gobject.threads_init()
if __name__ == "__main__":
import sys
sys.path.insert(0, "..")
from chirpui import inputdialog, common
try:
import serial
except ImportError,e:
common.log_exception()
common.show_error("\nThe Pyserial module is not installed!")
from chirp import platform, generic_xml, generic_csv, directory, util
from chirp import ic9x, kenwood_live, idrp, vx7, vx5, vx6
from chirp import CHIRP_VERSION, chirp_common, detect, errors
from chirp import icf, ic9x_icf
from chirpui import editorset, clone, miscwidgets, config, reporting, fips
CONF = config.get()
KEEP_RECENT = 8
RB_BANDS = {
"--All--" : 0,
"10 meters (29MHz)" : 29,
"6 meters (54MHz)" : 5,
"2 meters (144MHz)" : 14,
"1.25 meters (220MHz)" : 22,
"70 centimeters (440MHz)" : 4,
"33 centimeters (900MHz)" : 9,
"23 centimeters (1.2GHz)" : 12,
}
def key_bands(band):
if band.startswith("-"):
return -1
amount, units, mhz = band.split(" ")
scale = units == "meters" and 100 or 1
return 100000 - (float(amount) * scale)
class ModifiedError(Exception):
pass
class ChirpMain(gtk.Window):
def get_current_editorset(self):
page = self.tabs.get_current_page()
if page is not None:
return self.tabs.get_nth_page(page)
else:
return None
def ev_tab_switched(self, pagenum=None):
def set_action_sensitive(action, sensitive):
self.menu_ag.get_action(action).set_sensitive(sensitive)
if pagenum is not None:
eset = self.tabs.get_nth_page(pagenum)
else:
eset = self.get_current_editorset()
upload_sens = bool(eset and
isinstance(eset.radio, chirp_common.CloneModeRadio))
if not eset or isinstance(eset.radio, chirp_common.LiveRadio):
save_sens = False
elif isinstance(eset.radio, chirp_common.NetworkSourceRadio):
save_sens = False
else:
save_sens = True
for i in ["import", "importsrc", "stock"]:
set_action_sensitive(i,
eset is not None and not eset.get_read_only())
for i in ["save", "saveas"]:
set_action_sensitive(i, save_sens)
for i in ["upload"]:
set_action_sensitive(i, upload_sens)
for i in ["cancelq"]:
set_action_sensitive(i, eset is not None and not save_sens)
for i in ["export", "close", "columns", "irbook", "irfinder",
"move_up", "move_dn", "exchange", "iradioreference",
"cut", "copy", "paste", "delete", "viewdeveloper"]:
set_action_sensitive(i, eset is not None)
def ev_status(self, editorset, msg):
self.sb_radio.pop(0)
self.sb_radio.push(0, msg)
def ev_usermsg(self, editorset, msg):
self.sb_general.pop(0)
self.sb_general.push(0, msg)
def ev_editor_selected(self, editorset, editortype):
mappings = {
"memedit" : ["view", "edit"],
}
for _editortype, actions in mappings.items():
for _action in actions:
action = self.menu_ag.get_action(_action)
action.set_sensitive(_editortype == editortype)
def _connect_editorset(self, eset):
eset.connect("want-close", self.do_close)
eset.connect("status", self.ev_status)
eset.connect("usermsg", self.ev_usermsg)
eset.connect("editor-selected", self.ev_editor_selected)
def do_diff_radio(self):
if self.tabs.get_n_pages() < 2:
common.show_error("Diff tabs requires at least two open tabs!")
return
esets = []
for i in range(0, self.tabs.get_n_pages()):
esets.append(self.tabs.get_nth_page(i))
d = gtk.Dialog(title="Diff Radios",
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
parent=self)
choices = []
for eset in esets:
choices.append("%s %s (%s)" % (eset.rthread.radio.VENDOR,
eset.rthread.radio.MODEL,
eset.filename))
choice_a = miscwidgets.make_choice(choices, False, choices[0])
choice_a.show()
chan_a = gtk.SpinButton()
chan_a.get_adjustment().set_all(1, -1, 999, 1, 10, 0)
chan_a.show()
hbox = gtk.HBox(False, 3)
hbox.pack_start(choice_a, 1, 1, 1)
hbox.pack_start(chan_a, 0, 0, 0)
hbox.show()
d.vbox.pack_start(hbox, 0, 0, 0)
choice_b = miscwidgets.make_choice(choices, False, choices[1])
choice_b.show()
chan_b = gtk.SpinButton()
chan_b.get_adjustment().set_all(1, -1, 999, 1, 10, 0)
chan_b.show()
hbox = gtk.HBox(False, 3)
hbox.pack_start(choice_b, 1, 1, 1)
hbox.pack_start(chan_b, 0, 0, 0)
hbox.show()
d.vbox.pack_start(hbox, 0, 0, 0)
r = d.run()
sel_a = choice_a.get_active_text()
sel_chan_a = chan_a.get_value()
sel_b = choice_b.get_active_text()
sel_chan_b = chan_b.get_value()
d.destroy()
if r == gtk.RESPONSE_CANCEL:
return
if sel_a == sel_b:
common.show_error("Can't diff the same tab!")
return
print "Selected %s@%i and %s@%i" % (sel_a, sel_chan_a,
sel_b, sel_chan_b)
eset_a = esets[choices.index(sel_a)]
eset_b = esets[choices.index(sel_b)]
def _show_diff(mem_b, mem_a):
# Step 3: Show the diff
diff = common.simple_diff(mem_a, mem_b)
common.show_diff_blob("Differences", diff)
def _get_mem_b(mem_a):
# Step 2: Get memory b
job = common.RadioJob(_show_diff, "get_raw_memory", int(sel_chan_b))
job.set_cb_args(mem_a)
eset_b.rthread.submit(job)
if sel_chan_a >= 0 and sel_chan_b >= 0:
# Diff numbered memory
# Step 1: Get memory a
job = common.RadioJob(_get_mem_b, "get_raw_memory", int(sel_chan_a))
eset_a.rthread.submit(job)
elif isinstance(eset_a.rthread.radio, chirp_common.CloneModeRadio) and\
isinstance(eset_b.rthread.radio, chirp_common.CloneModeRadio):
# Diff whole (can do this without a job, since both are clone-mode)
a = util.hexprint(eset_a.rthread.radio._mmap.get_packed())
b = util.hexprint(eset_b.rthread.radio._mmap.get_packed())
common.show_diff_blob("Differences", common.simple_diff(a, b))
else:
common.show_error("Cannot diff whole live-mode radios!")
def do_new(self):
eset = editorset.EditorSet(_("Untitled") + ".csv", self)
self._connect_editorset(eset)
eset.prime()
eset.show()
tab = self.tabs.append_page(eset, eset.get_tab_label())
self.tabs.set_current_page(tab)
def _do_manual_select(self, filename):
radiolist = {}
for drv, radio in directory.DRV_TO_RADIO.items():
if not issubclass(radio, chirp_common.CloneModeRadio):
continue
radiolist["%s %s" % (radio.VENDOR, radio.MODEL)] = drv
lab = gtk.Label("""Unable to detect model!
If you think that it is valid, you can select a radio model below to force an open attempt. If selecting the model manually works, please file a bug on the website and attach your image. If selecting the model does not work, it is likely that you are trying to open some other type of file.
""")
lab.set_justify(gtk.JUSTIFY_FILL)
lab.set_line_wrap(True)
lab.set_use_markup(True)
lab.show()
choice = miscwidgets.make_choice(sorted(radiolist.keys()), False,
sorted(radiolist.keys())[0])
d = gtk.Dialog(title="Detection Failed",
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
d.vbox.pack_start(lab, 0, 0, 0)
d.vbox.pack_start(choice, 0, 0, 0)
d.vbox.set_spacing(5)
choice.show()
d.set_default_size(400, 200)
#d.set_resizable(False)
r = d.run()
d.destroy()
if r != gtk.RESPONSE_OK:
return
try:
rc = directory.DRV_TO_RADIO[radiolist[choice.get_active_text()]]
return rc(filename)
except:
return
def do_open(self, fname=None, tempname=None):
if not fname:
types = [(_("CHIRP Radio Images") + " (*.img)", "*.img"),
(_("CHIRP Files") + " (*.chirp)", "*.chirp"),
(_("CSV Files") + " (*.csv)", "*.csv"),
(_("EVE Files (VX5)") + " (*.eve)", "*.eve"),
(_("ICF Files") + " (*.icf)", "*.icf"),
(_("VX5 Commander Files") + " (*.vx5)", "*.vx5"),
(_("VX6 Commander Files") + " (*.vx6)", "*.vx6"),
(_("VX7 Commander Files") + " (*.vx7)", "*.vx7"),
]
fname = platform.get_platform().gui_open_file(types=types)
if not fname:
return
self.record_recent_file(fname)
if icf.is_icf_file(fname):
a = common.ask_yesno_question(\
_("ICF files cannot be edited, only displayed or imported "
"into another file. Open in read-only mode?"),
self)
if not a:
return
read_only = True
else:
read_only = False
if icf.is_9x_icf(fname):
# We have to actually instantiate the IC9xICFRadio to get its
# sub-devices
radio = ic9x_icf.IC9xICFRadio(fname)
devices = radio.get_sub_devices()
del radio
else:
try:
radio = directory.get_radio_by_image(fname)
except errors.ImageDetectFailed:
radio = self._do_manual_select(fname)
if not radio:
return
print "Manually selected %s" % radio
except Exception, e:
common.log_exception()
common.show_error(os.path.basename(fname) + ": " + str(e))
return
if radio.get_features().has_sub_devices:
devices = radio.get_sub_devices()
else:
devices = [radio]
prio = len(devices)
first_tab = False
for device in devices:
try:
eset = editorset.EditorSet(device, self,
filename=fname,
tempname=tempname)
except Exception, e:
common.log_exception()
common.show_error(
_("There was an error opening {fname}: {error}").format(
fname=fname,
error=error))
return
eset.set_read_only(read_only)
self._connect_editorset(eset)
eset.show()
tab = self.tabs.append_page(eset, eset.get_tab_label())
if first_tab:
self.tabs.set_current_page(tab)
first_tab = False
if hasattr(eset.rthread.radio, "errors") and \
eset.rthread.radio.errors:
msg = _("{num} errors during open:").format(num=len(eset.rthread.radio.errors))
common.show_error_text(msg,
"\r\n".join(eset.rthread.radio.errors))
def do_live_warning(self, radio):
d = gtk.MessageDialog(parent=self, buttons=gtk.BUTTONS_OK)
d.set_markup("" + _("Note:") + "")
msg = _("The {vendor} {model} operates in live mode. "
"This means that any changes you make are immediately sent "
"to the radio. Because of this, you cannot perform the "
"Save or Upload operations. If you wish to "
"edit the contents offline, please Export to a CSV "
"file, using the File menu.").format(vendor=radio.VENDOR,
model=radio.MODEL)
d.format_secondary_markup(msg)
again = gtk.CheckButton(_("Don't show this again"))
again.show()
d.vbox.pack_start(again, 0, 0, 0)
d.run()
CONF.set_bool("live_mode", again.get_active(), "noconfirm")
d.destroy()
def do_open_live(self, radio, tempname=None, read_only=False):
if radio.get_features().has_sub_devices:
devices = radio.get_sub_devices()
else:
devices = [radio]
first_tab = True
for device in devices:
eset = editorset.EditorSet(device, self, tempname=tempname)
eset.connect("want-close", self.do_close)
eset.connect("status", self.ev_status)
eset.set_read_only(read_only)
eset.show()
tab = self.tabs.append_page(eset, eset.get_tab_label())
if first_tab:
self.tabs.set_current_page(tab)
first_tab = False
if isinstance(radio, chirp_common.LiveRadio):
reporting.report_model_usage(radio, "live", True)
if not CONF.get_bool("live_mode", "noconfirm"):
self.do_live_warning(radio)
def do_save(self, eset=None):
if not eset:
eset = self.get_current_editorset()
# For usability, allow Ctrl-S to short-circuit to Save-As if
# we are working on a yet-to-be-saved image
if not os.path.exists(eset.filename):
return self.do_saveas()
eset.save()
def do_saveas(self):
eset = self.get_current_editorset()
label = _("{vendor} {model} image file").format(\
vendor=eset.radio.VENDOR,
model=eset.radio.MODEL)
types = [(label + " (*.%s)" % eset.radio.FILE_EXTENSION,
eset.radio.FILE_EXTENSION)]
if isinstance(eset.radio, vx7.VX7Radio):
types += [(_("VX7 Commander") + " (*.vx7)", "vx7")]
elif isinstance(eset.radio, vx6.VX6Radio):
types += [(_("VX6 Commander") + " (*.vx6)", "vx6")]
elif isinstance(eset.radio, vx5.VX5Radio):
types += [(_("EVE") + " (*.eve)", "eve")]
types += [(_("VX5 Commander") + " (*.vx5)", "vx5")]
while True:
fname = platform.get_platform().gui_save_file(types=types)
if not fname:
return
if os.path.exists(fname):
dlg = inputdialog.OverwriteDialog(fname)
owrite = dlg.run()
dlg.destroy()
if owrite == gtk.RESPONSE_OK:
break
else:
break
try:
eset.save(fname)
except Exception,e:
d = inputdialog.ExceptionDialog(e)
d.run()
d.destroy()
def cb_clonein(self, radio, emsg=None):
radio.pipe.close()
reporting.report_model_usage(radio, "download", bool(emsg))
if not emsg:
self.do_open_live(radio, tempname="(" + _("Untitled") + ")")
else:
d = inputdialog.ExceptionDialog(emsg)
d.run()
d.destroy()
def cb_cloneout(self, radio, emsg= None):
radio.pipe.close()
reporting.report_model_usage(radio, "upload", True)
if emsg:
d = inputdialog.ExceptionDialog(emsg)
d.run()
d.destroy()
def _get_recent_list(self):
recent = []
for i in range(0, KEEP_RECENT):
fn = CONF.get("recent%i" % i, "state")
if fn:
recent.append(fn)
return recent
def _set_recent_list(self, recent):
for fn in recent:
CONF.set("recent%i" % recent.index(fn), fn, "state")
def update_recent_files(self):
i = 0
for fname in self._get_recent_list():
action_name = "recent%i" % i
path = "/MenuBar/file/recent"
old_action = self.menu_ag.get_action(action_name)
if old_action:
self.menu_ag.remove_action(old_action)
file_basename = os.path.basename(fname).replace("_", "__")
action = gtk.Action(action_name,
"_%i. %s" % (i+1, file_basename),
_("Open recent file {name}").format(name=fname),
"")
action.connect("activate", lambda a,f: self.do_open(f), fname)
mid = self.menu_uim.new_merge_id()
self.menu_uim.add_ui(mid, path,
action_name, action_name,
gtk.UI_MANAGER_MENUITEM, False)
self.menu_ag.add_action(action)
i += 1
def record_recent_file(self, filename):
recent_files = self._get_recent_list()
if filename not in recent_files:
if len(recent_files) == KEEP_RECENT:
del recent_files[-1]
recent_files.insert(0, filename)
self._set_recent_list(recent_files)
self.update_recent_files()
def import_stock_config(self, action, config):
eset = self.get_current_editorset()
count = eset.do_import(config)
def copy_shipped_stock_configs(self, stock_dir):
execpath = platform.get_platform().executable_path()
basepath = os.path.abspath(os.path.join(execpath, "stock_configs"))
if not os.path.exists(basepath):
basepath = "/usr/share/chirp/stock_configs"
files = glob(os.path.join(basepath, "*.csv"))
for fn in files:
if os.path.exists(os.path.join(stock_dir, os.path.basename(fn))):
print "Skipping existing stock config"
continue
try:
shutil.copy(fn, stock_dir)
print "Copying %s -> %s" % (fn, stock_dir)
except Exception, e:
print "ERROR: Unable to copy %s to %s: %s" % (fn, stock_dir, e)
return False
return True
def update_stock_configs(self):
stock_dir = platform.get_platform().config_file("stock_configs")
if not os.path.isdir(stock_dir):
try:
os.mkdir(stock_dir)
except Exception, e:
print "ERROR: Unable to create directory: %s" % stock_dir
return
if not self.copy_shipped_stock_configs(stock_dir):
return
def _do_import_action(config):
name = os.path.splitext(os.path.basename(config))[0]
action_name = "stock-%i" % configs.index(config)
path = "/MenuBar/radio/stock"
action = gtk.Action(action_name,
name,
_("Import stock "
"configuration {name}").format(name=name),
"")
action.connect("activate", self.import_stock_config, config)
mid = self.menu_uim.new_merge_id()
mid = self.menu_uim.add_ui(mid, path,
action_name, action_name,
gtk.UI_MANAGER_MENUITEM, False)
self.menu_ag.add_action(action)
def _do_open_action(config):
name = os.path.splitext(os.path.basename(config))[0]
action_name = "openstock-%i" % configs.index(config)
path = "/MenuBar/file/openstock"
action = gtk.Action(action_name,
name,
_("Open stock "
"configuration {name}").format(name=name),
"")
action.connect("activate", lambda a,c: self.do_open(c), config)
mid = self.menu_uim.new_merge_id()
mid = self.menu_uim.add_ui(mid, path,
action_name, action_name,
gtk.UI_MANAGER_MENUITEM, False)
self.menu_ag.add_action(action)
configs = glob(os.path.join(stock_dir, "*.csv"))
for config in configs:
_do_import_action(config)
_do_open_action(config)
def _confirm_experimental(self, rclass):
sql_key = "warn_experimental_%s" % directory.radio_class_id(rclass)
if CONF.is_defined(sql_key, "state") and \
not CONF.get_bool(sql_key, "state"):
return True
title = _("Proceed with experimental driver?")
text = rclass.get_experimental_warning()
msg = _("This radio's driver is experimental. "
"Do you want to proceed?")
resp, squelch = common.show_warning(msg, text,
title=title,
buttons=gtk.BUTTONS_YES_NO,
can_squelch=True)
if resp == gtk.RESPONSE_YES:
CONF.set_bool(sql_key, not squelch, "state")
return resp == gtk.RESPONSE_YES
def do_download(self, port=None, rtype=None):
d = clone.CloneSettingsDialog(parent=self)
settings = d.run()
d.destroy()
if not settings:
return
rclass = settings.radio_class
if issubclass(rclass, chirp_common.ExperimentalRadio) and \
not self._confirm_experimental(rclass):
# User does not want to proceed with experimental driver
return
print "User selected %s %s on port %s" % (rclass.VENDOR,
rclass.MODEL,
settings.port)
try:
ser = serial.Serial(port=settings.port,
baudrate=rclass.BAUD_RATE,
rtscts=rclass.HARDWARE_FLOW,
timeout=0.25)
ser.flushInput()
except serial.SerialException, e:
d = inputdialog.ExceptionDialog(e)
d.run()
d.destroy()
return
radio = settings.radio_class(ser)
fn = tempfile.mktemp()
if isinstance(radio, chirp_common.CloneModeRadio):
ct = clone.CloneThread(radio, "in", cb=self.cb_clonein, parent=self)
ct.start()
else:
self.do_open_live(radio)
def do_upload(self, port=None, rtype=None):
eset = self.get_current_editorset()
radio = eset.radio
settings = clone.CloneSettings()
settings.radio_class = radio.__class__
d = clone.CloneSettingsDialog(settings, parent=self)
settings = d.run()
d.destroy()
if not settings:
return
if isinstance(radio, chirp_common.ExperimentalRadio) and \
not self._confirm_experimental(radio.__class__):
# User does not want to proceed with experimental driver
return
try:
ser = serial.Serial(port=settings.port,
baudrate=radio.BAUD_RATE,
rtscts=radio.HARDWARE_FLOW,
timeout=0.25)
ser.flushInput()
except serial.SerialException, e:
d = inputdialog.ExceptionDialog(e)
d.run()
d.destroy()
return
radio.set_pipe(ser)
ct = clone.CloneThread(radio, "out", cb=self.cb_cloneout, parent=self)
ct.start()
def do_close(self, tab_child=None):
if tab_child:
eset = tab_child
else:
eset = self.get_current_editorset()
if not eset:
return False
if eset.is_modified():
dlg = miscwidgets.YesNoDialog(title=_("Save Changes?"),
parent=self,
buttons=(gtk.STOCK_YES, gtk.RESPONSE_YES,
gtk.STOCK_NO, gtk.RESPONSE_NO,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
dlg.set_text(_("File is modified, save changes before closing?"))
res = dlg.run()
dlg.destroy()
if res == gtk.RESPONSE_YES:
self.do_save(eset)
elif res == gtk.RESPONSE_CANCEL:
raise ModifiedError()
eset.rthread.stop()
eset.rthread.join()
eset.prepare_close()
if eset.radio.pipe:
eset.radio.pipe.close()
if isinstance(eset.radio, chirp_common.LiveRadio):
action = self.menu_ag.get_action("openlive")
if action:
action.set_sensitive(True)
page = self.tabs.page_num(eset)
if page is not None:
self.tabs.remove_page(page)
return True
def do_import(self):
types = [(_("CHIRP Files") + " (*.chirp)", "*.chirp"),
(_("CHIRP Radio Images") + " (*.img)", "*.img"),
(_("CSV Files") + " (*.csv)", "*.csv"),
(_("EVE Files (VX5)") + " (*.eve)", "*.eve"),
(_("ICF Files") + " (*.icf)", "*.icf"),
(_("Kenwood HMK Files") + " (*.hmk)", "*.hmk"),
(_("Travel Plus Files") + " (*.tpe)", "*.tpe"),
(_("VX5 Commander Files") + " (*.vx5)", "*.vx5"),
(_("VX6 Commander Files") + " (*.vx6)", "*.vx6"),
(_("VX7 Commander Files") + " (*.vx7)", "*.vx7")]
filen = platform.get_platform().gui_open_file(types=types)
if not filen:
return
eset = self.get_current_editorset()
count = eset.do_import(filen)
reporting.report_model_usage(eset.rthread.radio, "import", count > 0)
def do_repeaterbook_prompt(self):
if not CONF.get_bool("has_seen_credit", "repeaterbook"):
d = gtk.MessageDialog(parent=self, buttons=gtk.BUTTONS_OK)
d.set_markup("RepeaterBook\r\n" + \
"North American Repeater Directory")
d.format_secondary_markup("For more information about this " +\
"free service, please go to\r\n" +\
"http://www.repeaterbook.com")
d.run()
d.destroy()
CONF.set_bool("has_seen_credit", True, "repeaterbook")
default_state = "Oregon"
default_county = "--All--"
default_band = "--All--"
try:
try:
code = int(CONF.get("state", "repeaterbook"))
except:
code = CONF.get("state", "repeaterbook")
for k,v in fips.FIPS_STATES.items():
if code == v:
default_state = k
break
code = CONF.get("county", "repeaterbook")
for k,v in fips.FIPS_COUNTIES[fips.FIPS_STATES[default_state]].items():
if code == v:
default_county = k
break
code = int(CONF.get("band", "repeaterbook"))
for k,v in RB_BANDS.items():
if code == v:
default_band = k
break
except:
pass
state = miscwidgets.make_choice(sorted(fips.FIPS_STATES.keys()),
False, default_state)
county = miscwidgets.make_choice(sorted(fips.FIPS_COUNTIES[fips.FIPS_STATES[default_state]].keys()),
False, default_county)
band = miscwidgets.make_choice(sorted(RB_BANDS.keys(), key=key_bands),
False, default_band)
def _changed(box, county):
state = fips.FIPS_STATES[box.get_active_text()]
county.get_model().clear()
for fips_county in sorted(fips.FIPS_COUNTIES[state].keys()):
county.append_text(fips_county)
county.set_active(0)
state.connect("changed", _changed, county)
d = inputdialog.FieldDialog(title="RepeaterBook Query", parent=self)
d.add_field("State", state)
d.add_field("County", county)
d.add_field("Band", band)
r = d.run()
d.destroy()
if r != gtk.RESPONSE_OK:
return False
code = fips.FIPS_STATES[state.get_active_text()]
county_id = fips.FIPS_COUNTIES[code][county.get_active_text()]
freq = RB_BANDS[band.get_active_text()]
CONF.set("state", str(code), "repeaterbook")
CONF.set("county", str(county_id), "repeaterbook")
CONF.set("band", str(freq), "repeaterbook")
return True
def do_repeaterbook(self, do_import):
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
if not self.do_repeaterbook_prompt():
self.window.set_cursor(None)
return
try:
code = "%02i" % int(CONF.get("state", "repeaterbook"))
except:
try:
code = CONF.get("state", "repeaterbook")
except:
code = '41' # Oregon default
try:
county = CONF.get("county", "repeaterbook")
except:
county = '%' # --All-- default
try:
band = int(CONF.get("band", "repeaterbook"))
except:
band = 14 # 2m default
query = "http://www.repeaterbook.com/repeaters/downloads/chirp.php?" + \
"func=default&state_id=%s&band=%s&freq=%%&band6=%%&loc=%%" + \
"&county_id=%s&status_id=%%&features=%%&coverage=%%&use=%%"
query = query % (code, band and band or "%%", county and county or "%%")
# Do this in case the import process is going to take a while
# to make sure we process events leading up to this
gtk.gdk.window_process_all_updates()
while gtk.events_pending():
gtk.main_iteration(False)
fn = tempfile.mktemp(".csv")
filename, headers = urllib.urlretrieve(query, fn)
if not os.path.exists(filename):
print "Failed, headers were:"
print str(headers)
common.show_error("RepeaterBook query failed")
self.window.set_cursor(None)
return
class RBRadio(generic_csv.CSVRadio,
chirp_common.NetworkSourceRadio):
VENDOR = "RepeaterBook"
MODEL = ""
try:
# Validate CSV
radio = RBRadio(filename)
if radio.errors:
reporting.report_misc_error("repeaterbook",
("query=%s\n" % query) +
("\n") +
("\n".join(radio.errors)))
except errors.InvalidDataError, e:
common.show_error(str(e))
self.window.set_cursor(None)
return
except Exception, e:
common.log_exception()
reporting.report_model_usage(radio, "import", True)
self.window.set_cursor(None)
if do_import:
eset = self.get_current_editorset()
count = eset.do_import(filename)
else:
self.do_open_live(radio, read_only=True)
def do_rfinder_prompt(self):
fields = {"1Email" : (gtk.Entry(),
lambda x: "@" in x),
"2Password" : (gtk.Entry(),
lambda x: x),
"3Latitude" : (gtk.Entry(),
lambda x: float(x) < 90 and \
float(x) > -90),
"4Longitude": (gtk.Entry(),
lambda x: float(x) < 180 and \
float(x) > -180),
"5Range_in_Miles": (gtk.Entry(),
lambda x: int(x) > 0 and int(x) < 5000),
}
d = inputdialog.FieldDialog(title="RFinder Login", parent=self)
for k in sorted(fields.keys()):
d.add_field(k[1:].replace("_", " "), fields[k][0])
fields[k][0].set_text(CONF.get(k[1:], "rfinder") or "")
fields[k][0].set_visibility(k != "2Password")
while d.run() == gtk.RESPONSE_OK:
valid = True
for k in sorted(fields.keys()):
widget, validator = fields[k]
try:
if validator(widget.get_text()):
CONF.set(k[1:], widget.get_text(), "rfinder")
continue
except Exception:
pass
common.show_error("Invalid value for %s" % k[1:])
valid = False
break
if valid:
d.destroy()
return True
d.destroy()
return False
def do_rfinder(self, do_import):
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
if not self.do_rfinder_prompt():
self.window.set_cursor(None)
return
lat = CONF.get_float("Latitude", "rfinder")
lon = CONF.get_float("Longitude", "rfinder")
passwd = CONF.get("Password", "rfinder")
email = CONF.get("Email", "rfinder")
miles = CONF.get_int("Range_in_Miles", "rfinder")
# Do this in case the import process is going to take a while
# to make sure we process events leading up to this
gtk.gdk.window_process_all_updates()
while gtk.events_pending():
gtk.main_iteration(False)
if do_import:
eset = self.get_current_editorset()
count = eset.do_import("rfinder://%s/%s/%f/%f/%i" % (email, passwd, lat, lon, miles))
else:
from chirp import rfinder
radio = rfinder.RFinderRadio(None)
radio.set_params((lat, lon), miles, email, passwd)
self.do_open_live(radio, read_only=True)
self.window.set_cursor(None)
def do_radioreference_prompt(self):
fields = {"1Username" : (gtk.Entry(), lambda x: x),
"2Password" : (gtk.Entry(), lambda x: x),
"3Zipcode" : (gtk.Entry(), lambda x: x),
}
d = inputdialog.FieldDialog(title="RadioReference.com Query", parent=self)
for k in sorted(fields.keys()):
d.add_field(k[1:], fields[k][0])
fields[k][0].set_text(CONF.get(k[1:], "radioreference") or "")
fields[k][0].set_visibility(k != "2Password")
while d.run() == gtk.RESPONSE_OK:
valid = True
for k in sorted(fields.keys()):
widget, validator = fields[k]
try:
if validator(widget.get_text()):
CONF.set(k[1:], widget.get_text(), "radioreference")
continue
except Exception:
pass
common.show_error("Invalid value for %s" % k[1:])
valid = False
break
if valid:
d.destroy()
return True
d.destroy()
return False
def do_radioreference(self, do_import):
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
if not self.do_radioreference_prompt():
self.window.set_cursor(None)
return
username = CONF.get("Username", "radioreference")
passwd = CONF.get("Password", "radioreference")
zipcode = CONF.get("Zipcode", "radioreference")
# Do this in case the import process is going to take a while
# to make sure we process events leading up to this
gtk.gdk.window_process_all_updates()
while gtk.events_pending():
gtk.main_iteration(False)
if do_import:
eset = self.get_current_editorset()
count = eset.do_import("radioreference://%s/%s/%s" % (zipcode, username, passwd))
else:
try:
from chirp import radioreference
radio = radioreference.RadioReferenceRadio(None)
radio.set_params(zipcode, username, passwd)
self.do_open_live(radio, read_only=True)
except errors.RadioError, e:
common.show_error(e)
self.window.set_cursor(None)
def do_export(self):
types = [(_("CSV Files") + " (*.csv)", "csv"),
(_("CHIRP Files") + " (*.chirp)", "chirp"),
]
eset = self.get_current_editorset()
if os.path.exists(eset.filename):
base = os.path.basename(eset.filename)
if "." in base:
base = base[:base.rindex(".")]
defname = base
else:
defname = "radio"
filen = platform.get_platform().gui_save_file(default_name=defname,
types=types)
if not filen:
return
if os.path.exists(filen):
dlg = inputdialog.OverwriteDialog(filen)
owrite = dlg.run()
dlg.destroy()
if owrite != gtk.RESPONSE_OK:
return
os.remove(filen)
count = eset.do_export(filen)
reporting.report_model_usage(eset.rthread.radio, "export", count > 0)
def do_about(self):
d = gtk.AboutDialog()
d.set_transient_for(self)
import sys
verinfo = "GTK %s\nPyGTK %s\nPython %s\n" % ( \
".".join([str(x) for x in gtk.gtk_version]),
".".join([str(x) for x in gtk.pygtk_version]),
sys.version.split()[0])
d.set_name("CHIRP")
d.set_version(CHIRP_VERSION)
d.set_copyright("Copyright 2012 Dan Smith (KK7DS)")
d.set_website("http://chirp.danplanet.com")
d.set_authors(("Dan Smith ",
_("With significant contributions by:"),
"Marco IZ3GME",
"Rick WZ3RO",
"Tom KD7LXL",
"Vernon N7OH"
))
d.set_translator_credits("Polish: Grzegorz SQ2RBY" +
os.linesep +
"Italian: Fabio IZ2QDH" +
os.linesep +
"Dutch: Michael PD4MT" +
os.linesep +
"German: Benjamin HB9EUK")
d.set_comments(verinfo)
d.run()
d.destroy()
def do_columns(self):
eset = self.get_current_editorset()
driver = directory.get_driver(eset.rthread.radio.__class__)
radio_name = "%s %s %s" % (eset.rthread.radio.VENDOR,
eset.rthread.radio.MODEL,
eset.rthread.radio.VARIANT)
d = gtk.Dialog(title=_("Select Columns"),
parent=self,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
vbox = gtk.VBox()
vbox.show()
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
sw.add_with_viewport(vbox)
sw.show()
d.vbox.pack_start(sw, 1, 1, 1)
d.set_size_request(-1, 300)
d.set_resizable(False)
label = gtk.Label(_("Visible columns for {radio}").format(radio=radio_name))
label.show()
vbox.pack_start(label)
fields = []
memedit = eset.editors["memedit"]
unsupported = memedit.get_unsupported_columns()
for colspec in memedit.cols:
if colspec[0].startswith("_"):
continue
elif colspec[0] in unsupported:
continue
label = colspec[0]
visible = memedit.get_column_visible(memedit.col(label))
widget = gtk.CheckButton(label)
widget.set_active(visible)
fields.append(widget)
vbox.pack_start(widget, 1, 1, 1)
widget.show()
res = d.run()
selected_columns = []
if res == gtk.RESPONSE_OK:
for widget in fields:
colnum = memedit.col(widget.get_label())
memedit.set_column_visible(colnum, widget.get_active())
if widget.get_active():
selected_columns.append(widget.get_label())
d.destroy()
CONF.set(driver, ",".join(selected_columns), "memedit_columns")
def do_hide_unused(self, action):
eset = self.get_current_editorset()
if eset is None:
conf = config.get("memedit")
conf.set_bool("hide_unused", action.get_active())
else:
eset.editors["memedit"].set_hide_unused(action.get_active())
def do_clearq(self):
eset = self.get_current_editorset()
eset.rthread.flush()
def do_copy(self, cut):
eset = self.get_current_editorset()
eset.get_current_editor().copy_selection(cut)
def do_paste(self):
eset = self.get_current_editorset()
eset.get_current_editor().paste_selection()
def do_delete(self):
eset = self.get_current_editorset()
eset.get_current_editor().copy_selection(True)
def do_toggle_report(self, action):
if not action.get_active():
d = gtk.MessageDialog(buttons=gtk.BUTTONS_YES_NO,
parent=self)
d.set_markup("" + _("Reporting is disabled") + "")
msg = _("The reporting feature of CHIRP is designed to help "
"improve quality by allowing the authors to focus "
"on the radio drivers used most often and errors "
"experienced by the users. The reports contain no "
"identifying information and are used only for statistical "
"purposes by the authors. Your privacy is extremely "
"important, but please consider leaving this feature "
"enabled to help make CHIRP better!\n\nAre you "
"sure you want to disable this feature?")
d.format_secondary_markup(msg.replace("\n", "\r\n"))
r = d.run()
d.destroy()
if r == gtk.RESPONSE_NO:
action.set_active(not action.get_active())
conf = config.get()
conf.set_bool("no_report", not action.get_active())
def do_toggle_autorpt(self, action):
CONF.set_bool("autorpt", action.get_active(), "memedit")
def do_toggle_developer(self, action):
conf = config.get()
conf.set_bool("developer", action.get_active(), "state")
for name in ["viewdeveloper", "loadmod"]:
devaction = self.menu_ag.get_action(name)
devaction.set_visible(action.get_active())
def do_change_language(self):
langs = ["Auto", "English", "Polish", "Italian", "Dutch", "German",
"Hungarian"]
d = inputdialog.ChoiceDialog(langs, parent=self,
title="Choose Language")
d.label.set_text(_("Choose a language or Auto to use the "
"operating system default. You will need to "
"restart the application before the change "
"will take effect"))
d.label.set_line_wrap(True)
r = d.run()
if r == gtk.RESPONSE_OK:
print "Chose language %s" % d.choice.get_active_text()
conf = config.get()
conf.set("language", d.choice.get_active_text(), "state")
d.destroy()
def load_module(self):
types = [(_("Python Modules") + "*.py", "*.py")]
filen = platform.get_platform().gui_open_file(types=types)
if not filen:
return
# We're in development mode, so we need to tell the directory to
# allow a loaded module to override an existing driver, against
# its normal better judgement
directory.enable_reregistrations()
try:
module = file(filen)
code = module.read()
module.close()
pyc = compile(code, filen, 'exec')
# See this for why:
# http://stackoverflow.com/questions/2904274/globals-and-locals-in-python-exec
exec(pyc, globals(), globals())
except Exception, e:
common.log_exception()
common.show_error("Unable to load module: %s" % e)
def mh(self, _action, *args):
action = _action.get_name()
if action == "quit":
gtk.main_quit()
elif action == "new":
self.do_new()
elif action == "open":
self.do_open()
elif action == "save":
self.do_save()
elif action == "saveas":
self.do_saveas()
elif action.startswith("download"):
self.do_download(*args)
elif action.startswith("upload"):
self.do_upload(*args)
elif action == "close":
self.do_close()
elif action == "import":
self.do_import()
elif action in ["qrfinder", "irfinder"]:
self.do_rfinder(action[0] == "i")
elif action in ["qradioreference", "iradioreference"]:
self.do_radioreference(action[0] == "i")
elif action == "export":
self.do_export()
elif action in ["qrbook", "irbook"]:
self.do_repeaterbook(action[0] == "i")
elif action == "about":
self.do_about()
elif action == "columns":
self.do_columns()
elif action == "hide_unused":
self.do_hide_unused(_action)
elif action == "cancelq":
self.do_clearq()
elif action == "report":
self.do_toggle_report(_action)
elif action == "autorpt":
self.do_toggle_autorpt(_action)
elif action == "developer":
self.do_toggle_developer(_action)
elif action in ["cut", "copy", "paste", "delete",
"move_up", "move_dn", "exchange",
"devshowraw", "devdiffraw"]:
self.get_current_editorset().get_current_editor().hotkey(_action)
elif action == "devdifftab":
self.do_diff_radio()
elif action == "language":
self.do_change_language()
elif action == "loadmod":
self.load_module()
else:
return
self.ev_tab_switched()
def make_menubar(self):
menu_xml = """
"""
actions = [\
('file', None, _("_File"), None, None, self.mh),
('new', gtk.STOCK_NEW, None, None, None, self.mh),
('open', gtk.STOCK_OPEN, None, None, None, self.mh),
('openstock', None, _("Open stock config"), None, None, self.mh),
('recent', None, _("_Recent"), None, None, self.mh),
('save', gtk.STOCK_SAVE, None, None, None, self.mh),
('saveas', gtk.STOCK_SAVE_AS, None, None, None, self.mh),
('loadmod', None, _("Load Module"), None, None, self.mh),
('close', gtk.STOCK_CLOSE, None, None, None, self.mh),
('quit', gtk.STOCK_QUIT, None, None, None, self.mh),
('edit', None, _("_Edit"), None, None, self.mh),
('cut', None, _("_Cut"), "x", None, self.mh),
('copy', None, _("_Copy"), "c", None, self.mh),
('paste', None, _("_Paste"), "v", None, self.mh),
('delete', None, _("_Delete"), "Delete", None, self.mh),
('move_up', None, _("Move _Up"), "Up", None, self.mh),
('move_dn', None, _("Move Dow_n"), "Down", None, self.mh),
('exchange', None, _("E_xchange"), "x", None, self.mh),
('view', None, _("_View"), None, None, self.mh),
('columns', None, _("Columns"), None, None, self.mh),
('viewdeveloper', None, _("Developer"), None, None, self.mh),
('devshowraw', None, _('Show raw memory'), "r", None, self.mh),
('devdiffraw', None, _("Diff raw memories"), "d", None, self.mh),
('devdifftab', None, _("Diff tabs"), "t", None, self.mh),
('language', None, _("Change language"), None, None, self.mh),
('radio', None, _("_Radio"), None, None, self.mh),
('download', None, _("Download From Radio"), "d", None, self.mh),
('upload', None, _("Upload To Radio"), "u", None, self.mh),
('import', None, _("Import"), "i", None, self.mh),
('export', None, _("Export"), "x", None, self.mh),
('importsrc', None, _("Import from data source"), None, None, self.mh),
('iradioreference', None, _("RadioReference.com"), None, None, self.mh),
('irfinder', None, _("RFinder"), None, None, self.mh),
('irbook', None, _("RepeaterBook"), None, None, self.mh),
('querysrc', None, _("Query data source"), None, None, self.mh),
('qradioreference', None, _("RadioReference.com"), None, None, self.mh),
('qrfinder', None, _("RFinder"), None, None, self.mh),
('qrbook', None, _("RepeaterBook"), None, None, self.mh),
('export_chirp', None, _("CHIRP Native File"), None, None, self.mh),
('export_csv', None, _("CSV File"), None, None, self.mh),
('stock', None, _("Import from stock config"), None, None, self.mh),
('cancelq', gtk.STOCK_STOP, None, "Escape", None, self.mh),
('help', None, _('Help'), None, None, self.mh),
('about', gtk.STOCK_ABOUT, None, None, None, self.mh),
]
conf = config.get()
re = not conf.get_bool("no_report");
hu = conf.get_bool("hide_unused", "memedit")
ro = conf.get_bool("autorpt", "memedit")
dv = conf.get_bool("developer", "state")
toggles = [\
('report', None, _("Report statistics"), None, None, self.mh, re),
('hide_unused', None, _("Hide Unused Fields"), None, None, self.mh, hu),
('autorpt', None, _("Automatic Repeater Offset"), None, None, self.mh, ro),
('developer', None, _("Enable Developer Functions"), None, None, self.mh, dv),
]
self.menu_uim = gtk.UIManager()
self.menu_ag = gtk.ActionGroup("MenuBar")
self.menu_ag.add_actions(actions)
self.menu_ag.add_toggle_actions(toggles)
self.menu_uim.insert_action_group(self.menu_ag, 0)
self.menu_uim.add_ui_from_string(menu_xml)
self.add_accel_group(self.menu_uim.get_accel_group())
self.recentmenu = self.menu_uim.get_widget("/MenuBar/file/recent")
# Initialize
self.do_toggle_developer(self.menu_ag.get_action("developer"))
return self.menu_uim.get_widget("/MenuBar")
def make_tabs(self):
self.tabs = gtk.Notebook()
return self.tabs
def close_out(self):
num = self.tabs.get_n_pages()
while num > 0:
num -= 1
print "Closing %i" % num
try:
self.do_close(self.tabs.get_nth_page(num))
except ModifiedError:
return False
gtk.main_quit()
return True
def make_status_bar(self):
box = gtk.HBox(False, 2)
self.sb_general = gtk.Statusbar()
self.sb_general.set_has_resize_grip(False)
self.sb_general.show()
box.pack_start(self.sb_general, 1,1,1)
self.sb_radio = gtk.Statusbar()
self.sb_radio.set_has_resize_grip(True)
self.sb_radio.show()
box.pack_start(self.sb_radio, 1,1,1)
box.show()
return box
def ev_delete(self, window, event):
if not self.close_out():
return True # Don't exit
def ev_destroy(self, window):
if not self.close_out():
return True # Don't exit
def setup_extra_hotkeys(self):
accelg = self.menu_uim.get_accel_group()
memedit = lambda a: self.get_current_editorset().editors["memedit"].hotkey(a)
actions = [
# ("action_name", "key", function)
]
for name, key, fn in actions:
a = gtk.Action(name, name, name, "")
a.connect("activate", fn)
self.menu_ag.add_action_with_accel(a, key)
a.set_accel_group(accelg)
a.connect_accelerator()
def _set_icon(self):
execpath = platform.get_platform().executable_path()
path = os.path.abspath(os.path.join(execpath, "share", "chirp.png"))
if not os.path.exists(path):
path = "/usr/share/pixmaps/chirp.png"
if os.path.exists(path):
self.set_icon_from_file(path)
else:
print "Icon %s not found" % path
def _updates(self, version):
if not version:
return
if version == CHIRP_VERSION:
return
print "Server reports version %s is available" % version
# Report new updates every seven days
intv = 3600 * 24 * 7
if CONF.is_defined("last_update_check", "state") and \
(time.time() - CONF.get_int("last_update_check", "state")) < intv:
return
CONF.set_int("last_update_check", int(time.time()), "state")
d = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, parent=self,
type=gtk.MESSAGE_INFO)
d.set_property("text",
_("A new version of CHIRP is available: " +
"{ver}. ".format(ver=version) +
"It is recommended that you upgrade, so " +
"go to http://chirp.danplanet.com soon!"))
d.run()
d.destroy()
def _init_macos(self, menu_bar):
try:
import gtk_osxapplication
macapp = gtk_osxapplication.OSXApplication()
except ImportError, e:
print "No MacOS support: %s" % e
return
menu_bar.hide()
macapp.set_menu_bar(menu_bar)
quititem = self.menu_uim.get_widget("/MenuBar/file/quit")
quititem.hide()
aboutitem = self.menu_uim.get_widget("/MenuBar/help/about")
macapp.insert_app_menu_item(aboutitem, 0)
macapp.set_use_quartz_accelerators(False)
macapp.ready()
print "Initialized MacOS support"
def __init__(self, *args, **kwargs):
gtk.Window.__init__(self, *args, **kwargs)
d = CONF.get("last_dir", "state")
if d and os.path.isdir(d):
platform.get_platform().set_last_dir(d)
vbox = gtk.VBox(False, 2)
self._recent = []
self.menu_ag = None
mbar = self.make_menubar()
if os.name != "nt":
self._set_icon() # Windows gets the icon from the exe
if os.uname()[0] == "Darwin":
self._init_macos(mbar)
vbox.pack_start(mbar, 0, 0, 0)
self.tabs = None
tabs = self.make_tabs()
tabs.connect("switch-page", lambda n, _, p: self.ev_tab_switched(p))
tabs.connect("page-removed", lambda *a: self.ev_tab_switched())
tabs.show()
self.ev_tab_switched()
vbox.pack_start(tabs, 1, 1, 1)
vbox.pack_start(self.make_status_bar(), 0, 0, 0)
vbox.show()
self.add(vbox)
self.set_default_size(800, 600)
self.set_title("CHIRP")
self.connect("delete_event", self.ev_delete)
self.connect("destroy", self.ev_destroy)
if not CONF.get_bool("warned_about_reporting") and \
not CONF.get_bool("no_report"):
d = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, parent=self)
d.set_markup("" +
_("Error reporting is enabled") +
"")
d.format_secondary_markup(\
_("If you wish to disable this feature you may do so in "
"the Help menu"))
d.run()
d.destroy()
CONF.set_bool("warned_about_reporting", True)
if not CONF.is_defined("autorpt", "memedit"):
print "autorpt not set et"
CONF.set_bool("autorpt", True, "memedit")
self.update_recent_files()
self.update_stock_configs()
self.setup_extra_hotkeys()
def updates_callback(ver):
gobject.idle_add(self._updates, ver)
if not CONF.get_bool("skip_update_check", "state"):
reporting.check_for_updates(updates_callback)
chirp-0.3.1/chirpui/reporting.py 0000644 0000161 0177776 00000013146 12130403635 020045 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2011 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# README:
#
# I know that collecting data is not very popular. I don't like it
# either. However, it's hard to tell what drivers people are using
# and I think it would be helpful if I had that information. This is
# completely optional, so you can turn it off if you want. It doesn't
# report anything other than version and model usage information. The
# code below is very conservative, and will disable itself if reporting
# fails even once or takes too long to perform. It's run in a thread
# so that the user shouldn't even notice it's happening.
#
import threading
import os
import time
from chirp import CHIRP_VERSION, platform
REPORT_URL = "http://chirp.danplanet.com/report/report.php?do_report"
ENABLED = True
DEBUG = os.getenv("CHIRP_DEBUG") == "y"
THREAD_SEM = threading.Semaphore(10) # Maximum number of outstanding threads
LAST = 0
LAST_TYPE = None
try:
# Don't let failure to import any of these modules cause trouble
from chirpui import config
import xmlrpclib
except:
ENABLED = False
def debug(string):
if DEBUG:
print string
def should_report():
if not ENABLED:
debug("Not reporting due to recent failure")
return False
conf = config.get()
if conf.get_bool("no_report"):
debug("Reporting disabled")
return False
return True
def _report_model_usage(model, direction, success):
global ENABLED
if direction not in ["live", "download", "upload", "import", "export", "importsrc"]:
print "Invalid direction `%s'" % direction
return True # This is a bug, but not fatal
model = "%s_%s" % (model.VENDOR, model.MODEL)
data = "%s,%s,%s" % (model, direction, success)
debug("Reporting model usage: %s" % data)
proxy = xmlrpclib.ServerProxy(REPORT_URL)
id = proxy.report_stats(CHIRP_VERSION,
platform.get_platform().os_version_string(),
"model_use",
data)
# If the server returns zero, it wants us to shut up
return id != 0
def _report_exception(stack):
global ENABLED
debug("Reporting exception")
proxy = xmlrpclib.ServerProxy(REPORT_URL)
id = proxy.report_exception(CHIRP_VERSION,
platform.get_platform().os_version_string(),
"exception",
stack)
# If the server returns zero, it wants us to shut up
return id != 0
def _report_misc_error(module, data):
global ENABLED
debug("Reporting misc error with %s" % module)
proxy = xmlrpclib.ServerProxy(REPORT_URL)
id = proxy.report_misc_error(CHIRP_VERSION,
platform.get_platform().os_version_string(),
module, data)
# If the server returns zero, it wants us to shut up
return id != 0
def _check_for_updates(callback):
debug("Checking for updates")
proxy = xmlrpclib.ServerProxy(REPORT_URL)
ver = proxy.check_for_updates(CHIRP_VERSION,
platform.get_platform().os_version_string())
debug("Server reports version %s is latest" % ver)
callback(ver)
return True
class ReportThread(threading.Thread):
def __init__(self, func, *args):
threading.Thread.__init__(self)
self.__func = func
self.__args = args
def _run(self):
try:
return self.__func(*self.__args)
except Exception, e:
debug("Failed to report: %s" % e)
return False
def run(self):
start = time.time()
result = self._run()
if not result:
# Reporting failed
ENABLED = False
elif (time.time() - start) > 15:
# Reporting took too long
debug("Time to report was %.2f sec -- Disabling" % \
(time.time()-start))
ENABLED = False
THREAD_SEM.release()
def dispatch_thread(func, *args):
global LAST
global LAST_TYPE
# If reporting is disabled or failing, bail
if not should_report():
debug("Reporting is disabled")
return
# If the time between now and the last report is less than 5 seconds, bail
delta = time.time() - LAST
if delta < 5 and func == LAST_TYPE:
debug("Throttling...")
return
LAST = time.time()
LAST_TYPE = func
# If there are already too many threads running, bail
if not THREAD_SEM.acquire(False):
debug("Too many threads already running")
return
t = ReportThread(func, *args)
t.start()
def report_model_usage(model, direction, success):
dispatch_thread(_report_model_usage, model, direction, success)
def report_exception(stack):
dispatch_thread(_report_exception, stack)
def report_misc_error(module, data):
dispatch_thread(_report_misc_error, module, data)
# Calls callback with the latest version
def check_for_updates(callback):
dispatch_thread(_check_for_updates, callback)
chirp-0.3.1/chirpui/bankedit.py 0000644 0000161 0177776 00000033225 12130403635 017615 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
import time
from gobject import TYPE_INT, TYPE_STRING, TYPE_BOOLEAN
from chirp import chirp_common
from chirpui import common, miscwidgets
class BankNamesJob(common.RadioJob):
def __init__(self, bm, editor, cb):
common.RadioJob.__init__(self, cb, None)
self.__bm = bm
self.__editor = editor
def execute(self, radio):
self.__editor.banks = []
banks = self.__bm.get_banks()
for bank in banks:
self.__editor.banks.append((bank, bank.get_name()))
gobject.idle_add(self.cb, *self.cb_args)
class BankNameEditor(common.Editor):
def refresh(self):
def got_banks():
self._keys = []
for bank, name in self.banks:
self._keys.append(bank.get_index())
self.listw.set_item(bank.get_index(),
bank.get_index(),
name)
self.listw.connect("item-set", self.bank_changed)
job = BankNamesJob(self._bm, self, got_banks)
job.set_desc(_("Retrieving bank information"))
self.rthread.submit(job)
def get_bank_list(self):
banks = []
keys = self.listw.get_keys()
for key in keys:
banks.append(self.listw.get_item(key)[2])
return banks
def bank_changed(self, listw, key):
def cb(*args):
self.emit("changed")
name = self.listw.get_item(key)[2]
bank, oldname = self.banks[self._keys.index(key)]
def trigger_changed(*args):
self.emit("changed")
job = common.RadioJob(trigger_changed, "set_name", name)
job.set_target(bank)
job.set_desc(_("Setting name on bank"))
self.rthread.submit(job)
return True
def __init__(self, rthread):
common.Editor.__init__(self)
self.rthread = rthread
self._bm = rthread.radio.get_bank_model()
types = [(gobject.TYPE_STRING, "key"),
(gobject.TYPE_STRING, _("Bank")),
(gobject.TYPE_STRING, _("Name"))]
self.listw = miscwidgets.KeyedListWidget(types)
self.listw.set_editable(1, True)
self.listw.set_sort_column(0, 1)
self.listw.set_sort_column(1, -1)
self.listw.show()
self.banks = []
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add_with_viewport(self.listw)
self.root = sw
self._loaded = False
def focus(self):
if self._loaded:
return
self.refresh()
self._loaded = True
class MemoryBanksJob(common.RadioJob):
def __init__(self, bm, cb, number):
common.RadioJob.__init__(self, cb, None)
self.__bm = bm
self.__number = number
def execute(self, radio):
mem = radio.get_memory(self.__number)
if mem.empty:
banks = []
indexes = []
else:
banks = self.__bm.get_memory_banks(mem)
indexes = []
if isinstance(self.__bm, chirp_common.BankIndexInterface):
for bank in banks:
indexes.append(self.__bm.get_memory_index(mem, bank))
self.cb(mem, banks, indexes, *self.cb_args)
class BankMembershipEditor(common.Editor):
def _number_to_path(self, number):
return (number - self._rf.memory_bounds[0],)
def _get_next_bank_index(self, bank):
# NB: Only works for one-to-one bank models right now!
iter = self._store.get_iter_first()
indexes = []
ncols = len(self._cols) + len(self.banks)
while iter:
vals = self._store.get(iter, *tuple([n for n in range(0, ncols)]))
loc = vals[self.C_LOC]
index = vals[self.C_INDEX]
banks = vals[self.C_BANKS:]
if True in banks and banks.index(True) == bank:
indexes.append(index)
iter = self._store.iter_next(iter)
index_bounds = self._bm.get_index_bounds()
num_indexes = index_bounds[1] - index_bounds[0]
indexes.sort()
for i in range(0, num_indexes):
if i not in indexes:
return i + index_bounds[0] # In case not zero-origin index
return 0 # If the bank is full, just wrap around!
def _toggled_cb(self, rend, path, colnum):
try:
if not rend.get_sensitive():
return
except AttributeError:
# support PyGTK < 2.22
iter = self._store.get_iter(path)
if not self._store.get(iter, self.C_FILLED)[0]:
return
# The bank index is the column number, minus the 3 label columns
bank, name = self.banks[colnum - len(self._cols)]
loc, = self._store.get(self._store.get_iter(path), self.C_LOC)
if rend.get_active():
# Changing from True to False
fn = "remove_memory_from_bank"
index = None
else:
# Changing from False to True
fn = "add_memory_to_bank"
if self._rf.has_bank_index:
index = self._get_next_bank_index(colnum - len(self._cols))
else:
index = None
def do_refresh_memory(*args):
# Step 2: Update our notion of the memory's bank information
self.refresh_memory(loc)
def do_bank_index(result, memory):
if isinstance(result, Exception):
common.show_error("Failed to add {mem} to bank: {err}"
.format(mem=memory.number,
err=str(result)),
parent=self.editorset.parent_window)
return
self.emit("changed")
# Step 3: Set the memory's bank index (maybe)
if not self._rf.has_bank_index or index is None:
return do_refresh_memory()
job = common.RadioJob(do_refresh_memory,
"set_memory_index", memory, bank, index)
job.set_target(self._bm)
job.set_desc(_("Updating bank index "
"for memory {num}").format(num=memory.number))
self.rthread.submit(job)
def do_bank_adjustment(memory):
# Step 1: Do the bank add/remove
job = common.RadioJob(do_bank_index, fn, memory, bank)
job.set_target(self._bm)
job.set_cb_args(memory)
job.set_desc(_("Updating bank information "
"for memory {num}").format(num=memory.number))
self.rthread.submit(job)
# Step 0: Fetch the memory
job = common.RadioJob(do_bank_adjustment, "get_memory", loc)
job.set_desc(_("Getting memory {num}").format(num=loc))
self.rthread.submit(job)
def _index_edited_cb(self, rend, path, new):
loc, = self._store.get(self._store.get_iter(path), self.C_LOC)
def refresh_memory(*args):
self.refresh_memory(loc)
def set_index(banks, memory):
self.emit("changed")
# Step 2: Set the index
job = common.RadioJob(refresh_memory, "set_memory_index",
memory, banks[0], int(new))
job.set_target(self._bm)
job.set_desc(_("Setting index "
"for memory {num}").format(num=memory.number))
self.rthread.submit(job)
def get_bank(memory):
# Step 1: Get the first/only bank
job = common.RadioJob(set_index, "get_memory_banks", memory)
job.set_cb_args(memory)
job.set_target(self._bm)
job.set_desc(_("Getting bank for "
"memory {num}").format(num=memory.number))
self.rthread.submit(job)
# Step 0: Get the memory
job = common.RadioJob(get_bank, "get_memory", loc)
job.set_desc(_("Getting memory {num}").format(num=loc))
self.rthread.submit(job)
def __init__(self, rthread, editorset):
common.Editor.__init__(self)
self.rthread = rthread
self.editorset = editorset
self._rf = rthread.radio.get_features()
self._bm = rthread.radio.get_bank_model()
self._view_cols = [
(_("Loc"), TYPE_INT, gtk.CellRendererText, ),
(_("Frequency"), TYPE_STRING, gtk.CellRendererText, ),
(_("Name"), TYPE_STRING, gtk.CellRendererText, ),
(_("Index"), TYPE_INT, gtk.CellRendererText, ),
]
self._cols = [
("_filled", TYPE_BOOLEAN, None, ),
] + self._view_cols
self.C_FILLED = 0
self.C_LOC = 1
self.C_FREQ = 2
self.C_NAME = 3
self.C_INDEX = 4
self.C_BANKS = 5 # and beyond
cols = list(self._cols)
self._index_cache = []
for i in range(0, self._bm.get_num_banks()):
label = "Bank %i" % (i+1)
cols.append((label, TYPE_BOOLEAN, gtk.CellRendererToggle))
self._store = gtk.ListStore(*tuple([y for x,y,z in cols]))
self._view = gtk.TreeView(self._store)
colnum = 0
for label, dtype, rtype in cols:
if not rtype:
colnum += 1
continue
rend = rtype()
if dtype == TYPE_BOOLEAN:
rend.set_property("activatable", True)
rend.connect("toggled", self._toggled_cb, colnum)
col = gtk.TreeViewColumn(label, rend, active=colnum,
sensitive=self.C_FILLED)
else:
col = gtk.TreeViewColumn(label, rend, text=colnum,
sensitive=self.C_FILLED)
self._view.append_column(col)
col.set_resizable(True)
if colnum == self.C_NAME:
col.set_visible(self._rf.has_name)
elif colnum == self.C_INDEX:
rend.set_property("editable", True)
rend.connect("edited", self._index_edited_cb)
col.set_visible(self._rf.has_bank_index)
colnum += 1
# A non-rendered column to absorb extra space in the row
self._view.append_column(gtk.TreeViewColumn())
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add(self._view)
self._view.show()
for i in range(*self._rf.memory_bounds):
iter = self._store.append()
self._store.set(iter,
self.C_FILLED, False,
self.C_LOC, i,
self.C_FREQ, 0,
self.C_NAME, "",
self.C_INDEX, 0)
self.root = sw
self._loaded = False
def refresh_memory(self, number):
def got_mem(memory, banks, indexes):
iter = self._store.get_iter(self._number_to_path(memory.number))
row = [self.C_FILLED, not memory.empty,
self.C_LOC, memory.number,
self.C_FREQ, chirp_common.format_freq(memory.freq),
self.C_NAME, memory.name,
# Hack for only one index right now
self.C_INDEX, indexes and indexes[0] or 0,
]
for i in range(0, len(self.banks)):
row.append(i + len(self._cols))
row.append(self.banks[i][0] in banks)
self._store.set(iter, *tuple(row))
if memory.number == self._rf.memory_bounds[1] - 1:
print "Got all bank info in %s" % (time.time() - self._start)
job = MemoryBanksJob(self._bm, got_mem, number)
job.set_desc(_("Getting bank information "
"for memory {num}").format(num=number))
self.rthread.submit(job)
def refresh_all_memories(self):
for i in range(*self._rf.memory_bounds):
self.refresh_memory(i)
def refresh_banks(self, and_memories=False):
def got_banks():
for i in range(len(self._cols) - len(self._view_cols) - 1,
len(self.banks)):
col = self._view.get_column(i + len(self._view_cols))
bank, name = self.banks[i]
if name:
col.set_title(name)
else:
col.set_title("(%s)" % i)
if and_memories:
self.refresh_all_memories()
job = BankNamesJob(self._bm, self, got_banks)
job.set_desc(_("Getting bank information"))
self.rthread.submit(job)
def focus(self):
common.Editor.focus(self)
if self._loaded:
return
self._start = time.time()
self.refresh_banks(True)
self._loaded = True
def memories_changed(self):
self._loaded = False
if self.is_focused():
self.refresh_all_memories()
def banks_changed(self):
self.refresh_banks()
chirp-0.3.1/chirpui/clone.py 0000644 0000161 0177776 00000020014 12107114672 017130 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import threading
import os
import gtk
import gobject
from chirp import platform, directory, detect, chirp_common
from chirpui import miscwidgets, cloneprog, inputdialog, common, config
AUTO_DETECT_STRING = "Auto Detect (Icom Only)"
class CloneSettings:
def __init__(self):
self.port = None
self.radio_class = None
def __str__(self):
s = ""
if self.radio_class:
return _("{vendor} {model} on {port}").format(\
vendor=self.radio_class.VENDOR,
model=self.radio_class.MODEL,
port=self.port)
class CloneSettingsDialog(gtk.Dialog):
def __make_field(self, label, widget):
l = gtk.Label(label)
self.__table.attach(l, 0, 1, self.__row, self.__row+1)
self.__table.attach(widget, 1, 2, self.__row, self.__row+1)
self.__row += 1
l.show()
widget.show()
def __make_port(self, port):
conf = config.get("state")
ports = platform.get_platform().list_serial_ports()
if not port:
if conf.get("last_port"):
port = conf.get("last_port")
elif ports:
port = ports[0]
if not port in ports:
ports.insert(0, port)
return miscwidgets.make_choice(ports, True, port)
def __make_model(self):
return miscwidgets.make_choice([], False)
def __make_vendor(self, model):
vendors = {}
for rclass in sorted(directory.DRV_TO_RADIO.values()):
if not issubclass(rclass, chirp_common.CloneModeRadio) and \
not issubclass(rclass, chirp_common.LiveRadio):
continue
if not vendors.has_key(rclass.VENDOR):
vendors[rclass.VENDOR] = []
vendors[rclass.VENDOR].append(rclass)
self.__vendors = vendors
conf = config.get("state")
if not conf.get("last_vendor"):
conf.set("last_vendor", sorted(vendors.keys())[0])
last_vendor = conf.get("last_vendor")
if last_vendor not in vendors.keys():
last_vendor = vendors.keys()[0]
v = miscwidgets.make_choice(sorted(vendors.keys()), False, last_vendor)
def _changed(box, vendors, model):
models = vendors[box.get_active_text()]
added_models = []
model.get_model().clear()
for rclass in sorted(models, key=lambda c: c.__name__):
if rclass.MODEL not in added_models:
model.append_text(rclass.MODEL)
added_models.append(rclass.MODEL)
if box.get_active_text() in detect.DETECT_FUNCTIONS:
model.insert_text(0, _("Detect"))
added_models.insert(0, _("Detect"))
model_names = [x.MODEL for x in models]
if conf.get("last_model") in model_names:
model.set_active(added_models.index(conf.get("last_model")))
else:
model.set_active(0)
v.connect("changed", _changed, vendors, model)
_changed(v, vendors, model)
return v
def __make_ui(self, settings):
self.__table = gtk.Table(3, 2)
self.__table.set_row_spacings(3)
self.__table.set_col_spacings(10)
self.__row = 0
self.__port = self.__make_port(settings and settings.port or None)
self.__modl = self.__make_model()
self.__vend = self.__make_vendor(self.__modl)
self.__make_field(_("Port"), self.__port)
self.__make_field(_("Vendor"), self.__vend)
self.__make_field(_("Model"), self.__modl)
if settings and settings.radio_class:
common.combo_select(self.__vend, settings.radio_class.VENDOR)
self.__modl.get_model().clear()
self.__modl.append_text(settings.radio_class.MODEL)
common.combo_select(self.__modl, settings.radio_class.MODEL)
self.__vend.set_sensitive(False)
self.__modl.set_sensitive(False)
self.__table.show()
self.vbox.pack_start(self.__table, 1, 1, 1)
def __init__(self, settings=None, parent=None, title=_("Radio")):
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK)
gtk.Dialog.__init__(self, title,
parent=parent,
flags=gtk.DIALOG_MODAL)
self.__make_ui(settings)
self.__cancel_button = self.add_button(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL)
self.__okay_button = self.add_button(gtk.STOCK_OK,
gtk.RESPONSE_OK)
self.__okay_button.grab_default()
self.__okay_button.grab_focus()
def run(self):
r = gtk.Dialog.run(self)
if r != gtk.RESPONSE_OK:
return None
vendor = self.__vend.get_active_text()
model = self.__modl.get_active_text()
cs = CloneSettings()
cs.port = self.__port.get_active_text()
if model == _("Detect"):
try:
cs.radio_class = detect.DETECT_FUNCTIONS[vendor](cs.port)
if not cs.radio_class:
raise Exception(_("Unable to detect radio on {port}").format(port=cs.port))
except Exception, e:
d = inputdialog.ExceptionDialog(e)
d.run()
d.destroy()
return None
else:
for rclass in directory.DRV_TO_RADIO.values():
if rclass.MODEL == model:
cs.radio_class = rclass
break
if not cs.radio_class:
common.show_error(_("Internal error: Unable to upload to {model}").format(model=model))
print self.__vendors
return None
conf = config.get("state")
conf.set("last_port", cs.port)
conf.set("last_vendor", cs.radio_class.VENDOR)
conf.set("last_model", model)
return cs
class CloneCancelledException(Exception):
pass
class CloneThread(threading.Thread):
def __status(self, status):
gobject.idle_add(self.__progw.status, status)
def __init__(self, radio, direction, cb=None, parent=None):
threading.Thread.__init__(self)
self.__radio = radio
self.__out = direction == "out"
self.__cback = cb
self.__cancelled = False
self.__progw = cloneprog.CloneProg(parent=parent, cancel=self.cancel)
def cancel(self):
self.__radio.pipe.close()
self.__cancelled = True
def run(self):
print "Clone thread started"
gobject.idle_add(self.__progw.show)
self.__radio.status_fn = self.__status
try:
if self.__out:
self.__radio.sync_out()
else:
self.__radio.sync_in()
emsg = None
except Exception, e:
common.log_exception()
print _("Clone failed: {error}").format(error=e)
emsg = e
gobject.idle_add(self.__progw.hide)
# NB: Compulsory close of the radio's serial connection
self.__radio.pipe.close()
print "Clone thread ended"
if self.__cback and not self.__cancelled:
gobject.idle_add(self.__cback, self.__radio, emsg)
if __name__ == "__main__":
d = CloneSettingsDialog("/dev/ttyUSB0")
r = d.run()
print r
chirp-0.3.1/chirpui/settingsedit.py 0000644 0000161 0177776 00000017401 12130403635 020540 0 ustar jenkins nogroup 0000000 0000000 # Copyright 2012 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
import gobject
from chirp import chirp_common, settings
from chirpui import common, miscwidgets
class RadioSettingProxy(settings.RadioSetting):
def __init__(self, setting, editor):
self._setting = setting
self._editor = editor
class SettingsEditor(common.Editor):
def __init__(self, rthread):
common.Editor.__init__(self)
self._rthread = rthread
self.root = gtk.HBox(False, 10)
self._store = gtk.TreeStore(gobject.TYPE_STRING,
gobject.TYPE_PYOBJECT)
self._view = gtk.TreeView(self._store)
self._view.set_size_request(150, -1)
self._view.connect("button-press-event", self._group_selected)
self._view.show()
self.root.pack_start(self._view, 0, 0, 0)
col = gtk.TreeViewColumn("", gtk.CellRendererText(), text=0)
self._view.append_column(col)
self._table = gtk.Table(20, 3)
self._table.set_col_spacings(10)
self._table.show()
sw = gtk.ScrolledWindow()
sw.add_with_viewport(self._table)
sw.show()
self.root.pack_start(sw, 1, 1, 1)
self._index = 0
self._top_setting_group = None
job = common.RadioJob(self._build_ui, "get_settings")
job.set_desc("Getting radio settings")
self._rthread.submit(job)
def _save_settings(self):
if self._top_setting_group is None:
return
job = common.RadioJob(None, "set_settings", self._top_setting_group)
job.set_desc("Setting radio settings")
self._rthread.submit(job)
def _load_setting(self, value, widget):
if isinstance(value, settings.RadioSettingValueInteger):
adj = widget.get_adjustment()
adj.configure(value.get_value(),
value.get_min(), value.get_max(),
value.get_step(), 1, 0)
elif isinstance(value, settings.RadioSettingValueBoolean):
widget.set_active(value.get_value())
elif isinstance(value, settings.RadioSettingValueList):
model = widget.get_model()
model.clear()
for option in value.get_options():
widget.append_text(option)
current = value.get_value()
index = value.get_options().index(current)
widget.set_active(index)
elif isinstance(value, settings.RadioSettingValueString):
widget.set_text(str(value).rstrip())
else:
print "Unsupported widget type %s for %s" % (value.__class__,
element.get_name())
def _save_setting(self, widget, value):
if isinstance(value, settings.RadioSettingValueInteger):
value.set_value(widget.get_adjustment().get_value())
elif isinstance(value, settings.RadioSettingValueBoolean):
value.set_value(widget.get_active())
elif isinstance(value, settings.RadioSettingValueList):
value.set_value(widget.get_active_text())
elif isinstance(value, settings.RadioSettingValueString):
value.set_value(widget.get_text())
else:
print "Unsupported widget type %s for %s" % (\
element.value.__class__,
element.get_name())
self._save_settings()
def _build_ui_group(self, group):
def pack(widget, pos):
self._table.attach(widget, pos, pos+1, self._index, self._index+1,
xoptions=gtk.FILL, yoptions=0)
def abandon(child):
self._table.remove(child)
self._table.foreach(abandon)
self._index = 0
for element in group:
if not isinstance(element, settings.RadioSetting):
continue
label = gtk.Label(element.get_shortname())
label.set_alignment(1.0, 0.5)
label.show()
pack(label, 0)
if isinstance(element.value, list) and \
isinstance(element.value[0],
settings.RadioSettingValueInteger):
arraybox = gtk.HBox(3, True)
else:
arraybox = gtk.VBox(3, True)
pack(arraybox, 1)
arraybox.show()
widgets = []
for index in element.keys():
value = element[index]
if isinstance(value, settings.RadioSettingValueInteger):
widget = gtk.SpinButton()
print "Digits: %i" % widget.get_digits()
signal = "value-changed"
elif isinstance(value, settings.RadioSettingValueBoolean):
widget = gtk.CheckButton(_("Enabled"))
signal = "toggled"
elif isinstance(value, settings.RadioSettingValueList):
widget = miscwidgets.make_choice([], editable=False)
signal = "changed"
elif isinstance(value, settings.RadioSettingValueString):
widget = gtk.Entry()
signal = "changed"
else:
print "Unsupported widget type: %s" % value.__class__
# Make sure the widget gets left-aligned to match up
# with its label
lalign = gtk.Alignment(0, 0, 0, 0)
lalign.add(widget)
lalign.show()
arraybox.pack_start(lalign, 1, 1, 1)
widget.show()
self._load_setting(value, widget)
widget.connect(signal, self._save_setting, value)
self._index += 1
def _build_tree(self, group, parent):
iter = self._store.append(parent)
self._store.set(iter, 0, group.get_shortname(), 1, group)
if self._set_default is None:
# If we haven't found the first page with actual settings on it
# yet, then look for one here
for element in group:
if isinstance(element, settings.RadioSetting):
self._set_default = self._store.get_path(iter), group
break
for element in group:
if not isinstance(element, settings.RadioSetting):
self._build_tree(element, iter)
self._view.expand_all()
def _build_ui_real(self, group):
if not isinstance(group, settings.RadioSettingGroup):
print "Toplevel is not a group"
return
self._set_default = None
self._top_setting_group = group
self._build_tree(group, None)
self._view.set_cursor(self._set_default[0])
self._build_ui_group(self._set_default[1])
def _build_ui(self, group):
gobject.idle_add(self._build_ui_real, group)
def _group_selected(self, view, event):
if event.button != 1:
return
try:
path, col, x, y = view.get_path_at_pos(int(event.x), int(event.y))
except TypeError:
return # Didn't click on an actual item
group, = self._store.get(self._store.get_iter(path), 1)
if group:
self._build_ui_group(group)
chirp-0.3.1/chirpui/cloneprog.py 0000644 0000161 0000750 00000004071 11717005656 016373 0 ustar jenkins 0000000 0000000 # Copyright 2008 Dan Smith
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gtk
class CloneProg(gtk.Window):
def __init__(self, **args):
if args.has_key("parent"):
parent = args["parent"]
del args["parent"]
else:
parent = None
if args.has_key("cancel"):
cancel = args["cancel"]
del args["cancel"]
else:
cancel = None
gtk.Window.__init__(self, **args)
self.set_transient_for(parent)
self.set_modal(True)
self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
vbox = gtk.VBox(False, 2)
vbox.show()
self.add(vbox)
self.set_title(_("Clone Progress"))
self.set_resizable(False)
self.infolabel = gtk.Label(_("Cloning"))
self.infolabel.show()
vbox.pack_start(self.infolabel, 1, 1, 1)
self.progbar = gtk.ProgressBar()
self.progbar.set_fraction(0.0)
self.progbar.show()
vbox.pack_start(self.progbar, 0, 0, 0)
cancel_b = gtk.Button(_("Cancel"))
cancel_b.connect("clicked", lambda b: cancel())
cancel_b.show()
vbox.pack_start(cancel_b, 0, 0, 0)
def status(self, _status):
self.infolabel.set_text(_status.msg)
if _status.cur > _status.max:
_status.cur = _status.max
self.progbar.set_fraction(_status.cur / float(_status.max))
chirp-0.3.1/chirpui/fips.py 0000644 0000161 0000750 00000750627 12023560646 015357 0 ustar jenkins 0000000 0000000 # Copyright 2012 Tom Hayward
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
FIPS_STATES = {
"Alaska" : 2,
"Alabama" : 1,
"Arkansas" : 5,
"Arizona" : 4,
"California" : 6,
"Colorado" : 8,
"Connecticut" : 9,
"District of Columbia" : 11,
"Delaware" : 10,
"Florida" : 12,
"Georgia" : 13,
"Guam" : 66,
"Hawaii" : 15,
"Iowa" : 19,
"Idaho" : 16,
"Illinois" : 17,
"Indiana" : 18,
"Kansas" : 20,
"Kentucky" : 21,
"Louisiana" : 22,
"Massachusetts" : 25,
"Maryland" : 24,
"Maine" : 23,
"Michigan" : 26,
"Minnesota" : 27,
"Missouri" : 29,
"Mississippi" : 28,
"Montana" : 30,
"North Carolina" : 37,
"North Dakota" : 38,
"Nebraska" : 31,
"New Hampshire" : 33,
"New Jersey" : 34,
"New Mexico" : 35,
"Nevada" : 32,
"New York" : 36,
"Ohio" : 39,
"Oklahoma" : 40,
"Oregon" : 41,
"Pennsylvania" : 42,
"Puerto Rico" : 72,
"Rhode Island" : 44,
"South Carolina" : 45,
"South Dakota" : 46,
"Tennessee" : 47,
"Texas" : 48,
"Utah" : 49,
"Virginia" : 51,
"Virgin Islands" : 78,
"Vermont" : 50,
"Washington" : 53,
"Wisconsin" : 55,
"West Virginia" : 54,
"Wyoming" : 56,
"Alberta" : "CA01",
"British Columbia" : "CA02",
"Manitoba" : "CA03",
"New Brunswick" : "CA04",
"Newfoundland and Labrador": "CA05",
"Northwest Territories": "CA13",
"Nova Scotia" : "CA07",
"Nunavut" : "CA14",
"Ontario" : "CA08",
"Prince Edward Island" : "CA09",
"Quebec" : "CA10",
"Saskatchewan" : "CA11",
"Yukon" : "CA12",
}
FIPS_COUNTIES = {
1: { '--All--': '%',
'Autauga County, AL': '001',
'Baldwin County, AL': '003',
'Barbour County, AL': '005',
'Bibb County, AL': '007',
'Blount County, AL': '009',
'Bullock County, AL': '011',
'Butler County, AL': '013',
'Calhoun County, AL': '015',
'Chambers County, AL': '017',
'Cherokee County, AL': '019',
'Chilton County, AL': '021',
'Choctaw County, AL': '023',
'Clarke County, AL': '025',
'Clay County, AL': '027',
'Cleburne County, AL': '029',
'Coffee County, AL': '031',
'Colbert County, AL': '033',
'Conecuh County, AL': '035',
'Coosa County, AL': '037',
'Covington County, AL': '039',
'Crenshaw County, AL': '041',
'Cullman County, AL': '043',
'Dale County, AL': '045',
'Dallas County, AL': '047',
'DeKalb County, AL': '049',
'Elmore County, AL': '051',
'Escambia County, AL': '053',
'Etowah County, AL': '055',
'Fayette County, AL': '057',
'Franklin County, AL': '059',
'Geneva County, AL': '061',
'Greene County, AL': '063',
'Hale County, AL': '065',
'Henry County, AL': '067',
'Houston County, AL': '069',
'Jackson County, AL': '071',
'Jefferson County, AL': '073',
'Lamar County, AL': '075',
'Lauderdale County, AL': '077',
'Lawrence County, AL': '079',
'Lee County, AL': '081',
'Limestone County, AL': '083',
'Lowndes County, AL': '085',
'Macon County, AL': '087',
'Madison County, AL': '089',
'Marengo County, AL': '091',
'Marion County, AL': '093',
'Marshall County, AL': '095',
'Mobile County, AL': '097',
'Monroe County, AL': '099',
'Montgomery County, AL': '101',
'Morgan County, AL': '103',
'Perry County, AL': '105',
'Pickens County, AL': '107',
'Pike County, AL': '109',
'Randolph County, AL': '111',
'Russell County, AL': '113',
'Shelby County, AL': '117',
'St. Clair County, AL': '115',
'Sumter County, AL': '119',
'Talladega County, AL': '121',
'Tallapoosa County, AL': '123',
'Tuscaloosa County, AL': '125',
'Walker County, AL': '127',
'Washington County, AL': '129',
'Wilcox County, AL': '131',
'Winston County, AL': '133'},
2: { '--All--': '%',
'Aleutians East Borough, AK': '013',
'Aleutians West Census Area, AK': '016',
'Anchorage Borough/municipality, AK': '020',
'Bethel Census Area, AK': '050',
'Bristol Bay Borough, AK': '060',
'Denali Borough, AK': '068',
'Dillingham Census Area, AK': '070',
'Fairbanks North Star Borough, AK': '090',
'Haines Borough, AK': '100',
'Juneau Borough/city, AK': '110',
'Kenai Peninsula Borough, AK': '122',
'Ketchikan Gateway Borough, AK': '130',
'Kodiak Island Borough, AK': '150',
'Lake and Peninsula Borough, AK': '164',
'Matanuska-Susitna Borough, AK': '170',
'Nome Census Area, AK': '180',
'North Slope Borough, AK': '185',
'Northwest Arctic Borough, AK': '188',
'Prince of Wales-Outer Ketchikan Census Area, AK': '201',
'Sitka Borough/city, AK': '220',
'Skagway-Hoonah-Angoon Census Area, AK': '232',
'Southeast Fairbanks Census Area, AK': '240',
'Valdez-Cordova Census Area, AK': '261',
'Wade Hampton Census Area, AK': '270',
'Wrangell-Petersburg Census Area, AK': '280',
'Yakutat Borough, AK': '282',
'Yukon-Koyukuk Census Area, AK': '290'},
4: { '--All--': '%',
'Apache County, AZ': '001',
'Cochise County, AZ': '003',
'Coconino County, AZ': '005',
'Gila County, AZ': '007',
'Graham County, AZ': '009',
'Greenlee County, AZ': '011',
'La Paz County, AZ': '012',
'Maricopa County, AZ': '013',
'Mohave County, AZ': '015',
'Navajo County, AZ': '017',
'Pima County, AZ': '019',
'Pinal County, AZ': '021',
'Santa Cruz County, AZ': '023',
'Yavapai County, AZ': '025',
'Yuma County, AZ': '027'},
5: { '--All--': '%',
'Arkansas County, AR': '001',
'Ashley County, AR': '003',
'Baxter County, AR': '005',
'Benton County, AR': '007',
'Boone County, AR': '009',
'Bradley County, AR': '011',
'Calhoun County, AR': '013',
'Carroll County, AR': '015',
'Chicot County, AR': '017',
'Clark County, AR': '019',
'Clay County, AR': '021',
'Cleburne County, AR': '023',
'Cleveland County, AR': '025',
'Columbia County, AR': '027',
'Conway County, AR': '029',
'Craighead County, AR': '031',
'Crawford County, AR': '033',
'Crittenden County, AR': '035',
'Cross County, AR': '037',
'Dallas County, AR': '039',
'Desha County, AR': '041',
'Drew County, AR': '043',
'Faulkner County, AR': '045',
'Franklin County, AR': '047',
'Fulton County, AR': '049',
'Garland County, AR': '051',
'Grant County, AR': '053',
'Greene County, AR': '055',
'Hempstead County, AR': '057',
'Hot Spring County, AR': '059',
'Howard County, AR': '061',
'Independence County, AR': '063',
'Izard County, AR': '065',
'Jackson County, AR': '067',
'Jefferson County, AR': '069',
'Johnson County, AR': '071',
'Lafayette County, AR': '073',
'Lawrence County, AR': '075',
'Lee County, AR': '077',
'Lincoln County, AR': '079',
'Little River County, AR': '081',
'Logan County, AR': '083',
'Lonoke County, AR': '085',
'Madison County, AR': '087',
'Marion County, AR': '089',
'Miller County, AR': '091',
'Mississippi County, AR': '093',
'Monroe County, AR': '095',
'Montgomery County, AR': '097',
'Nevada County, AR': '099',
'Newton County, AR': '101',
'Ouachita County, AR': '103',
'Perry County, AR': '105',
'Phillips County, AR': '107',
'Pike County, AR': '109',
'Poinsett County, AR': '111',
'Polk County, AR': '113',
'Pope County, AR': '115',
'Prairie County, AR': '117',
'Pulaski County, AR': '119',
'Randolph County, AR': '121',
'Saline County, AR': '125',
'Scott County, AR': '127',
'Searcy County, AR': '129',
'Sebastian County, AR': '131',
'Sevier County, AR': '133',
'Sharp County, AR': '135',
'St. Francis County, AR': '123',
'Stone County, AR': '137',
'Union County, AR': '139',
'Van Buren County, AR': '141',
'Washington County, AR': '143',
'White County, AR': '145',
'Woodruff County, AR': '147',
'Yell County, AR': '149'},
6: { '--All--': '%',
'Alameda County, CA': '001',
'Alpine County, CA': '003',
'Amador County, CA': '005',
'Butte County, CA': '007',
'Calaveras County, CA': '009',
'Colusa County, CA': '011',
'Contra Costa County, CA': '013',
'Del Norte County, CA': '015',
'El Dorado County, CA': '017',
'Fresno County, CA': '019',
'Glenn County, CA': '021',
'Humboldt County, CA': '023',
'Imperial County, CA': '025',
'Inyo County, CA': '027',
'Kern County, CA': '029',
'Kings County, CA': '031',
'Lake County, CA': '033',
'Lassen County, CA': '035',
'Los Angeles County, CA': '037',
'Madera County, CA': '039',
'Marin County, CA': '041',
'Mariposa County, CA': '043',
'Mendocino County, CA': '045',
'Merced County, CA': '047',
'Modoc County, CA': '049',
'Mono County, CA': '051',
'Monterey County, CA': '053',
'Napa County, CA': '055',
'Nevada County, CA': '057',
'Orange County, CA': '059',
'Placer County, CA': '061',
'Plumas County, CA': '063',
'Riverside County, CA': '065',
'Sacramento County, CA': '067',
'San Benito County, CA': '069',
'San Bernardino County, CA': '071',
'San Diego County, CA': '073',
'San Francisco County/city, CA': '075',
'San Joaquin County, CA': '077',
'San Luis Obispo County, CA': '079',
'San Mateo County, CA': '081',
'Santa Barbara County, CA': '083',
'Santa Clara County, CA': '085',
'Santa Cruz County, CA': '087',
'Shasta County, CA': '089',
'Sierra County, CA': '091',
'Siskiyou County, CA': '093',
'Solano County, CA': '095',
'Sonoma County, CA': '097',
'Stanislaus County, CA': '099',
'Sutter County, CA': '101',
'Tehama County, CA': '103',
'Trinity County, CA': '105',
'Tulare County, CA': '107',
'Tuolumne County, CA': '109',
'Ventura County, CA': '111',
'Yolo County, CA': '113',
'Yuba County, CA': '115'},
8: { '--All--': '%',
'Adams County, CO': '001',
'Alamosa County, CO': '003',
'Arapahoe County, CO': '005',
'Archuleta County, CO': '007',
'Baca County, CO': '009',
'Bent County, CO': '011',
'Boulder County, CO': '013',
'Broomfield County/city, CO': '014',
'Chaffee County, CO': '015',
'Cheyenne County, CO': '017',
'Clear Creek County, CO': '019',
'Conejos County, CO': '021',
'Costilla County, CO': '023',
'Crowley County, CO': '025',
'Custer County, CO': '027',
'Delta County, CO': '029',
'Denver County/city, CO': '031',
'Dolores County, CO': '033',
'Douglas County, CO': '035',
'Eagle County, CO': '037',
'El Paso County, CO': '041',
'Elbert County, CO': '039',
'Fremont County, CO': '043',
'Garfield County, CO': '045',
'Gilpin County, CO': '047',
'Grand County, CO': '049',
'Gunnison County, CO': '051',
'Hinsdale County, CO': '053',
'Huerfano County, CO': '055',
'Jackson County, CO': '057',
'Jefferson County, CO': '059',
'Kiowa County, CO': '061',
'Kit Carson County, CO': '063',
'La Plata County, CO': '067',
'Lake County, CO': '065',
'Larimer County, CO': '069',
'Las Animas County, CO': '071',
'Lincoln County, CO': '073',
'Logan County, CO': '075',
'Mesa County, CO': '077',
'Mineral County, CO': '079',
'Moffat County, CO': '081',
'Montezuma County, CO': '083',
'Montrose County, CO': '085',
'Morgan County, CO': '087',
'Otero County, CO': '089',
'Ouray County, CO': '091',
'Park County, CO': '093',
'Phillips County, CO': '095',
'Pitkin County, CO': '097',
'Prowers County, CO': '099',
'Pueblo County, CO': '101',
'Rio Blanco County, CO': '103',
'Rio Grande County, CO': '105',
'Routt County, CO': '107',
'Saguache County, CO': '109',
'San Juan County, CO': '111',
'San Miguel County, CO': '113',
'Sedgwick County, CO': '115',
'Summit County, CO': '117',
'Teller County, CO': '119',
'Washington County, CO': '121',
'Weld County, CO': '123',
'Yuma County, CO': '125'},
9: { '--All--': '%',
'Fairfield County, CT': '001',
'Hartford County, CT': '003',
'Litchfield County, CT': '005',
'Middlesex County, CT': '007',
'New Haven County, CT': '009',
'New London County, CT': '011',
'Tolland County, CT': '013',
'Windham County, CT': '015'},
10: { '--All--': '%',
'Kent County, DE': '001',
'New Castle County, DE': '003',
'Sussex County, DE': '005'},
11: { '--All--': '%', 'District of Columbia': '001'},
12: { '--All--': '%',
'Alachua County, FL': '001',
'Baker County, FL': '003',
'Bay County, FL': '005',
'Bradford County, FL': '007',
'Brevard County, FL': '009',
'Broward County, FL': '011',
'Calhoun County, FL': '013',
'Charlotte County, FL': '015',
'Citrus County, FL': '017',
'Clay County, FL': '019',
'Collier County, FL': '021',
'Columbia County, FL': '023',
'DeSoto County, FL': '027',
'Dixie County, FL': '029',
'Duval County, FL': '031',
'Escambia County, FL': '033',
'Flagler County, FL': '035',
'Franklin County, FL': '037',
'Gadsden County, FL': '039',
'Gilchrist County, FL': '041',
'Glades County, FL': '043',
'Gulf County, FL': '045',
'Hamilton County, FL': '047',
'Hardee County, FL': '049',
'Hendry County, FL': '051',
'Hernando County, FL': '053',
'Highlands County, FL': '055',
'Hillsborough County, FL': '057',
'Holmes County, FL': '059',
'Indian River County, FL': '061',
'Jackson County, FL': '063',
'Jefferson County, FL': '065',
'Lafayette County, FL': '067',
'Lake County, FL': '069',
'Lee County, FL': '071',
'Leon County, FL': '073',
'Levy County, FL': '075',
'Liberty County, FL': '077',
'Madison County, FL': '079',
'Manatee County, FL': '081',
'Marion County, FL': '083',
'Martin County, FL': '085',
'Miami-Dade County, FL': '086',
'Monroe County, FL': '087',
'Nassau County, FL': '089',
'Okaloosa County, FL': '091',
'Okeechobee County, FL': '093',
'Orange County, FL': '095',
'Osceola County, FL': '097',
'Palm Beach County, FL': '099',
'Pasco County, FL': '101',
'Pinellas County, FL': '103',
'Polk County, FL': '105',
'Putnam County, FL': '107',
'Santa Rosa County, FL': '113',
'Sarasota County, FL': '115',
'Seminole County, FL': '117',
'St. Johns County, FL': '109',
'St. Lucie County, FL': '111',
'Sumter County, FL': '119',
'Suwannee County, FL': '121',
'Taylor County, FL': '123',
'Union County, FL': '125',
'Volusia County, FL': '127',
'Wakulla County, FL': '129',
'Walton County, FL': '131',
'Washington County, FL': '133'},
13: { '--All--': '%',
'Appling County, GA': '001',
'Atkinson County, GA': '003',
'Bacon County, GA': '005',
'Baker County, GA': '007',
'Baldwin County, GA': '009',
'Banks County, GA': '011',
'Barrow County, GA': '013',
'Bartow County, GA': '015',
'Ben Hill County, GA': '017',
'Berrien County, GA': '019',
'Bibb County, GA': '021',
'Bleckley County, GA': '023',
'Brantley County, GA': '025',
'Brooks County, GA': '027',
'Bryan County, GA': '029',
'Bulloch County, GA': '031',
'Burke County, GA': '033',
'Butts County, GA': '035',
'Calhoun County, GA': '037',
'Camden County, GA': '039',
'Candler County, GA': '043',
'Carroll County, GA': '045',
'Catoosa County, GA': '047',
'Charlton County, GA': '049',
'Chatham County, GA': '051',
'Chattahoochee County, GA': '053',
'Chattooga County, GA': '055',
'Cherokee County, GA': '057',
'Clarke County, GA': '059',
'Clay County, GA': '061',
'Clayton County, GA': '063',
'Clinch County, GA': '065',
'Cobb County, GA': '067',
'Coffee County, GA': '069',
'Colquitt County, GA': '071',
'Columbia County, GA': '073',
'Cook County, GA': '075',
'Coweta County, GA': '077',
'Crawford County, GA': '079',
'Crisp County, GA': '081',
'Dade County, GA': '083',
'Dawson County, GA': '085',
'DeKalb County, GA': '089',
'Decatur County, GA': '087',
'Dodge County, GA': '091',
'Dooly County, GA': '093',
'Dougherty County, GA': '095',
'Douglas County, GA': '097',
'Early County, GA': '099',
'Echols County, GA': '101',
'Effingham County, GA': '103',
'Elbert County, GA': '105',
'Emanuel County, GA': '107',
'Evans County, GA': '109',
'Fannin County, GA': '111',
'Fayette County, GA': '113',
'Floyd County, GA': '115',
'Forsyth County, GA': '117',
'Franklin County, GA': '119',
'Fulton County, GA': '121',
'Gilmer County, GA': '123',
'Glascock County, GA': '125',
'Glynn County, GA': '127',
'Gordon County, GA': '129',
'Grady County, GA': '131',
'Greene County, GA': '133',
'Gwinnett County, GA': '135',
'Habersham County, GA': '137',
'Hall County, GA': '139',
'Hancock County, GA': '141',
'Haralson County, GA': '143',
'Harris County, GA': '145',
'Hart County, GA': '147',
'Heard County, GA': '149',
'Henry County, GA': '151',
'Houston County, GA': '153',
'Irwin County, GA': '155',
'Jackson County, GA': '157',
'Jasper County, GA': '159',
'Jeff Davis County, GA': '161',
'Jefferson County, GA': '163',
'Jenkins County, GA': '165',
'Johnson County, GA': '167',
'Jones County, GA': '169',
'Lamar County, GA': '171',
'Lanier County, GA': '173',
'Laurens County, GA': '175',
'Lee County, GA': '177',
'Liberty County, GA': '179',
'Lincoln County, GA': '181',
'Long County, GA': '183',
'Lowndes County, GA': '185',
'Lumpkin County, GA': '187',
'Macon County, GA': '193',
'Madison County, GA': '195',
'Marion County, GA': '197',
'McDuffie County, GA': '189',
'McIntosh County, GA': '191',
'Meriwether County, GA': '199',
'Miller County, GA': '201',
'Mitchell County, GA': '205',
'Monroe County, GA': '207',
'Montgomery County, GA': '209',
'Morgan County, GA': '211',
'Murray County, GA': '213',
'Muscogee County, GA': '215',
'Newton County, GA': '217',
'Oconee County, GA': '219',
'Oglethorpe County, GA': '221',
'Paulding County, GA': '223',
'Peach County, GA': '225',
'Pickens County, GA': '227',
'Pierce County, GA': '229',
'Pike County, GA': '231',
'Polk County, GA': '233',
'Pulaski County, GA': '235',
'Putnam County, GA': '237',
'Quitman County, GA': '239',
'Rabun County, GA': '241',
'Randolph County, GA': '243',
'Richmond County, GA': '245',
'Rockdale County, GA': '247',
'Schley County, GA': '249',
'Screven County, GA': '251',
'Seminole County, GA': '253',
'Spalding County, GA': '255',
'Stephens County, GA': '257',
'Stewart County, GA': '259',
'Sumter County, GA': '261',
'Talbot County, GA': '263',
'Taliaferro County, GA': '265',
'Tattnall County, GA': '267',
'Taylor County, GA': '269',
'Telfair County, GA': '271',
'Terrell County, GA': '273',
'Thomas County, GA': '275',
'Tift County, GA': '277',
'Toombs County, GA': '279',
'Towns County, GA': '281',
'Treutlen County, GA': '283',
'Troup County, GA': '285',
'Turner County, GA': '287',
'Twiggs County, GA': '289',
'Union County, GA': '291',
'Upson County, GA': '293',
'Walker County, GA': '295',
'Walton County, GA': '297',
'Ware County, GA': '299',
'Warren County, GA': '301',
'Washington County, GA': '303',
'Wayne County, GA': '305',
'Webster County, GA': '307',
'Wheeler County, GA': '309',
'White County, GA': '311',
'Whitfield County, GA': '313',
'Wilcox County, GA': '315',
'Wilkes County, GA': '317',
'Wilkinson County, GA': '319',
'Worth County, GA': '321'},
15: { '--All--': '%',
'Hawaii County, HI': '001',
'Honolulu County/city, HI': '003',
'Kauai County, HI': '007',
'Maui County, HI': '009'},
16: { '--All--': '%',
'Ada County, ID': '001',
'Adams County, ID': '003',
'Bannock County, ID': '005',
'Bear Lake County, ID': '007',
'Benewah County, ID': '009',
'Bingham County, ID': '011',
'Blaine County, ID': '013',
'Boise County, ID': '015',
'Bonner County, ID': '017',
'Bonneville County, ID': '019',
'Boundary County, ID': '021',
'Butte County, ID': '023',
'Camas County, ID': '025',
'Canyon County, ID': '027',
'Caribou County, ID': '029',
'Cassia County, ID': '031',
'Clark County, ID': '033',
'Clearwater County, ID': '035',
'Custer County, ID': '037',
'Elmore County, ID': '039',
'Franklin County, ID': '041',
'Fremont County, ID': '043',
'Gem County, ID': '045',
'Gooding County, ID': '047',
'Idaho County, ID': '049',
'Jefferson County, ID': '051',
'Jerome County, ID': '053',
'Kootenai County, ID': '055',
'Latah County, ID': '057',
'Lemhi County, ID': '059',
'Lewis County, ID': '061',
'Lincoln County, ID': '063',
'Madison County, ID': '065',
'Minidoka County, ID': '067',
'Nez Perce County, ID': '069',
'Oneida County, ID': '071',
'Owyhee County, ID': '073',
'Payette County, ID': '075',
'Power County, ID': '077',
'Shoshone County, ID': '079',
'Teton County, ID': '081',
'Twin Falls County, ID': '083',
'Valley County, ID': '085',
'Washington County, ID': '087'},
17: { '--All--': '%',
'Adams County, IL': '001',
'Alexander County, IL': '003',
'Bond County, IL': '005',
'Boone County, IL': '007',
'Brown County, IL': '009',
'Bureau County, IL': '011',
'Calhoun County, IL': '013',
'Carroll County, IL': '015',
'Cass County, IL': '017',
'Champaign County, IL': '019',
'Christian County, IL': '021',
'Clark County, IL': '023',
'Clay County, IL': '025',
'Clinton County, IL': '027',
'Coles County, IL': '029',
'Cook County, IL': '031',
'Crawford County, IL': '033',
'Cumberland County, IL': '035',
'De Witt County, IL': '039',
'DeKalb County, IL': '037',
'Douglas County, IL': '041',
'DuPage County, IL': '043',
'Edgar County, IL': '045',
'Edwards County, IL': '047',
'Effingham County, IL': '049',
'Fayette County, IL': '051',
'Ford County, IL': '053',
'Franklin County, IL': '055',
'Fulton County, IL': '057',
'Gallatin County, IL': '059',
'Greene County, IL': '061',
'Grundy County, IL': '063',
'Hamilton County, IL': '065',
'Hancock County, IL': '067',
'Hardin County, IL': '069',
'Henderson County, IL': '071',
'Henry County, IL': '073',
'Iroquois County, IL': '075',
'Jackson County, IL': '077',
'Jasper County, IL': '079',
'Jefferson County, IL': '081',
'Jersey County, IL': '083',
'Jo Daviess County, IL': '085',
'Johnson County, IL': '087',
'Kane County, IL': '089',
'Kankakee County, IL': '091',
'Kendall County, IL': '093',
'Knox County, IL': '095',
'La Salle County, IL': '099',
'Lake County, IL': '097',
'Lawrence County, IL': '101',
'Lee County, IL': '103',
'Livingston County, IL': '105',
'Logan County, IL': '107',
'Macon County, IL': '115',
'Macoupin County, IL': '117',
'Madison County, IL': '119',
'Marion County, IL': '121',
'Marshall County, IL': '123',
'Mason County, IL': '125',
'Massac County, IL': '127',
'McDonough County, IL': '109',
'McHenry County, IL': '111',
'McLean County, IL': '113',
'Menard County, IL': '129',
'Mercer County, IL': '131',
'Monroe County, IL': '133',
'Montgomery County, IL': '135',
'Morgan County, IL': '137',
'Moultrie County, IL': '139',
'Ogle County, IL': '141',
'Peoria County, IL': '143',
'Perry County, IL': '145',
'Piatt County, IL': '147',
'Pike County, IL': '149',
'Pope County, IL': '151',
'Pulaski County, IL': '153',
'Putnam County, IL': '155',
'Randolph County, IL': '157',
'Richland County, IL': '159',
'Rock Island County, IL': '161',
'Saline County, IL': '165',
'Sangamon County, IL': '167',
'Schuyler County, IL': '169',
'Scott County, IL': '171',
'Shelby County, IL': '173',
'St. Clair County, IL': '163',
'Stark County, IL': '175',
'Stephenson County, IL': '177',
'Tazewell County, IL': '179',
'Union County, IL': '181',
'Vermilion County, IL': '183',
'Wabash County, IL': '185',
'Warren County, IL': '187',
'Washington County, IL': '189',
'Wayne County, IL': '191',
'White County, IL': '193',
'Whiteside County, IL': '195',
'Will County, IL': '197',
'Williamson County, IL': '199',
'Winnebago County, IL': '201',
'Woodford County, IL': '203'},
18: { '--All--': '%',
'Adams County, IN': '001',
'Allen County, IN': '003',
'Bartholomew County, IN': '005',
'Benton County, IN': '007',
'Blackford County, IN': '009',
'Boone County, IN': '011',
'Brown County, IN': '013',
'Carroll County, IN': '015',
'Cass County, IN': '017',
'Clark County, IN': '019',
'Clay County, IN': '021',
'Clinton County, IN': '023',
'Crawford County, IN': '025',
'Daviess County, IN': '027',
'DeKalb County, IN': '033',
'Dearborn County, IN': '029',
'Decatur County, IN': '031',
'Delaware County, IN': '035',
'Dubois County, IN': '037',
'Elkhart County, IN': '039',
'Fayette County, IN': '041',
'Floyd County, IN': '043',
'Fountain County, IN': '045',
'Franklin County, IN': '047',
'Fulton County, IN': '049',
'Gibson County, IN': '051',
'Grant County, IN': '053',
'Greene County, IN': '055',
'Hamilton County, IN': '057',
'Hancock County, IN': '059',
'Harrison County, IN': '061',
'Hendricks County, IN': '063',
'Henry County, IN': '065',
'Howard County, IN': '067',
'Huntington County, IN': '069',
'Jackson County, IN': '071',
'Jasper County, IN': '073',
'Jay County, IN': '075',
'Jefferson County, IN': '077',
'Jennings County, IN': '079',
'Johnson County, IN': '081',
'Knox County, IN': '083',
'Kosciusko County, IN': '085',
'LaGrange County, IN': '087',
'LaPorte County, IN': '091',
'Lake County, IN': '089',
'Lawrence County, IN': '093',
'Madison County, IN': '095',
'Marion County, IN': '097',
'Marshall County, IN': '099',
'Martin County, IN': '101',
'Miami County, IN': '103',
'Monroe County, IN': '105',
'Montgomery County, IN': '107',
'Morgan County, IN': '109',
'Newton County, IN': '111',
'Noble County, IN': '113',
'Ohio County, IN': '115',
'Orange County, IN': '117',
'Owen County, IN': '119',
'Parke County, IN': '121',
'Perry County, IN': '123',
'Pike County, IN': '125',
'Porter County, IN': '127',
'Posey County, IN': '129',
'Pulaski County, IN': '131',
'Putnam County, IN': '133',
'Randolph County, IN': '135',
'Ripley County, IN': '137',
'Rush County, IN': '139',
'Scott County, IN': '143',
'Shelby County, IN': '145',
'Spencer County, IN': '147',
'St. Joseph County, IN': '141',
'Starke County, IN': '149',
'Steuben County, IN': '151',
'Sullivan County, IN': '153',
'Switzerland County, IN': '155',
'Tippecanoe County, IN': '157',
'Tipton County, IN': '159',
'Union County, IN': '161',
'Vanderburgh County, IN': '163',
'Vermillion County, IN': '165',
'Vigo County, IN': '167',
'Wabash County, IN': '169',
'Warren County, IN': '171',
'Warrick County, IN': '173',
'Washington County, IN': '175',
'Wayne County, IN': '177',
'Wells County, IN': '179',
'White County, IN': '181',
'Whitley County, IN': '183'},
19: { '--All--': '%',
'Adair County, IA': '001',
'Adams County, IA': '003',
'Allamakee County, IA': '005',
'Appanoose County, IA': '007',
'Audubon County, IA': '009',
'Benton County, IA': '011',
'Black Hawk County, IA': '013',
'Boone County, IA': '015',
'Bremer County, IA': '017',
'Buchanan County, IA': '019',
'Buena Vista County, IA': '021',
'Butler County, IA': '023',
'Calhoun County, IA': '025',
'Carroll County, IA': '027',
'Cass County, IA': '029',
'Cedar County, IA': '031',
'Cerro Gordo County, IA': '033',
'Cherokee County, IA': '035',
'Chickasaw County, IA': '037',
'Clarke County, IA': '039',
'Clay County, IA': '041',
'Clayton County, IA': '043',
'Clinton County, IA': '045',
'Crawford County, IA': '047',
'Dallas County, IA': '049',
'Davis County, IA': '051',
'Decatur County, IA': '053',
'Delaware County, IA': '055',
'Des Moines County, IA': '057',
'Dickinson County, IA': '059',
'Dubuque County, IA': '061',
'Emmet County, IA': '063',
'Fayette County, IA': '065',
'Floyd County, IA': '067',
'Franklin County, IA': '069',
'Fremont County, IA': '071',
'Greene County, IA': '073',
'Grundy County, IA': '075',
'Guthrie County, IA': '077',
'Hamilton County, IA': '079',
'Hancock County, IA': '081',
'Hardin County, IA': '083',
'Harrison County, IA': '085',
'Henry County, IA': '087',
'Howard County, IA': '089',
'Humboldt County, IA': '091',
'Ida County, IA': '093',
'Iowa County, IA': '095',
'Jackson County, IA': '097',
'Jasper County, IA': '099',
'Jefferson County, IA': '101',
'Johnson County, IA': '103',
'Jones County, IA': '105',
'Keokuk County, IA': '107',
'Kossuth County, IA': '109',
'Lee County, IA': '111',
'Linn County, IA': '113',
'Louisa County, IA': '115',
'Lucas County, IA': '117',
'Lyon County, IA': '119',
'Madison County, IA': '121',
'Mahaska County, IA': '123',
'Marion County, IA': '125',
'Marshall County, IA': '127',
'Mills County, IA': '129',
'Mitchell County, IA': '131',
'Monona County, IA': '133',
'Monroe County, IA': '135',
'Montgomery County, IA': '137',
'Muscatine County, IA': '139',
"O'Brien County, IA": '141',
'Osceola County, IA': '143',
'Page County, IA': '145',
'Palo Alto County, IA': '147',
'Plymouth County, IA': '149',
'Pocahontas County, IA': '151',
'Polk County, IA': '153',
'Pottawattamie County, IA': '155',
'Poweshiek County, IA': '157',
'Ringgold County, IA': '159',
'Sac County, IA': '161',
'Scott County, IA': '163',
'Shelby County, IA': '165',
'Sioux County, IA': '167',
'Story County, IA': '169',
'Tama County, IA': '171',
'Taylor County, IA': '173',
'Union County, IA': '175',
'Van Buren County, IA': '177',
'Wapello County, IA': '179',
'Warren County, IA': '181',
'Washington County, IA': '183',
'Wayne County, IA': '185',
'Webster County, IA': '187',
'Winnebago County, IA': '189',
'Winneshiek County, IA': '191',
'Woodbury County, IA': '193',
'Worth County, IA': '195',
'Wright County, IA': '197'},
20: { '--All--': '%',
'Allen County, KS': '001',
'Anderson County, KS': '003',
'Atchison County, KS': '005',
'Barber County, KS': '007',
'Barton County, KS': '009',
'Bourbon County, KS': '011',
'Brown County, KS': '013',
'Butler County, KS': '015',
'Chase County, KS': '017',
'Chautauqua County, KS': '019',
'Cherokee County, KS': '021',
'Cheyenne County, KS': '023',
'Clark County, KS': '025',
'Clay County, KS': '027',
'Cloud County, KS': '029',
'Coffey County, KS': '031',
'Comanche County, KS': '033',
'Cowley County, KS': '035',
'Crawford County, KS': '037',
'Decatur County, KS': '039',
'Dickinson County, KS': '041',
'Doniphan County, KS': '043',
'Douglas County, KS': '045',
'Edwards County, KS': '047',
'Elk County, KS': '049',
'Ellis County, KS': '051',
'Ellsworth County, KS': '053',
'Finney County, KS': '055',
'Ford County, KS': '057',
'Franklin County, KS': '059',
'Geary County, KS': '061',
'Gove County, KS': '063',
'Graham County, KS': '065',
'Grant County, KS': '067',
'Gray County, KS': '069',
'Greeley County, KS': '071',
'Greenwood County, KS': '073',
'Hamilton County, KS': '075',
'Harper County, KS': '077',
'Harvey County, KS': '079',
'Haskell County, KS': '081',
'Hodgeman County, KS': '083',
'Jackson County, KS': '085',
'Jefferson County, KS': '087',
'Jewell County, KS': '089',
'Johnson County, KS': '091',
'Kearny County, KS': '093',
'Kingman County, KS': '095',
'Kiowa County, KS': '097',
'Labette County, KS': '099',
'Lane County, KS': '101',
'Leavenworth County, KS': '103',
'Lincoln County, KS': '105',
'Linn County, KS': '107',
'Logan County, KS': '109',
'Lyon County, KS': '111',
'Marion County, KS': '115',
'Marshall County, KS': '117',
'McPherson County, KS': '113',
'Meade County, KS': '119',
'Miami County, KS': '121',
'Mitchell County, KS': '123',
'Montgomery County, KS': '125',
'Morris County, KS': '127',
'Morton County, KS': '129',
'Nemaha County, KS': '131',
'Neosho County, KS': '133',
'Ness County, KS': '135',
'Norton County, KS': '137',
'Osage County, KS': '139',
'Osborne County, KS': '141',
'Ottawa County, KS': '143',
'Pawnee County, KS': '145',
'Phillips County, KS': '147',
'Pottawatomie County, KS': '149',
'Pratt County, KS': '151',
'Rawlins County, KS': '153',
'Reno County, KS': '155',
'Republic County, KS': '157',
'Rice County, KS': '159',
'Riley County, KS': '161',
'Rooks County, KS': '163',
'Rush County, KS': '165',
'Russell County, KS': '167',
'Saline County, KS': '169',
'Scott County, KS': '171',
'Sedgwick County, KS': '173',
'Seward County, KS': '175',
'Shawnee County, KS': '177',
'Sheridan County, KS': '179',
'Sherman County, KS': '181',
'Smith County, KS': '183',
'Stafford County, KS': '185',
'Stanton County, KS': '187',
'Stevens County, KS': '189',
'Sumner County, KS': '191',
'Thomas County, KS': '193',
'Trego County, KS': '195',
'Wabaunsee County, KS': '197',
'Wallace County, KS': '199',
'Washington County, KS': '201',
'Wichita County, KS': '203',
'Wilson County, KS': '205',
'Woodson County, KS': '207',
'Wyandotte County, KS': '209'},
21: { '--All--': '%',
'Adair County, KY': '001',
'Allen County, KY': '003',
'Anderson County, KY': '005',
'Ballard County, KY': '007',
'Barren County, KY': '009',
'Bath County, KY': '011',
'Bell County, KY': '013',
'Boone County, KY': '015',
'Bourbon County, KY': '017',
'Boyd County, KY': '019',
'Boyle County, KY': '021',
'Bracken County, KY': '023',
'Breathitt County, KY': '025',
'Breckinridge County, KY': '027',
'Bullitt County, KY': '029',
'Butler County, KY': '031',
'Caldwell County, KY': '033',
'Calloway County, KY': '035',
'Campbell County, KY': '037',
'Carlisle County, KY': '039',
'Carroll County, KY': '041',
'Carter County, KY': '043',
'Casey County, KY': '045',
'Christian County, KY': '047',
'Clark County, KY': '049',
'Clay County, KY': '051',
'Clinton County, KY': '053',
'Crittenden County, KY': '055',
'Cumberland County, KY': '057',
'Daviess County, KY': '059',
'Edmonson County, KY': '061',
'Elliott County, KY': '063',
'Estill County, KY': '065',
'Fayette County, KY': '067',
'Fleming County, KY': '069',
'Floyd County, KY': '071',
'Franklin County, KY': '073',
'Fulton County, KY': '075',
'Gallatin County, KY': '077',
'Garrard County, KY': '079',
'Grant County, KY': '081',
'Graves County, KY': '083',
'Grayson County, KY': '085',
'Green County, KY': '087',
'Greenup County, KY': '089',
'Hancock County, KY': '091',
'Hardin County, KY': '093',
'Harlan County, KY': '095',
'Harrison County, KY': '097',
'Hart County, KY': '099',
'Henderson County, KY': '101',
'Henry County, KY': '103',
'Hickman County, KY': '105',
'Hopkins County, KY': '107',
'Jackson County, KY': '109',
'Jefferson County, KY': '111',
'Jessamine County, KY': '113',
'Johnson County, KY': '115',
'Kenton County, KY': '117',
'Knott County, KY': '119',
'Knox County, KY': '121',
'Larue County, KY': '123',
'Laurel County, KY': '125',
'Lawrence County, KY': '127',
'Lee County, KY': '129',
'Leslie County, KY': '131',
'Letcher County, KY': '133',
'Lewis County, KY': '135',
'Lincoln County, KY': '137',
'Livingston County, KY': '139',
'Logan County, KY': '141',
'Lyon County, KY': '143',
'Madison County, KY': '151',
'Magoffin County, KY': '153',
'Marion County, KY': '155',
'Marshall County, KY': '157',
'Martin County, KY': '159',
'Mason County, KY': '161',
'McCracken County, KY': '145',
'McCreary County, KY': '147',
'McLean County, KY': '149',
'Meade County, KY': '163',
'Menifee County, KY': '165',
'Mercer County, KY': '167',
'Metcalfe County, KY': '169',
'Monroe County, KY': '171',
'Montgomery County, KY': '173',
'Morgan County, KY': '175',
'Muhlenberg County, KY': '177',
'Nelson County, KY': '179',
'Nicholas County, KY': '181',
'Ohio County, KY': '183',
'Oldham County, KY': '185',
'Owen County, KY': '187',
'Owsley County, KY': '189',
'Pendleton County, KY': '191',
'Perry County, KY': '193',
'Pike County, KY': '195',
'Powell County, KY': '197',
'Pulaski County, KY': '199',
'Robertson County, KY': '201',
'Rockcastle County, KY': '203',
'Rowan County, KY': '205',
'Russell County, KY': '207',
'Scott County, KY': '209',
'Shelby County, KY': '211',
'Simpson County, KY': '213',
'Spencer County, KY': '215',
'Taylor County, KY': '217',
'Todd County, KY': '219',
'Trigg County, KY': '221',
'Trimble County, KY': '223',
'Union County, KY': '225',
'Warren County, KY': '227',
'Washington County, KY': '229',
'Wayne County, KY': '231',
'Webster County, KY': '233',
'Whitley County, KY': '235',
'Wolfe County, KY': '237',
'Woodford County, KY': '239'},
22: { '--All--': '%',
'Acadia Parish, LA': '001',
'Allen Parish, LA': '003',
'Ascension Parish, LA': '005',
'Assumption Parish, LA': '007',
'Avoyelles Parish, LA': '009',
'Beauregard Parish, LA': '011',
'Bienville Parish, LA': '013',
'Bossier Parish, LA': '015',
'Caddo Parish, LA': '017',
'Calcasieu Parish, LA': '019',
'Caldwell Parish, LA': '021',
'Cameron Parish, LA': '023',
'Catahoula Parish, LA': '025',
'Claiborne Parish, LA': '027',
'Concordia Parish, LA': '029',
'De Soto Parish, LA': '031',
'East Baton Rouge Parish, LA': '033',
'East Carroll Parish, LA': '035',
'East Feliciana Parish, LA': '037',
'Evangeline Parish, LA': '039',
'Franklin Parish, LA': '041',
'Grant Parish, LA': '043',
'Iberia Parish, LA': '045',
'Iberville Parish, LA': '047',
'Jackson Parish, LA': '049',
'Jefferson Davis Parish, LA': '053',
'Jefferson Parish, LA': '051',
'La Salle Parish, LA': '059',
'Lafayette Parish, LA': '055',
'Lafourche Parish, LA': '057',
'Lincoln Parish, LA': '061',
'Livingston Parish, LA': '063',
'Madison Parish, LA': '065',
'Morehouse Parish, LA': '067',
'Natchitoches Parish, LA': '069',
'Orleans Parish, LA': '071',
'Ouachita Parish, LA': '073',
'Plaquemines Parish, LA': '075',
'Pointe Coupee Parish, LA': '077',
'Rapides Parish, LA': '079',
'Red River Parish, LA': '081',
'Richland Parish, LA': '083',
'Sabine Parish, LA': '085',
'St. Bernard Parish, LA': '087',
'St. Charles Parish, LA': '089',
'St. Helena Parish, LA': '091',
'St. James Parish, LA': '093',
'St. John the Baptist Parish, LA': '095',
'St. Landry Parish, LA': '097',
'St. Martin Parish, LA': '099',
'St. Mary Parish, LA': '101',
'St. Tammany Parish, LA': '103',
'Tangipahoa Parish, LA': '105',
'Tensas Parish, LA': '107',
'Terrebonne Parish, LA': '109',
'Union Parish, LA': '111',
'Vermilion Parish, LA': '113',
'Vernon Parish, LA': '115',
'Washington Parish, LA': '117',
'Webster Parish, LA': '119',
'West Baton Rouge Parish, LA': '121',
'West Carroll Parish, LA': '123',
'West Feliciana Parish, LA': '125',
'Winn Parish, LA': '127'},
23: { '--All--': '%',
'Androscoggin County, ME': '001',
'Aroostook County, ME': '003',
'Cumberland County, ME': '005',
'Franklin County, ME': '007',
'Hancock County, ME': '009',
'Kennebec County, ME': '011',
'Knox County, ME': '013',
'Lincoln County, ME': '015',
'Oxford County, ME': '017',
'Penobscot County, ME': '019',
'Piscataquis County, ME': '021',
'Sagadahoc County, ME': '023',
'Somerset County, ME': '025',
'Waldo County, ME': '027',
'Washington County, ME': '029',
'York County, ME': '031'},
24: { '--All--': '%',
'Allegany County, MD': '001',
'Anne Arundel County, MD': '003',
'Baltimore County, MD': '005',
'Baltimore city, MD': '510',
'Calvert County, MD': '009',
'Caroline County, MD': '011',
'Carroll County, MD': '013',
'Cecil County, MD': '015',
'Charles County, MD': '017',
'Dorchester County, MD': '019',
'Frederick County, MD': '021',
'Garrett County, MD': '023',
'Harford County, MD': '025',
'Howard County, MD': '027',
'Kent County, MD': '029',
'Montgomery County, MD': '031',
"Prince George's County, MD": '033',
"Queen Anne's County, MD": '035',
'Somerset County, MD': '039',
"St. Mary's County, MD": '037',
'Talbot County, MD': '041',
'Washington County, MD': '043',
'Wicomico County, MD': '045',
'Worcester County, MD': '047'},
25: { '--All--': '%',
'Barnstable County, MA': '001',
'Berkshire County, MA': '003',
'Bristol County, MA': '005',
'Dukes County, MA': '007',
'Essex County, MA': '009',
'Franklin County, MA': '011',
'Hampden County, MA': '013',
'Hampshire County, MA': '015',
'Middlesex County, MA': '017',
'Nantucket County/town, MA': '019',
'Norfolk County, MA': '021',
'Plymouth County, MA': '023',
'Suffolk County, MA': '025',
'Worcester County, MA': '027'},
26: { '--All--': '%',
'Alcona County, MI': '001',
'Alger County, MI': '003',
'Allegan County, MI': '005',
'Alpena County, MI': '007',
'Antrim County, MI': '009',
'Arenac County, MI': '011',
'Baraga County, MI': '013',
'Barry County, MI': '015',
'Bay County, MI': '017',
'Benzie County, MI': '019',
'Berrien County, MI': '021',
'Branch County, MI': '023',
'Calhoun County, MI': '025',
'Cass County, MI': '027',
'Charlevoix County, MI': '029',
'Cheboygan County, MI': '031',
'Chippewa County, MI': '033',
'Clare County, MI': '035',
'Clinton County, MI': '037',
'Crawford County, MI': '039',
'Delta County, MI': '041',
'Dickinson County, MI': '043',
'Eaton County, MI': '045',
'Emmet County, MI': '047',
'Genesee County, MI': '049',
'Gladwin County, MI': '051',
'Gogebic County, MI': '053',
'Grand Traverse County, MI': '055',
'Gratiot County, MI': '057',
'Hillsdale County, MI': '059',
'Houghton County, MI': '061',
'Huron County, MI': '063',
'Ingham County, MI': '065',
'Ionia County, MI': '067',
'Iosco County, MI': '069',
'Iron County, MI': '071',
'Isabella County, MI': '073',
'Jackson County, MI': '075',
'Kalamazoo County, MI': '077',
'Kalkaska County, MI': '079',
'Kent County, MI': '081',
'Keweenaw County, MI': '083',
'Lake County, MI': '085',
'Lapeer County, MI': '087',
'Leelanau County, MI': '089',
'Lenawee County, MI': '091',
'Livingston County, MI': '093',
'Luce County, MI': '095',
'Mackinac County, MI': '097',
'Macomb County, MI': '099',
'Manistee County, MI': '101',
'Marquette County, MI': '103',
'Mason County, MI': '105',
'Mecosta County, MI': '107',
'Menominee County, MI': '109',
'Midland County, MI': '111',
'Missaukee County, MI': '113',
'Monroe County, MI': '115',
'Montcalm County, MI': '117',
'Montmorency County, MI': '119',
'Muskegon County, MI': '121',
'Newaygo County, MI': '123',
'Oakland County, MI': '125',
'Oceana County, MI': '127',
'Ogemaw County, MI': '129',
'Ontonagon County, MI': '131',
'Osceola County, MI': '133',
'Oscoda County, MI': '135',
'Otsego County, MI': '137',
'Ottawa County, MI': '139',
'Presque Isle County, MI': '141',
'Roscommon County, MI': '143',
'Saginaw County, MI': '145',
'Sanilac County, MI': '151',
'Schoolcraft County, MI': '153',
'Shiawassee County, MI': '155',
'St. Clair County, MI': '147',
'St. Joseph County, MI': '149',
'Tuscola County, MI': '157',
'Van Buren County, MI': '159',
'Washtenaw County, MI': '161',
'Wayne County, MI': '163',
'Wexford County, MI': '165'},
27: { '--All--': '%',
'Aitkin County, MN': '001',
'Anoka County, MN': '003',
'Becker County, MN': '005',
'Beltrami County, MN': '007',
'Benton County, MN': '009',
'Big Stone County, MN': '011',
'Blue Earth County, MN': '013',
'Brown County, MN': '015',
'Carlton County, MN': '017',
'Carver County, MN': '019',
'Cass County, MN': '021',
'Chippewa County, MN': '023',
'Chisago County, MN': '025',
'Clay County, MN': '027',
'Clearwater County, MN': '029',
'Cook County, MN': '031',
'Cottonwood County, MN': '033',
'Crow Wing County, MN': '035',
'Dakota County, MN': '037',
'Dodge County, MN': '039',
'Douglas County, MN': '041',
'Faribault County, MN': '043',
'Fillmore County, MN': '045',
'Freeborn County, MN': '047',
'Goodhue County, MN': '049',
'Grant County, MN': '051',
'Hennepin County, MN': '053',
'Houston County, MN': '055',
'Hubbard County, MN': '057',
'Isanti County, MN': '059',
'Itasca County, MN': '061',
'Jackson County, MN': '063',
'Kanabec County, MN': '065',
'Kandiyohi County, MN': '067',
'Kittson County, MN': '069',
'Koochiching County, MN': '071',
'Lac qui Parle County, MN': '073',
'Lake County, MN': '075',
'Lake of the Woods County, MN': '077',
'Le Sueur County, MN': '079',
'Lincoln County, MN': '081',
'Lyon County, MN': '083',
'Mahnomen County, MN': '087',
'Marshall County, MN': '089',
'Martin County, MN': '091',
'McLeod County, MN': '085',
'Meeker County, MN': '093',
'Mille Lacs County, MN': '095',
'Morrison County, MN': '097',
'Mower County, MN': '099',
'Murray County, MN': '101',
'Nicollet County, MN': '103',
'Nobles County, MN': '105',
'Norman County, MN': '107',
'Olmsted County, MN': '109',
'Otter Tail County, MN': '111',
'Pennington County, MN': '113',
'Pine County, MN': '115',
'Pipestone County, MN': '117',
'Polk County, MN': '119',
'Pope County, MN': '121',
'Ramsey County, MN': '123',
'Red Lake County, MN': '125',
'Redwood County, MN': '127',
'Renville County, MN': '129',
'Rice County, MN': '131',
'Rock County, MN': '133',
'Roseau County, MN': '135',
'Scott County, MN': '139',
'Sherburne County, MN': '141',
'Sibley County, MN': '143',
'St. Louis County, MN': '137',
'Stearns County, MN': '145',
'Steele County, MN': '147',
'Stevens County, MN': '149',
'Swift County, MN': '151',
'Todd County, MN': '153',
'Traverse County, MN': '155',
'Wabasha County, MN': '157',
'Wadena County, MN': '159',
'Waseca County, MN': '161',
'Washington County, MN': '163',
'Watonwan County, MN': '165',
'Wilkin County, MN': '167',
'Winona County, MN': '169',
'Wright County, MN': '171',
'Yellow Medicine County, MN': '173'},
28: { '--All--': '%',
'Adams County, MS': '001',
'Alcorn County, MS': '003',
'Amite County, MS': '005',
'Attala County, MS': '007',
'Benton County, MS': '009',
'Bolivar County, MS': '011',
'Calhoun County, MS': '013',
'Carroll County, MS': '015',
'Chickasaw County, MS': '017',
'Choctaw County, MS': '019',
'Claiborne County, MS': '021',
'Clarke County, MS': '023',
'Clay County, MS': '025',
'Coahoma County, MS': '027',
'Copiah County, MS': '029',
'Covington County, MS': '031',
'DeSoto County, MS': '033',
'Forrest County, MS': '035',
'Franklin County, MS': '037',
'George County, MS': '039',
'Greene County, MS': '041',
'Grenada County, MS': '043',
'Hancock County, MS': '045',
'Harrison County, MS': '047',
'Hinds County, MS': '049',
'Holmes County, MS': '051',
'Humphreys County, MS': '053',
'Issaquena County, MS': '055',
'Itawamba County, MS': '057',
'Jackson County, MS': '059',
'Jasper County, MS': '061',
'Jefferson County, MS': '063',
'Jefferson Davis County, MS': '065',
'Jones County, MS': '067',
'Kemper County, MS': '069',
'Lafayette County, MS': '071',
'Lamar County, MS': '073',
'Lauderdale County, MS': '075',
'Lawrence County, MS': '077',
'Leake County, MS': '079',
'Lee County, MS': '081',
'Leflore County, MS': '083',
'Lincoln County, MS': '085',
'Lowndes County, MS': '087',
'Madison County, MS': '089',
'Marion County, MS': '091',
'Marshall County, MS': '093',
'Monroe County, MS': '095',
'Montgomery County, MS': '097',
'Neshoba County, MS': '099',
'Newton County, MS': '101',
'Noxubee County, MS': '103',
'Oktibbeha County, MS': '105',
'Panola County, MS': '107',
'Pearl River County, MS': '109',
'Perry County, MS': '111',
'Pike County, MS': '113',
'Pontotoc County, MS': '115',
'Prentiss County, MS': '117',
'Quitman County, MS': '119',
'Rankin County, MS': '121',
'Scott County, MS': '123',
'Sharkey County, MS': '125',
'Simpson County, MS': '127',
'Smith County, MS': '129',
'Stone County, MS': '131',
'Sunflower County, MS': '133',
'Tallahatchie County, MS': '135',
'Tate County, MS': '137',
'Tippah County, MS': '139',
'Tishomingo County, MS': '141',
'Tunica County, MS': '143',
'Union County, MS': '145',
'Walthall County, MS': '147',
'Warren County, MS': '149',
'Washington County, MS': '151',
'Wayne County, MS': '153',
'Webster County, MS': '155',
'Wilkinson County, MS': '157',
'Winston County, MS': '159',
'Yalobusha County, MS': '161',
'Yazoo County, MS': '163'},
29: { '--All--': '%',
'Adair County, MO': '001',
'Andrew County, MO': '003',
'Atchison County, MO': '005',
'Audrain County, MO': '007',
'Barry County, MO': '009',
'Barton County, MO': '011',
'Bates County, MO': '013',
'Benton County, MO': '015',
'Bollinger County, MO': '017',
'Boone County, MO': '019',
'Buchanan County, MO': '021',
'Butler County, MO': '023',
'Caldwell County, MO': '025',
'Callaway County, MO': '027',
'Camden County, MO': '029',
'Cape Girardeau County, MO': '031',
'Carroll County, MO': '033',
'Carter County, MO': '035',
'Cass County, MO': '037',
'Cedar County, MO': '039',
'Chariton County, MO': '041',
'Christian County, MO': '043',
'Clark County, MO': '045',
'Clay County, MO': '047',
'Clinton County, MO': '049',
'Cole County, MO': '051',
'Cooper County, MO': '053',
'Crawford County, MO': '055',
'Dade County, MO': '057',
'Dallas County, MO': '059',
'Daviess County, MO': '061',
'DeKalb County, MO': '063',
'Dent County, MO': '065',
'Douglas County, MO': '067',
'Dunklin County, MO': '069',
'Franklin County, MO': '071',
'Gasconade County, MO': '073',
'Gentry County, MO': '075',
'Greene County, MO': '077',
'Grundy County, MO': '079',
'Harrison County, MO': '081',
'Henry County, MO': '083',
'Hickory County, MO': '085',
'Holt County, MO': '087',
'Howard County, MO': '089',
'Howell County, MO': '091',
'Iron County, MO': '093',
'Jackson County, MO': '095',
'Jasper County, MO': '097',
'Jefferson County, MO': '099',
'Johnson County, MO': '101',
'Knox County, MO': '103',
'Laclede County, MO': '105',
'Lafayette County, MO': '107',
'Lawrence County, MO': '109',
'Lewis County, MO': '111',
'Lincoln County, MO': '113',
'Linn County, MO': '115',
'Livingston County, MO': '117',
'Macon County, MO': '121',
'Madison County, MO': '123',
'Maries County, MO': '125',
'Marion County, MO': '127',
'McDonald County, MO': '119',
'Mercer County, MO': '129',
'Miller County, MO': '131',
'Mississippi County, MO': '133',
'Moniteau County, MO': '135',
'Monroe County, MO': '137',
'Montgomery County, MO': '139',
'Morgan County, MO': '141',
'New Madrid County, MO': '143',
'Newton County, MO': '145',
'Nodaway County, MO': '147',
'Oregon County, MO': '149',
'Osage County, MO': '151',
'Ozark County, MO': '153',
'Pemiscot County, MO': '155',
'Perry County, MO': '157',
'Pettis County, MO': '159',
'Phelps County, MO': '161',
'Pike County, MO': '163',
'Platte County, MO': '165',
'Polk County, MO': '167',
'Pulaski County, MO': '169',
'Putnam County, MO': '171',
'Ralls County, MO': '173',
'Randolph County, MO': '175',
'Ray County, MO': '177',
'Reynolds County, MO': '179',
'Ripley County, MO': '181',
'Saline County, MO': '195',
'Schuyler County, MO': '197',
'Scotland County, MO': '199',
'Scott County, MO': '201',
'Shannon County, MO': '203',
'Shelby County, MO': '205',
'St. Charles County, MO': '183',
'St. Clair County, MO': '185',
'St. Francois County, MO': '187',
'St. Louis County, MO': '189',
'St. Louis city, MO': '510',
'Ste. Genevieve County, MO': '186',
'Stoddard County, MO': '207',
'Stone County, MO': '209',
'Sullivan County, MO': '211',
'Taney County, MO': '213',
'Texas County, MO': '215',
'Vernon County, MO': '217',
'Warren County, MO': '219',
'Washington County, MO': '221',
'Wayne County, MO': '223',
'Webster County, MO': '225',
'Worth County, MO': '227',
'Wright County, MO': '229'},
30: { '--All--': '%',
'Beaverhead County, MT': '001',
'Big Horn County, MT': '003',
'Blaine County, MT': '005',
'Broadwater County, MT': '007',
'Carbon County, MT': '009',
'Carter County, MT': '011',
'Cascade County, MT': '013',
'Chouteau County, MT': '015',
'Custer County, MT': '017',
'Daniels County, MT': '019',
'Dawson County, MT': '021',
'Deer Lodge County, MT': '023',
'Fallon County, MT': '025',
'Fergus County, MT': '027',
'Flathead County, MT': '029',
'Gallatin County, MT': '031',
'Garfield County, MT': '033',
'Glacier County, MT': '035',
'Golden Valley County, MT': '037',
'Granite County, MT': '039',
'Hill County, MT': '041',
'Jefferson County, MT': '043',
'Judith Basin County, MT': '045',
'Lake County, MT': '047',
'Lewis and Clark County, MT': '049',
'Liberty County, MT': '051',
'Lincoln County, MT': '053',
'Madison County, MT': '057',
'McCone County, MT': '055',
'Meagher County, MT': '059',
'Mineral County, MT': '061',
'Missoula County, MT': '063',
'Musselshell County, MT': '065',
'Park County, MT': '067',
'Petroleum County, MT': '069',
'Phillips County, MT': '071',
'Pondera County, MT': '073',
'Powder River County, MT': '075',
'Powell County, MT': '077',
'Prairie County, MT': '079',
'Ravalli County, MT': '081',
'Richland County, MT': '083',
'Roosevelt County, MT': '085',
'Rosebud County, MT': '087',
'Sanders County, MT': '089',
'Sheridan County, MT': '091',
'Silver Bow County, MT': '093',
'Stillwater County, MT': '095',
'Sweet Grass County, MT': '097',
'Teton County, MT': '099',
'Toole County, MT': '101',
'Treasure County, MT': '103',
'Valley County, MT': '105',
'Wheatland County, MT': '107',
'Wibaux County, MT': '109',
'Yellowstone County, MT': '111'},
31: { '--All--': '%',
'Adams County, NE': '001',
'Antelope County, NE': '003',
'Arthur County, NE': '005',
'Banner County, NE': '007',
'Blaine County, NE': '009',
'Boone County, NE': '011',
'Box Butte County, NE': '013',
'Boyd County, NE': '015',
'Brown County, NE': '017',
'Buffalo County, NE': '019',
'Burt County, NE': '021',
'Butler County, NE': '023',
'Cass County, NE': '025',
'Cedar County, NE': '027',
'Chase County, NE': '029',
'Cherry County, NE': '031',
'Cheyenne County, NE': '033',
'Clay County, NE': '035',
'Colfax County, NE': '037',
'Cuming County, NE': '039',
'Custer County, NE': '041',
'Dakota County, NE': '043',
'Dawes County, NE': '045',
'Dawson County, NE': '047',
'Deuel County, NE': '049',
'Dixon County, NE': '051',
'Dodge County, NE': '053',
'Douglas County, NE': '055',
'Dundy County, NE': '057',
'Fillmore County, NE': '059',
'Franklin County, NE': '061',
'Frontier County, NE': '063',
'Furnas County, NE': '065',
'Gage County, NE': '067',
'Garden County, NE': '069',
'Garfield County, NE': '071',
'Gosper County, NE': '073',
'Grant County, NE': '075',
'Greeley County, NE': '077',
'Hall County, NE': '079',
'Hamilton County, NE': '081',
'Harlan County, NE': '083',
'Hayes County, NE': '085',
'Hitchcock County, NE': '087',
'Holt County, NE': '089',
'Hooker County, NE': '091',
'Howard County, NE': '093',
'Jefferson County, NE': '095',
'Johnson County, NE': '097',
'Kearney County, NE': '099',
'Keith County, NE': '101',
'Keya Paha County, NE': '103',
'Kimball County, NE': '105',
'Knox County, NE': '107',
'Lancaster County, NE': '109',
'Lincoln County, NE': '111',
'Logan County, NE': '113',
'Loup County, NE': '115',
'Madison County, NE': '119',
'McPherson County, NE': '117',
'Merrick County, NE': '121',
'Morrill County, NE': '123',
'Nance County, NE': '125',
'Nemaha County, NE': '127',
'Nuckolls County, NE': '129',
'Otoe County, NE': '131',
'Pawnee County, NE': '133',
'Perkins County, NE': '135',
'Phelps County, NE': '137',
'Pierce County, NE': '139',
'Platte County, NE': '141',
'Polk County, NE': '143',
'Red Willow County, NE': '145',
'Richardson County, NE': '147',
'Rock County, NE': '149',
'Saline County, NE': '151',
'Sarpy County, NE': '153',
'Saunders County, NE': '155',
'Scotts Bluff County, NE': '157',
'Seward County, NE': '159',
'Sheridan County, NE': '161',
'Sherman County, NE': '163',
'Sioux County, NE': '165',
'Stanton County, NE': '167',
'Thayer County, NE': '169',
'Thomas County, NE': '171',
'Thurston County, NE': '173',
'Valley County, NE': '175',
'Washington County, NE': '177',
'Wayne County, NE': '179',
'Webster County, NE': '181',
'Wheeler County, NE': '183',
'York County, NE': '185'},
32: { '--All--': '%',
'Carson City, NV': '510',
'Churchill County, NV': '001',
'Clark County, NV': '003',
'Douglas County, NV': '005',
'Elko County, NV': '007',
'Esmeralda County, NV': '009',
'Eureka County, NV': '011',
'Humboldt County, NV': '013',
'Lander County, NV': '015',
'Lincoln County, NV': '017',
'Lyon County, NV': '019',
'Mineral County, NV': '021',
'Nye County, NV': '023',
'Pershing County, NV': '027',
'Storey County, NV': '029',
'Washoe County, NV': '031',
'White Pine County, NV': '033'},
33: { '--All--': '%',
'Belknap County, NH': '001',
'Carroll County, NH': '003',
'Cheshire County, NH': '005',
'Coos County, NH': '007',
'Grafton County, NH': '009',
'Hillsborough County, NH': '011',
'Merrimack County, NH': '013',
'Rockingham County, NH': '015',
'Strafford County, NH': '017',
'Sullivan County, NH': '019'},
34: { '--All--': '%',
'Atlantic County, NJ': '001',
'Bergen County, NJ': '003',
'Burlington County, NJ': '005',
'Camden County, NJ': '007',
'Cape May County, NJ': '009',
'Cumberland County, NJ': '011',
'Essex County, NJ': '013',
'Gloucester County, NJ': '015',
'Hudson County, NJ': '017',
'Hunterdon County, NJ': '019',
'Mercer County, NJ': '021',
'Middlesex County, NJ': '023',
'Monmouth County, NJ': '025',
'Morris County, NJ': '027',
'Ocean County, NJ': '029',
'Passaic County, NJ': '031',
'Salem County, NJ': '033',
'Somerset County, NJ': '035',
'Sussex County, NJ': '037',
'Union County, NJ': '039',
'Warren County, NJ': '041'},
35: { '--All--': '%',
'Bernalillo County, NM': '001',
'Catron County, NM': '003',
'Chaves County, NM': '005',
'Cibola County, NM': '006',
'Colfax County, NM': '007',
'Curry County, NM': '009',
'DeBaca County, NM': '011',
'Dona Ana County, NM': '013',
'Eddy County, NM': '015',
'Grant County, NM': '017',
'Guadalupe County, NM': '019',
'Harding County, NM': '021',
'Hidalgo County, NM': '023',
'Lea County, NM': '025',
'Lincoln County, NM': '027',
'Los Alamos County, NM': '028',
'Luna County, NM': '029',
'McKinley County, NM': '031',
'Mora County, NM': '033',
'Otero County, NM': '035',
'Quay County, NM': '037',
'Rio Arriba County, NM': '039',
'Roosevelt County, NM': '041',
'San Juan County, NM': '045',
'San Miguel County, NM': '047',
'Sandoval County, NM': '043',
'Santa Fe County, NM': '049',
'Sierra County, NM': '051',
'Socorro County, NM': '053',
'Taos County, NM': '055',
'Torrance County, NM': '057',
'Union County, NM': '059',
'Valencia County, NM': '061'},
36: { '--All--': '%',
'Albany County, NY': '001',
'Allegany County, NY': '003',
'Bronx County, NY': '005',
'Broome County, NY': '007',
'Cattaraugus County, NY': '009',
'Cayuga County, NY': '011',
'Chautauqua County, NY': '013',
'Chemung County, NY': '015',
'Chenango County, NY': '017',
'Clinton County, NY': '019',
'Columbia County, NY': '021',
'Cortland County, NY': '023',
'Delaware County, NY': '025',
'Dutchess County, NY': '027',
'Erie County, NY': '029',
'Essex County, NY': '031',
'Franklin County, NY': '033',
'Fulton County, NY': '035',
'Genesee County, NY': '037',
'Greene County, NY': '039',
'Hamilton County, NY': '041',
'Herkimer County, NY': '043',
'Jefferson County, NY': '045',
'Kings County, NY': '047',
'Lewis County, NY': '049',
'Livingston County, NY': '051',
'Madison County, NY': '053',
'Monroe County, NY': '055',
'Montgomery County, NY': '057',
'Nassau County, NY': '059',
'New York County, NY': '061',
'Niagara County, NY': '063',
'Oneida County, NY': '065',
'Onondaga County, NY': '067',
'Ontario County, NY': '069',
'Orange County, NY': '071',
'Orleans County, NY': '073',
'Oswego County, NY': '075',
'Otsego County, NY': '077',
'Putnam County, NY': '079',
'Queens County, NY': '081',
'Rensselaer County, NY': '083',
'Richmond County, NY': '085',
'Rockland County, NY': '087',
'Saratoga County, NY': '091',
'Schenectady County, NY': '093',
'Schoharie County, NY': '095',
'Schuyler County, NY': '097',
'Seneca County, NY': '099',
'St. Lawrence County, NY': '089',
'Steuben County, NY': '101',
'Suffolk County, NY': '103',
'Sullivan County, NY': '105',
'Tioga County, NY': '107',
'Tompkins County, NY': '109',
'Ulster County, NY': '111',
'Warren County, NY': '113',
'Washington County, NY': '115',
'Wayne County, NY': '117',
'Westchester County, NY': '119',
'Wyoming County, NY': '121',
'Yates County, NY': '123'},
37: { '--All--': '%',
'Alamance County, NC': '001',
'Alexander County, NC': '003',
'Alleghany County, NC': '005',
'Anson County, NC': '007',
'Ashe County, NC': '009',
'Avery County, NC': '011',
'Beaufort County, NC': '013',
'Bertie County, NC': '015',
'Bladen County, NC': '017',
'Brunswick County, NC': '019',
'Buncombe County, NC': '021',
'Burke County, NC': '023',
'Cabarrus County, NC': '025',
'Caldwell County, NC': '027',
'Camden County, NC': '029',
'Carteret County, NC': '031',
'Caswell County, NC': '033',
'Catawba County, NC': '035',
'Chatham County, NC': '037',
'Cherokee County, NC': '039',
'Chowan County, NC': '041',
'Clay County, NC': '043',
'Cleveland County, NC': '045',
'Columbus County, NC': '047',
'Craven County, NC': '049',
'Cumberland County, NC': '051',
'Currituck County, NC': '053',
'Dare County, NC': '055',
'Davidson County, NC': '057',
'Davie County, NC': '059',
'Duplin County, NC': '061',
'Durham County, NC': '063',
'Edgecombe County, NC': '065',
'Forsyth County, NC': '067',
'Franklin County, NC': '069',
'Gaston County, NC': '071',
'Gates County, NC': '073',
'Graham County, NC': '075',
'Granville County, NC': '077',
'Greene County, NC': '079',
'Guilford County, NC': '081',
'Halifax County, NC': '083',
'Harnett County, NC': '085',
'Haywood County, NC': '087',
'Henderson County, NC': '089',
'Hertford County, NC': '091',
'Hoke County, NC': '093',
'Hyde County, NC': '095',
'Iredell County, NC': '097',
'Jackson County, NC': '099',
'Johnston County, NC': '101',
'Jones County, NC': '103',
'Lee County, NC': '105',
'Lenoir County, NC': '107',
'Lincoln County, NC': '109',
'Macon County, NC': '113',
'Madison County, NC': '115',
'Martin County, NC': '117',
'McDowell County, NC': '111',
'Mecklenburg County, NC': '119',
'Mitchell County, NC': '121',
'Montgomery County, NC': '123',
'Moore County, NC': '125',
'Nash County, NC': '127',
'New Hanover County, NC': '129',
'Northampton County, NC': '131',
'Onslow County, NC': '133',
'Orange County, NC': '135',
'Pamlico County, NC': '137',
'Pasquotank County, NC': '139',
'Pender County, NC': '141',
'Perquimans County, NC': '143',
'Person County, NC': '145',
'Pitt County, NC': '147',
'Polk County, NC': '149',
'Randolph County, NC': '151',
'Richmond County, NC': '153',
'Robeson County, NC': '155',
'Rockingham County, NC': '157',
'Rowan County, NC': '159',
'Rutherford County, NC': '161',
'Sampson County, NC': '163',
'Scotland County, NC': '165',
'Stanly County, NC': '167',
'Stokes County, NC': '169',
'Surry County, NC': '171',
'Swain County, NC': '173',
'Transylvania County, NC': '175',
'Tyrrell County, NC': '177',
'Union County, NC': '179',
'Vance County, NC': '181',
'Wake County, NC': '183',
'Warren County, NC': '185',
'Washington County, NC': '187',
'Watauga County, NC': '189',
'Wayne County, NC': '191',
'Wilkes County, NC': '193',
'Wilson County, NC': '195',
'Yadkin County, NC': '197',
'Yancey County, NC': '199'},
38: { '--All--': '%',
'Adams County, ND': '001',
'Barnes County, ND': '003',
'Benson County, ND': '005',
'Billings County, ND': '007',
'Bottineau County, ND': '009',
'Bowman County, ND': '011',
'Burke County, ND': '013',
'Burleigh County, ND': '015',
'Cass County, ND': '017',
'Cavalier County, ND': '019',
'Dickey County, ND': '021',
'Divide County, ND': '023',
'Dunn County, ND': '025',
'Eddy County, ND': '027',
'Emmons County, ND': '029',
'Foster County, ND': '031',
'Golden Valley County, ND': '033',
'Grand Forks County, ND': '035',
'Grant County, ND': '037',
'Griggs County, ND': '039',
'Hettinger County, ND': '041',
'Kidder County, ND': '043',
'LaMoure County, ND': '045',
'Logan County, ND': '047',
'McHenry County, ND': '049',
'McIntosh County, ND': '051',
'McKenzie County, ND': '053',
'McLean County, ND': '055',
'Mercer County, ND': '057',
'Morton County, ND': '059',
'Mountrail County, ND': '061',
'Nelson County, ND': '063',
'Oliver County, ND': '065',
'Pembina County, ND': '067',
'Pierce County, ND': '069',
'Ramsey County, ND': '071',
'Ransom County, ND': '073',
'Renville County, ND': '075',
'Richland County, ND': '077',
'Rolette County, ND': '079',
'Sargent County, ND': '081',
'Sheridan County, ND': '083',
'Sioux County, ND': '085',
'Slope County, ND': '087',
'Stark County, ND': '089',
'Steele County, ND': '091',
'Stutsman County, ND': '093',
'Towner County, ND': '095',
'Traill County, ND': '097',
'Walsh County, ND': '099',
'Ward County, ND': '101',
'Wells County, ND': '103',
'Williams County, ND': '105'},
39: { '--All--': '%',
'Adams County, OH': '001',
'Allen County, OH': '003',
'Ashland County, OH': '005',
'Ashtabula County, OH': '007',
'Athens County, OH': '009',
'Auglaize County, OH': '011',
'Belmont County, OH': '013',
'Brown County, OH': '015',
'Butler County, OH': '017',
'Carroll County, OH': '019',
'Champaign County, OH': '021',
'Clark County, OH': '023',
'Clermont County, OH': '025',
'Clinton County, OH': '027',
'Columbiana County, OH': '029',
'Coshocton County, OH': '031',
'Crawford County, OH': '033',
'Cuyahoga County, OH': '035',
'Darke County, OH': '037',
'Defiance County, OH': '039',
'Delaware County, OH': '041',
'Erie County, OH': '043',
'Fairfield County, OH': '045',
'Fayette County, OH': '047',
'Franklin County, OH': '049',
'Fulton County, OH': '051',
'Gallia County, OH': '053',
'Geauga County, OH': '055',
'Greene County, OH': '057',
'Guernsey County, OH': '059',
'Hamilton County, OH': '061',
'Hancock County, OH': '063',
'Hardin County, OH': '065',
'Harrison County, OH': '067',
'Henry County, OH': '069',
'Highland County, OH': '071',
'Hocking County, OH': '073',
'Holmes County, OH': '075',
'Huron County, OH': '077',
'Jackson County, OH': '079',
'Jefferson County, OH': '081',
'Knox County, OH': '083',
'Lake County, OH': '085',
'Lawrence County, OH': '087',
'Licking County, OH': '089',
'Logan County, OH': '091',
'Lorain County, OH': '093',
'Lucas County, OH': '095',
'Madison County, OH': '097',
'Mahoning County, OH': '099',
'Marion County, OH': '101',
'Medina County, OH': '103',
'Meigs County, OH': '105',
'Mercer County, OH': '107',
'Miami County, OH': '109',
'Monroe County, OH': '111',
'Montgomery County, OH': '113',
'Morgan County, OH': '115',
'Morrow County, OH': '117',
'Muskingum County, OH': '119',
'Noble County, OH': '121',
'Ottawa County, OH': '123',
'Paulding County, OH': '125',
'Perry County, OH': '127',
'Pickaway County, OH': '129',
'Pike County, OH': '131',
'Portage County, OH': '133',
'Preble County, OH': '135',
'Putnam County, OH': '137',
'Richland County, OH': '139',
'Ross County, OH': '141',
'Sandusky County, OH': '143',
'Scioto County, OH': '145',
'Seneca County, OH': '147',
'Shelby County, OH': '149',
'Stark County, OH': '151',
'Summit County, OH': '153',
'Trumbull County, OH': '155',
'Tuscarawas County, OH': '157',
'Union County, OH': '159',
'Van Wert County, OH': '161',
'Vinton County, OH': '163',
'Warren County, OH': '165',
'Washington County, OH': '167',
'Wayne County, OH': '169',
'Williams County, OH': '171',
'Wood County, OH': '173',
'Wyandot County, OH': '175'},
40: { '--All--': '%',
'Adair County, OK': '001',
'Alfalfa County, OK': '003',
'Atoka County, OK': '005',
'Beaver County, OK': '007',
'Beckham County, OK': '009',
'Blaine County, OK': '011',
'Bryan County, OK': '013',
'Caddo County, OK': '015',
'Canadian County, OK': '017',
'Carter County, OK': '019',
'Cherokee County, OK': '021',
'Choctaw County, OK': '023',
'Cimarron County, OK': '025',
'Cleveland County, OK': '027',
'Coal County, OK': '029',
'Comanche County, OK': '031',
'Cotton County, OK': '033',
'Craig County, OK': '035',
'Creek County, OK': '037',
'Custer County, OK': '039',
'Delaware County, OK': '041',
'Dewey County, OK': '043',
'Ellis County, OK': '045',
'Garfield County, OK': '047',
'Garvin County, OK': '049',
'Grady County, OK': '051',
'Grant County, OK': '053',
'Greer County, OK': '055',
'Harmon County, OK': '057',
'Harper County, OK': '059',
'Haskell County, OK': '061',
'Hughes County, OK': '063',
'Jackson County, OK': '065',
'Jefferson County, OK': '067',
'Johnston County, OK': '069',
'Kay County, OK': '071',
'Kingfisher County, OK': '073',
'Kiowa County, OK': '075',
'Latimer County, OK': '077',
'Le Flore County, OK': '079',
'Lincoln County, OK': '081',
'Logan County, OK': '083',
'Love County, OK': '085',
'Major County, OK': '093',
'Marshall County, OK': '095',
'Mayes County, OK': '097',
'McClain County, OK': '087',
'McCurtain County, OK': '089',
'McIntosh County, OK': '091',
'Murray County, OK': '099',
'Muskogee County, OK': '101',
'Noble County, OK': '103',
'Nowata County, OK': '105',
'Okfuskee County, OK': '107',
'Oklahoma County, OK': '109',
'Okmulgee County, OK': '111',
'Osage County, OK': '113',
'Ottawa County, OK': '115',
'Pawnee County, OK': '117',
'Payne County, OK': '119',
'Pittsburg County, OK': '121',
'Pontotoc County, OK': '123',
'Pottawatomie County, OK': '125',
'Pushmataha County, OK': '127',
'Roger Mills County, OK': '129',
'Rogers County, OK': '131',
'Seminole County, OK': '133',
'Sequoyah County, OK': '135',
'Stephens County, OK': '137',
'Texas County, OK': '139',
'Tillman County, OK': '141',
'Tulsa County, OK': '143',
'Wagoner County, OK': '145',
'Washington County, OK': '147',
'Washita County, OK': '149',
'Woods County, OK': '151',
'Woodward County, OK': '153'},
41: { '--All--': '%',
'Baker County, OR': '001',
'Benton County, OR': '003',
'Clackamas County, OR': '005',
'Clatsop County, OR': '007',
'Columbia County, OR': '009',
'Coos County, OR': '011',
'Crook County, OR': '013',
'Curry County, OR': '015',
'Deschutes County, OR': '017',
'Douglas County, OR': '019',
'Gilliam County, OR': '021',
'Grant County, OR': '023',
'Harney County, OR': '025',
'Hood River County, OR': '027',
'Jackson County, OR': '029',
'Jefferson County, OR': '031',
'Josephine County, OR': '033',
'Klamath County, OR': '035',
'Lake County, OR': '037',
'Lane County, OR': '039',
'Lincoln County, OR': '041',
'Linn County, OR': '043',
'Malheur County, OR': '045',
'Marion County, OR': '047',
'Morrow County, OR': '049',
'Multnomah County, OR': '051',
'Polk County, OR': '053',
'Sherman County, OR': '055',
'Tillamook County, OR': '057',
'Umatilla County, OR': '059',
'Union County, OR': '061',
'Wallowa County, OR': '063',
'Wasco County, OR': '065',
'Washington County, OR': '067',
'Wheeler County, OR': '069',
'Yamhill County, OR': '071'},
42: { '--All--': '%',
'Adams County, PA': '001',
'Allegheny County, PA': '003',
'Armstrong County, PA': '005',
'Beaver County, PA': '007',
'Bedford County, PA': '009',
'Berks County, PA': '011',
'Blair County, PA': '013',
'Bradford County, PA': '015',
'Bucks County, PA': '017',
'Butler County, PA': '019',
'Cambria County, PA': '021',
'Cameron County, PA': '023',
'Carbon County, PA': '025',
'Centre County, PA': '027',
'Chester County, PA': '029',
'Clarion County, PA': '031',
'Clearfield County, PA': '033',
'Clinton County, PA': '035',
'Columbia County, PA': '037',
'Crawford County, PA': '039',
'Cumberland County, PA': '041',
'Dauphin County, PA': '043',
'Delaware County, PA': '045',
'Elk County, PA': '047',
'Erie County, PA': '049',
'Fayette County, PA': '051',
'Forest County, PA': '053',
'Franklin County, PA': '055',
'Fulton County, PA': '057',
'Greene County, PA': '059',
'Huntingdon County, PA': '061',
'Indiana County, PA': '063',
'Jefferson County, PA': '065',
'Juniata County, PA': '067',
'Lackawanna County, PA': '069',
'Lancaster County, PA': '071',
'Lawrence County, PA': '073',
'Lebanon County, PA': '075',
'Lehigh County, PA': '077',
'Luzerne County, PA': '079',
'Lycoming County, PA': '081',
'McKean County, PA': '083',
'Mercer County, PA': '085',
'Mifflin County, PA': '087',
'Monroe County, PA': '089',
'Montgomery County, PA': '091',
'Montour County, PA': '093',
'Northampton County, PA': '095',
'Northumberland County, PA': '097',
'Perry County, PA': '099',
'Philadelphia County/city, PA': '101',
'Pike County, PA': '103',
'Potter County, PA': '105',
'Schuylkill County, PA': '107',
'Snyder County, PA': '109',
'Somerset County, PA': '111',
'Sullivan County, PA': '113',
'Susquehanna County, PA': '115',
'Tioga County, PA': '117',
'Union County, PA': '119',
'Venango County, PA': '121',
'Warren County, PA': '123',
'Washington County, PA': '125',
'Wayne County, PA': '127',
'Westmoreland County, PA': '129',
'Wyoming County, PA': '131',
'York County, PA': '133'},
44: { '--All--': '%',
'Bristol County, RI': '001',
'Kent County, RI': '003',
'Newport County, RI': '005',
'Providence County, RI': '007',
'Washington County, RI': '009'},
45: { '--All--': '%',
'Abbeville County, SC': '001',
'Aiken County, SC': '003',
'Allendale County, SC': '005',
'Anderson County, SC': '007',
'Bamberg County, SC': '009',
'Barnwell County, SC': '011',
'Beaufort County, SC': '013',
'Berkeley County, SC': '015',
'Calhoun County, SC': '017',
'Charleston County, SC': '019',
'Cherokee County, SC': '021',
'Chester County, SC': '023',
'Chesterfield County, SC': '025',
'Clarendon County, SC': '027',
'Colleton County, SC': '029',
'Darlington County, SC': '031',
'Dillon County, SC': '033',
'Dorchester County, SC': '035',
'Edgefield County, SC': '037',
'Fairfield County, SC': '039',
'Florence County, SC': '041',
'Georgetown County, SC': '043',
'Greenville County, SC': '045',
'Greenwood County, SC': '047',
'Hampton County, SC': '049',
'Horry County, SC': '051',
'Jasper County, SC': '053',
'Kershaw County, SC': '055',
'Lancaster County, SC': '057',
'Laurens County, SC': '059',
'Lee County, SC': '061',
'Lexington County, SC': '063',
'Marion County, SC': '067',
'Marlboro County, SC': '069',
'McCormick County, SC': '065',
'Newberry County, SC': '071',
'Oconee County, SC': '073',
'Orangeburg County, SC': '075',
'Pickens County, SC': '077',
'Richland County, SC': '079',
'Saluda County, SC': '081',
'Spartanburg County, SC': '083',
'Sumter County, SC': '085',
'Union County, SC': '087',
'Williamsburg County, SC': '089',
'York County, SC': '091'},
46: { '--All--': '%',
'Aurora County, SD': '003',
'Beadle County, SD': '005',
'Bennett County, SD': '007',
'Bon Homme County, SD': '009',
'Brookings County, SD': '011',
'Brown County, SD': '013',
'Brule County, SD': '015',
'Buffalo County, SD': '017',
'Butte County, SD': '019',
'Campbell County, SD': '021',
'Charles Mix County, SD': '023',
'Clark County, SD': '025',
'Clay County, SD': '027',
'Codington County, SD': '029',
'Corson County, SD': '031',
'Custer County, SD': '033',
'Davison County, SD': '035',
'Day County, SD': '037',
'Deuel County, SD': '039',
'Dewey County, SD': '041',
'Douglas County, SD': '043',
'Edmunds County, SD': '045',
'Fall River County, SD': '047',
'Faulk County, SD': '049',
'Grant County, SD': '051',
'Gregory County, SD': '053',
'Haakon County, SD': '055',
'Hamlin County, SD': '057',
'Hand County, SD': '059',
'Hanson County, SD': '061',
'Harding County, SD': '063',
'Hughes County, SD': '065',
'Hutchinson County, SD': '067',
'Hyde County, SD': '069',
'Jackson County, SD': '071',
'Jerauld County, SD': '073',
'Jones County, SD': '075',
'Kingsbury County, SD': '077',
'Lake County, SD': '079',
'Lawrence County, SD': '081',
'Lincoln County, SD': '083',
'Lyman County, SD': '085',
'Marshall County, SD': '091',
'McCook County, SD': '087',
'McPherson County, SD': '089',
'Meade County, SD': '093',
'Mellette County, SD': '095',
'Miner County, SD': '097',
'Minnehaha County, SD': '099',
'Moody County, SD': '101',
'Pennington County, SD': '103',
'Perkins County, SD': '105',
'Potter County, SD': '107',
'Roberts County, SD': '109',
'Sanborn County, SD': '111',
'Shannon County, SD': '113',
'Spink County, SD': '115',
'Stanley County, SD': '117',
'Sully County, SD': '119',
'Todd County, SD': '121',
'Tripp County, SD': '123',
'Turner County, SD': '125',
'Union County, SD': '127',
'Walworth County, SD': '129',
'Yankton County, SD': '135',
'Ziebach County, SD': '137'},
47: { '--All--': '%',
'Anderson County, TN': '001',
'Bedford County, TN': '003',
'Benton County, TN': '005',
'Bledsoe County, TN': '007',
'Blount County, TN': '009',
'Bradley County, TN': '011',
'Campbell County, TN': '013',
'Cannon County, TN': '015',
'Carroll County, TN': '017',
'Carter County, TN': '019',
'Cheatham County, TN': '021',
'Chester County, TN': '023',
'Claiborne County, TN': '025',
'Clay County, TN': '027',
'Cocke County, TN': '029',
'Coffee County, TN': '031',
'Crockett County, TN': '033',
'Cumberland County, TN': '035',
'Davidson County, TN': '037',
'DeKalb County, TN': '041',
'Decatur County, TN': '039',
'Dickson County, TN': '043',
'Dyer County, TN': '045',
'Fayette County, TN': '047',
'Fentress County, TN': '049',
'Franklin County, TN': '051',
'Gibson County, TN': '053',
'Giles County, TN': '055',
'Grainger County, TN': '057',
'Greene County, TN': '059',
'Grundy County, TN': '061',
'Hamblen County, TN': '063',
'Hamilton County, TN': '065',
'Hancock County, TN': '067',
'Hardeman County, TN': '069',
'Hardin County, TN': '071',
'Hawkins County, TN': '073',
'Haywood County, TN': '075',
'Henderson County, TN': '077',
'Henry County, TN': '079',
'Hickman County, TN': '081',
'Houston County, TN': '083',
'Humphreys County, TN': '085',
'Jackson County, TN': '087',
'Jefferson County, TN': '089',
'Johnson County, TN': '091',
'Knox County, TN': '093',
'Lake County, TN': '095',
'Lauderdale County, TN': '097',
'Lawrence County, TN': '099',
'Lewis County, TN': '101',
'Lincoln County, TN': '103',
'Loudon County, TN': '105',
'Macon County, TN': '111',
'Madison County, TN': '113',
'Marion County, TN': '115',
'Marshall County, TN': '117',
'Maury County, TN': '119',
'McMinn County, TN': '107',
'McNairy County, TN': '109',
'Meigs County, TN': '121',
'Monroe County, TN': '123',
'Montgomery County, TN': '125',
'Moore County, TN': '127',
'Morgan County, TN': '129',
'Obion County, TN': '131',
'Overton County, TN': '133',
'Perry County, TN': '135',
'Pickett County, TN': '137',
'Polk County, TN': '139',
'Putnam County, TN': '141',
'Rhea County, TN': '143',
'Roane County, TN': '145',
'Robertson County, TN': '147',
'Rutherford County, TN': '149',
'Scott County, TN': '151',
'Sequatchie County, TN': '153',
'Sevier County, TN': '155',
'Shelby County, TN': '157',
'Smith County, TN': '159',
'Stewart County, TN': '161',
'Sullivan County, TN': '163',
'Sumner County, TN': '165',
'Tipton County, TN': '167',
'Trousdale County, TN': '169',
'Unicoi County, TN': '171',
'Union County, TN': '173',
'Van Buren County, TN': '175',
'Warren County, TN': '177',
'Washington County, TN': '179',
'Wayne County, TN': '181',
'Weakley County, TN': '183',
'White County, TN': '185',
'Williamson County, TN': '187',
'Wilson County, TN': '189'},
48: { '--All--': '%',
'Anderson County, TX': '001',
'Andrews County, TX': '003',
'Angelina County, TX': '005',
'Aransas County, TX': '007',
'Archer County, TX': '009',
'Armstrong County, TX': '011',
'Atascosa County, TX': '013',
'Austin County, TX': '015',
'Bailey County, TX': '017',
'Bandera County, TX': '019',
'Bastrop County, TX': '021',
'Baylor County, TX': '023',
'Bee County, TX': '025',
'Bell County, TX': '027',
'Bexar County, TX': '029',
'Blanco County, TX': '031',
'Borden County, TX': '033',
'Bosque County, TX': '035',
'Bowie County, TX': '037',
'Brazoria County, TX': '039',
'Brazos County, TX': '041',
'Brewster County, TX': '043',
'Briscoe County, TX': '045',
'Brooks County, TX': '047',
'Brown County, TX': '049',
'Burleson County, TX': '051',
'Burnet County, TX': '053',
'Caldwell County, TX': '055',
'Calhoun County, TX': '057',
'Callahan County, TX': '059',
'Cameron County, TX': '061',
'Camp County, TX': '063',
'Carson County, TX': '065',
'Cass County, TX': '067',
'Castro County, TX': '069',
'Chambers County, TX': '071',
'Cherokee County, TX': '073',
'Childress County, TX': '075',
'Clay County, TX': '077',
'Cochran County, TX': '079',
'Coke County, TX': '081',
'Coleman County, TX': '083',
'Collin County, TX': '085',
'Collingsworth County, TX': '087',
'Colorado County, TX': '089',
'Comal County, TX': '091',
'Comanche County, TX': '093',
'Concho County, TX': '095',
'Cooke County, TX': '097',
'Coryell County, TX': '099',
'Cottle County, TX': '101',
'Crane County, TX': '103',
'Crockett County, TX': '105',
'Crosby County, TX': '107',
'Culberson County, TX': '109',
'Dallam County, TX': '111',
'Dallas County, TX': '113',
'Dawson County, TX': '115',
'DeWitt County, TX': '123',
'Deaf Smith County, TX': '117',
'Delta County, TX': '119',
'Denton County, TX': '121',
'Dickens County, TX': '125',
'Dimmit County, TX': '127',
'Donley County, TX': '129',
'Duval County, TX': '131',
'Eastland County, TX': '133',
'Ector County, TX': '135',
'Edwards County, TX': '137',
'El Paso County, TX': '141',
'Ellis County, TX': '139',
'Erath County, TX': '143',
'Falls County, TX': '145',
'Fannin County, TX': '147',
'Fayette County, TX': '149',
'Fisher County, TX': '151',
'Floyd County, TX': '153',
'Foard County, TX': '155',
'Fort Bend County, TX': '157',
'Franklin County, TX': '159',
'Freestone County, TX': '161',
'Frio County, TX': '163',
'Gaines County, TX': '165',
'Galveston County, TX': '167',
'Garza County, TX': '169',
'Gillespie County, TX': '171',
'Glasscock County, TX': '173',
'Goliad County, TX': '175',
'Gonzales County, TX': '177',
'Gray County, TX': '179',
'Grayson County, TX': '181',
'Gregg County, TX': '183',
'Grimes County, TX': '185',
'Guadalupe County, TX': '187',
'Hale County, TX': '189',
'Hall County, TX': '191',
'Hamilton County, TX': '193',
'Hansford County, TX': '195',
'Hardeman County, TX': '197',
'Hardin County, TX': '199',
'Harris County, TX': '201',
'Harrison County, TX': '203',
'Hartley County, TX': '205',
'Haskell County, TX': '207',
'Hays County, TX': '209',
'Hemphill County, TX': '211',
'Henderson County, TX': '213',
'Hidalgo County, TX': '215',
'Hill County, TX': '217',
'Hockley County, TX': '219',
'Hood County, TX': '221',
'Hopkins County, TX': '223',
'Houston County, TX': '225',
'Howard County, TX': '227',
'Hudspeth County, TX': '229',
'Hunt County, TX': '231',
'Hutchinson County, TX': '233',
'Irion County, TX': '235',
'Jack County, TX': '237',
'Jackson County, TX': '239',
'Jasper County, TX': '241',
'Jeff Davis County, TX': '243',
'Jefferson County, TX': '245',
'Jim Hogg County, TX': '247',
'Jim Wells County, TX': '249',
'Johnson County, TX': '251',
'Jones County, TX': '253',
'Karnes County, TX': '255',
'Kaufman County, TX': '257',
'Kendall County, TX': '259',
'Kenedy County, TX': '261',
'Kent County, TX': '263',
'Kerr County, TX': '265',
'Kimble County, TX': '267',
'King County, TX': '269',
'Kinney County, TX': '271',
'Kleberg County, TX': '273',
'Knox County, TX': '275',
'La Salle County, TX': '283',
'Lamar County, TX': '277',
'Lamb County, TX': '279',
'Lampasas County, TX': '281',
'Lavaca County, TX': '285',
'Lee County, TX': '287',
'Leon County, TX': '289',
'Liberty County, TX': '291',
'Limestone County, TX': '293',
'Lipscomb County, TX': '295',
'Live Oak County, TX': '297',
'Llano County, TX': '299',
'Loving County, TX': '301',
'Lubbock County, TX': '303',
'Lynn County, TX': '305',
'Madison County, TX': '313',
'Marion County, TX': '315',
'Martin County, TX': '317',
'Mason County, TX': '319',
'Matagorda County, TX': '321',
'Maverick County, TX': '323',
'McCulloch County, TX': '307',
'McLennan County, TX': '309',
'McMullen County, TX': '311',
'Medina County, TX': '325',
'Menard County, TX': '327',
'Midland County, TX': '329',
'Milam County, TX': '331',
'Mills County, TX': '333',
'Mitchell County, TX': '335',
'Montague County, TX': '337',
'Montgomery County, TX': '339',
'Moore County, TX': '341',
'Morris County, TX': '343',
'Motley County, TX': '345',
'Nacogdoches County, TX': '347',
'Navarro County, TX': '349',
'Newton County, TX': '351',
'Nolan County, TX': '353',
'Nueces County, TX': '355',
'Ochiltree County, TX': '357',
'Oldham County, TX': '359',
'Orange County, TX': '361',
'Palo Pinto County, TX': '363',
'Panola County, TX': '365',
'Parker County, TX': '367',
'Parmer County, TX': '369',
'Pecos County, TX': '371',
'Polk County, TX': '373',
'Potter County, TX': '375',
'Presidio County, TX': '377',
'Rains County, TX': '379',
'Randall County, TX': '381',
'Reagan County, TX': '383',
'Real County, TX': '385',
'Red River County, TX': '387',
'Reeves County, TX': '389',
'Refugio County, TX': '391',
'Roberts County, TX': '393',
'Robertson County, TX': '395',
'Rockwall County, TX': '397',
'Runnels County, TX': '399',
'Rusk County, TX': '401',
'Sabine County, TX': '403',
'San Augustine County, TX': '405',
'San Jacinto County, TX': '407',
'San Patricio County, TX': '409',
'San Saba County, TX': '411',
'Schleicher County, TX': '413',
'Scurry County, TX': '415',
'Shackelford County, TX': '417',
'Shelby County, TX': '419',
'Sherman County, TX': '421',
'Smith County, TX': '423',
'Somervell County, TX': '425',
'Starr County, TX': '427',
'Stephens County, TX': '429',
'Sterling County, TX': '431',
'Stonewall County, TX': '433',
'Sutton County, TX': '435',
'Swisher County, TX': '437',
'Tarrant County, TX': '439',
'Taylor County, TX': '441',
'Terrell County, TX': '443',
'Terry County, TX': '445',
'Throckmorton County, TX': '447',
'Titus County, TX': '449',
'Tom Green County, TX': '451',
'Travis County, TX': '453',
'Trinity County, TX': '455',
'Tyler County, TX': '457',
'Upshur County, TX': '459',
'Upton County, TX': '461',
'Uvalde County, TX': '463',
'Val Verde County, TX': '465',
'Van Zandt County, TX': '467',
'Victoria County, TX': '469',
'Walker County, TX': '471',
'Waller County, TX': '473',
'Ward County, TX': '475',
'Washington County, TX': '477',
'Webb County, TX': '479',
'Wharton County, TX': '481',
'Wheeler County, TX': '483',
'Wichita County, TX': '485',
'Wilbarger County, TX': '487',
'Willacy County, TX': '489',
'Williamson County, TX': '491',
'Wilson County, TX': '493',
'Winkler County, TX': '495',
'Wise County, TX': '497',
'Wood County, TX': '499',
'Yoakum County, TX': '501',
'Young County, TX': '503',
'Zapata County, TX': '505',
'Zavala County, TX': '507'},
49: { '--All--': '%',
'Beaver County, UT': '001',
'Box Elder County, UT': '003',
'Cache County, UT': '005',
'Carbon County, UT': '007',
'Daggett County, UT': '009',
'Davis County, UT': '011',
'Duchesne County, UT': '013',
'Emery County, UT': '015',
'Garfield County, UT': '017',
'Grand County, UT': '019',
'Iron County, UT': '021',
'Juab County, UT': '023',
'Kane County, UT': '025',
'Millard County, UT': '027',
'Morgan County, UT': '029',
'Piute County, UT': '031',
'Rich County, UT': '033',
'Salt Lake County, UT': '035',
'San Juan County, UT': '037',
'Sanpete County, UT': '039',
'Sevier County, UT': '041',
'Summit County, UT': '043',
'Tooele County, UT': '045',
'Uintah County, UT': '047',
'Utah County, UT': '049',
'Wasatch County, UT': '051',
'Washington County, UT': '053',
'Wayne County, UT': '055',
'Weber County, UT': '057'},
50: { '--All--': '%',
'Addison County, VT': '001',
'Bennington County, VT': '003',
'Caledonia County, VT': '005',
'Chittenden County, VT': '007',
'Essex County, VT': '009',
'Franklin County, VT': '011',
'Grand Isle County, VT': '013',
'Lamoille County, VT': '015',
'Orange County, VT': '017',
'Orleans County, VT': '019',
'Rutland County, VT': '021',
'Washington County, VT': '023',
'Windham County, VT': '025',
'Windsor County, VT': '027'},
51: { '--All--': '%',
'Accomack County, VA': '001',
'Albemarle County, VA': '003',
'Alexandria city, VA': '510',
'Alleghany County, VA': '005',
'Amelia County, VA': '007',
'Amherst County, VA': '009',
'Appomattox County, VA': '011',
'Arlington County, VA': '013',
'Augusta County, VA': '015',
'Bath County, VA': '017',
'Bedford County, VA': '019',
'Bedford city, VA': '515',
'Bland County, VA': '021',
'Botetourt County, VA': '023',
'Bristol city, VA': '520',
'Brunswick County, VA': '025',
'Buchanan County, VA': '027',
'Buckingham County, VA': '029',
'Buena Vista city, VA': '530',
'Campbell County, VA': '031',
'Caroline County, VA': '033',
'Carroll County, VA': '035',
'Charles City County, VA': '036',
'Charlotte County, VA': '037',
'Charlottesville city, VA': '540',
'Chesapeake city, VA': '550',
'Chesterfield County, VA': '041',
'Clarke County, VA': '043',
'Colonial Heights city, VA': '570',
'Covington city, VA': '580',
'Craig County, VA': '045',
'Culpeper County, VA': '047',
'Cumberland County, VA': '049',
'Danville city, VA': '590',
'Dickenson County, VA': '051',
'Dinwiddie County, VA': '053',
'Emporia city, VA': '595',
'Essex County, VA': '057',
'Fairfax County, VA': '059',
'Fairfax city, VA': '600',
'Falls Church city, VA': '610',
'Fauquier County, VA': '061',
'Floyd County, VA': '063',
'Fluvanna County, VA': '065',
'Franklin County, VA': '067',
'Franklin city, VA': '620',
'Frederick County, VA': '069',
'Fredericksburg city, VA': '630',
'Galax city, VA': '640',
'Giles County, VA': '071',
'Gloucester County, VA': '073',
'Goochland County, VA': '075',
'Grayson County, VA': '077',
'Greene County, VA': '079',
'Greensville County, VA': '081',
'Halifax County, VA': '083',
'Hampton city, VA': '650',
'Hanover County, VA': '085',
'Harrisonburg city, VA': '660',
'Henrico County, VA': '087',
'Henry County, VA': '089',
'Highland County, VA': '091',
'Hopewell city, VA': '670',
'Isle of Wight County, VA': '093',
'James City County, VA': '095',
'King George County, VA': '099',
'King William County, VA': '101',
'King and Queen County, VA': '097',
'Lancaster County, VA': '103',
'Lee County, VA': '105',
'Lexington city, VA': '678',
'Loudoun County, VA': '107',
'Louisa County, VA': '109',
'Lunenburg County, VA': '111',
'Lynchburg city, VA': '680',
'Madison County, VA': '113',
'Manassas Park city, VA': '685',
'Manassas city, VA': '683',
'Martinsville city, VA': '690',
'Mathews County, VA': '115',
'Mecklenburg County, VA': '117',
'Middlesex County, VA': '119',
'Montgomery County, VA': '121',
'Nelson County, VA': '125',
'New Kent County, VA': '127',
'Newport News city, VA': '700',
'Norfolk city, VA': '710',
'Northampton County, VA': '131',
'Northumberland County, VA': '133',
'Norton city, VA': '720',
'Nottoway County, VA': '135',
'Orange County, VA': '137',
'Page County, VA': '139',
'Patrick County, VA': '141',
'Petersburg city, VA': '730',
'Pittsylvania County, VA': '143',
'Poquoson city, VA': '735',
'Portsmouth city, VA': '740',
'Powhatan County, VA': '145',
'Prince Edward County, VA': '147',
'Prince George County, VA': '149',
'Prince William County, VA': '153',
'Pulaski County, VA': '155',
'Radford city, VA': '750',
'Rappahannock County, VA': '157',
'Richmond County, VA': '159',
'Richmond city, VA': '760',
'Roanoke County, VA': '161',
'Roanoke city, VA': '770',
'Rockbridge County, VA': '163',
'Rockingham County, VA': '165',
'Russell County, VA': '167',
'Salem city, VA': '775',
'Scott County, VA': '169',
'Shenandoah County, VA': '171',
'Smyth County, VA': '173',
'Southampton County, VA': '175',
'Spotsylvania County, VA': '177',
'Stafford County, VA': '179',
'Staunton city, VA': '790',
'Suffolk city, VA': '800',
'Surry County, VA': '181',
'Sussex County, VA': '183',
'Tazewell County, VA': '185',
'Virginia Beach city, VA': '810',
'Warren County, VA': '187',
'Washington County, VA': '191',
'Waynesboro city, VA': '820',
'Westmoreland County, VA': '193',
'Williamsburg city, VA': '830',
'Winchester city, VA': '840',
'Wise County, VA': '195',
'Wythe County, VA': '197',
'York County, VA': '199'},
53: { '--All--': '%',
'Adams County, WA': '001',
'Asotin County, WA': '003',
'Benton County, WA': '005',
'Chelan County, WA': '007',
'Clallam County, WA': '009',
'Clark County, WA': '011',
'Columbia County, WA': '013',
'Cowlitz County, WA': '015',
'Douglas County, WA': '017',
'Ferry County, WA': '019',
'Franklin County, WA': '021',
'Garfield County, WA': '023',
'Grant County, WA': '025',
'Grays Harbor County, WA': '027',
'Island County, WA': '029',
'Jefferson County, WA': '031',
'King County, WA': '033',
'Kitsap County, WA': '035',
'Kittitas County, WA': '037',
'Klickitat County, WA': '039',
'Lewis County, WA': '041',
'Lincoln County, WA': '043',
'Mason County, WA': '045',
'Okanogan County, WA': '047',
'Pacific County, WA': '049',
'Pend Oreille County, WA': '051',
'Pierce County, WA': '053',
'San Juan County, WA': '055',
'Skagit County, WA': '057',
'Skamania County, WA': '059',
'Snohomish County, WA': '061',
'Spokane County, WA': '063',
'Stevens County, WA': '065',
'Thurston County, WA': '067',
'Wahkiakum County, WA': '069',
'Walla Walla County, WA': '071',
'Whatcom County, WA': '073',
'Whitman County, WA': '075',
'Yakima County, WA': '077'},
54: { '--All--': '%',
'Barbour County, WV': '001',
'Berkeley County, WV': '003',
'Boone County, WV': '005',
'Braxton County, WV': '007',
'Brooke County, WV': '009',
'Cabell County, WV': '011',
'Calhoun County, WV': '013',
'Clay County, WV': '015',
'Doddridge County, WV': '017',
'Fayette County, WV': '019',
'Gilmer County, WV': '021',
'Grant County, WV': '023',
'Greenbrier County, WV': '025',
'Hampshire County, WV': '027',
'Hancock County, WV': '029',
'Hardy County, WV': '031',
'Harrison County, WV': '033',
'Jackson County, WV': '035',
'Jefferson County, WV': '037',
'Kanawha County, WV': '039',
'Lewis County, WV': '041',
'Lincoln County, WV': '043',
'Logan County, WV': '045',
'Marion County, WV': '049',
'Marshall County, WV': '051',
'Mason County, WV': '053',
'McDowell County, WV': '047',
'Mercer County, WV': '055',
'Mineral County, WV': '057',
'Mingo County, WV': '059',
'Monongalia County, WV': '061',
'Monroe County, WV': '063',
'Morgan County, WV': '065',
'Nicholas County, WV': '067',
'Ohio County, WV': '069',
'Pendleton County, WV': '071',
'Pleasants County, WV': '073',
'Pocahontas County, WV': '075',
'Preston County, WV': '077',
'Putnam County, WV': '079',
'Raleigh County, WV': '081',
'Randolph County, WV': '083',
'Ritchie County, WV': '085',
'Roane County, WV': '087',
'Summers County, WV': '089',
'Taylor County, WV': '091',
'Tucker County, WV': '093',
'Tyler County, WV': '095',
'Upshur County, WV': '097',
'Wayne County, WV': '099',
'Webster County, WV': '101',
'Wetzel County, WV': '103',
'Wirt County, WV': '105',
'Wood County, WV': '107',
'Wyoming County, WV': '109'},
55: { '--All--': '%',
'Adams County, WI': '001',
'Ashland County, WI': '003',
'Barron County, WI': '005',
'Bayfield County, WI': '007',
'Brown County, WI': '009',
'Buffalo County, WI': '011',
'Burnett County, WI': '013',
'Calumet County, WI': '015',
'Chippewa County, WI': '017',
'Clark County, WI': '019',
'Columbia County, WI': '021',
'Crawford County, WI': '023',
'Dane County, WI': '025',
'Dodge County, WI': '027',
'Door County, WI': '029',
'Douglas County, WI': '031',
'Dunn County, WI': '033',
'Eau Claire County, WI': '035',
'Florence County, WI': '037',
'Fond du Lac County, WI': '039',
'Forest County, WI': '041',
'Grant County, WI': '043',
'Green County, WI': '045',
'Green Lake County, WI': '047',
'Iowa County, WI': '049',
'Iron County, WI': '051',
'Jackson County, WI': '053',
'Jefferson County, WI': '055',
'Juneau County, WI': '057',
'Kenosha County, WI': '059',
'Kewaunee County, WI': '061',
'La Crosse County, WI': '063',
'Lafayette County, WI': '065',
'Langlade County, WI': '067',
'Lincoln County, WI': '069',
'Manitowoc County, WI': '071',
'Marathon County, WI': '073',
'Marinette County, WI': '075',
'Marquette County, WI': '077',
'Menominee County, WI': '078',
'Milwaukee County, WI': '079',
'Monroe County, WI': '081',
'Oconto County, WI': '083',
'Oneida County, WI': '085',
'Outagamie County, WI': '087',
'Ozaukee County, WI': '089',
'Pepin County, WI': '091',
'Pierce County, WI': '093',
'Polk County, WI': '095',
'Portage County, WI': '097',
'Price County, WI': '099',
'Racine County, WI': '101',
'Richland County, WI': '103',
'Rock County, WI': '105',
'Rusk County, WI': '107',
'Sauk County, WI': '111',
'Sawyer County, WI': '113',
'Shawano County, WI': '115',
'Sheboygan County, WI': '117',
'St. Croix County, WI': '109',
'Taylor County, WI': '119',
'Trempealeau County, WI': '121',
'Vernon County, WI': '123',
'Vilas County, WI': '125',
'Walworth County, WI': '127',
'Washburn County, WI': '129',
'Washington County, WI': '131',
'Waukesha County, WI': '133',
'Waupaca County, WI': '135',
'Waushara County, WI': '137',
'Winnebago County, WI': '139',
'Wood County, WI': '141'},
56: { '--All--': '%',
'Albany County, WY': '001',
'Big Horn County, WY': '003',
'Campbell County, WY': '005',
'Carbon County, WY': '007',
'Converse County, WY': '009',
'Crook County, WY': '011',
'Fremont County, WY': '013',
'Goshen County, WY': '015',
'Hot Springs County, WY': '017',
'Johnson County, WY': '019',
'Laramie County, WY': '021',
'Lincoln County, WY': '023',
'Natrona County, WY': '025',
'Niobrara County, WY': '027',
'Park County, WY': '029',
'Platte County, WY': '031',
'Sheridan County, WY': '033',
'Sublette County, WY': '035',
'Sweetwater County, WY': '037',
'Teton County, WY': '039',
'Uinta County, WY': '041',
'Washakie County, WY': '043',
'Weston County, WY': '045'},
72: { '--All--': '%',
'Adjuntas Municipio, PR': '001',
'Aguada Municipio, PR': '003',
'Aguadilla Municipio, PR': '005',
'Aguas Buenas Municipio, PR': '007',
'Aibonito Municipio, PR': '009',
'Anasco Municipio, PR': '011',
'Arecibo Municipio, PR': '013',
'Arroyo Municipio, PR': '015',
'Barceloneta Municipio, PR': '017',
'Barranquitas Municipio, PR': '019',
'Bayamon Municipio, PR': '021',
'Cabo Rojo Municipio, PR': '023',
'Caguas Municipio, PR': '025',
'Camuy Municipio, PR': '027',
'Canovanas Municipio, PR': '029',
'Carolina Municipio, PR': '031',
'Catano Municipio, PR': '033',
'Cayey Municipio, PR': '035',
'Ceiba Municipio, PR': '037',
'Ciales Municipio, PR': '039',
'Cidra Municipio, PR': '041',
'Coamo Municipio, PR': '043',
'Comerio Municipio, PR': '045',
'Corozal Municipio, PR': '047',
'Culebra Municipio, PR': '049',
'Dorado Municipio, PR': '051',
'Fajardo Municipio, PR': '053',
'Florida Municipio, PR': '054',
'Guanica Municipio, PR': '055',
'Guayama Municipio, PR': '057',
'Guayanilla Municipio, PR': '059',
'Guaynabo Municipio, PR': '061',
'Gurabo Municipio, PR': '063',
'Hatillo Municipio, PR': '065',
'Hormigueros Municipio, PR': '067',
'Humacao Municipio, PR': '069',
'Isabela Municipio, PR': '071',
'Jayuya Municipio, PR': '073',
'Juana Diaz Municipio, PR': '075',
'Juncos Municipio, PR': '077',
'Lajas Municipio, PR': '079',
'Lares Municipio, PR': '081',
'Las Marias Municipio, PR': '083',
'Las Piedras Municipio, PR': '085',
'Loiza Municipio, PR': '087',
'Luquillo Municipio, PR': '089',
'Manati Municipio, PR': '091',
'Maricao Municipio, PR': '093',
'Maunabo Municipio, PR': '095',
'Mayaguez Municipio, PR': '097',
'Moca Municipio, PR': '099',
'Morovis Municipio, PR': '101',
'Naguabo Municipio, PR': '103',
'Naranjito Municipio, PR': '105',
'Orocovis Municipio, PR': '107',
'Patillas Municipio, PR': '109',
'Penuelas Municipio, PR': '111',
'Ponce Municipio, PR': '113',
'Quebradillas Municipio, PR': '115',
'Rincon Municipio, PR': '117',
'Rio Grande Municipio, PR': '119',
'Sabana Grande Municipio, PR': '121',
'Salinas Municipio, PR': '123',
'San German Municipio, PR': '125',
'San Juan Municipio, PR': '127',
'San Lorenzo Municipio, PR': '129',
'San Sebastian Municipio, PR': '131',
'Santa Isabel Municipio, PR': '133',
'Toa Alta Municipio, PR': '135',
'Toa Baja Municipio, PR': '137',
'Trujillo Alto Municipio, PR': '139',
'Utuado Municipio, PR': '141',
'Vega Alta Municipio, PR': '143',
'Vega Baja Municipio, PR': '145',
'Vieques Municipio, PR': '147',
'Villalba Municipio, PR': '149',
'Yabucoa Municipio, PR': '151',
'Yauco Municipio, PR': '153'},
'01': { 'Autauga County, AL': '001',
'Baldwin County, AL': '003',
'Barbour County, AL': '005',
'Bibb County, AL': '007',
'Blount County, AL': '009',
'Bullock County, AL': '011',
'Butler County, AL': '013',
'Calhoun County, AL': '015',
'Chambers County, AL': '017',
'Cherokee County, AL': '019',
'Chilton County, AL': '021',
'Choctaw County, AL': '023',
'Clarke County, AL': '025',
'Clay County, AL': '027',
'Cleburne County, AL': '029',
'Coffee County, AL': '031',
'Colbert County, AL': '033',
'Conecuh County, AL': '035',
'Coosa County, AL': '037',
'Covington County, AL': '039',
'Crenshaw County, AL': '041',
'Cullman County, AL': '043',
'Dale County, AL': '045',
'Dallas County, AL': '047',
'DeKalb County, AL': '049',
'Elmore County, AL': '051',
'Escambia County, AL': '053',
'Etowah County, AL': '055',
'Fayette County, AL': '057',
'Franklin County, AL': '059',
'Geneva County, AL': '061',
'Greene County, AL': '063',
'Hale County, AL': '065',
'Henry County, AL': '067',
'Houston County, AL': '069',
'Jackson County, AL': '071',
'Jefferson County, AL': '073',
'Lamar County, AL': '075',
'Lauderdale County, AL': '077',
'Lawrence County, AL': '079',
'Lee County, AL': '081',
'Limestone County, AL': '083',
'Lowndes County, AL': '085',
'Macon County, AL': '087',
'Madison County, AL': '089',
'Marengo County, AL': '091',
'Marion County, AL': '093',
'Marshall County, AL': '095',
'Mobile County, AL': '097',
'Monroe County, AL': '099',
'Montgomery County, AL': '101',
'Morgan County, AL': '103',
'Perry County, AL': '105',
'Pickens County, AL': '107',
'Pike County, AL': '109',
'Randolph County, AL': '111',
'Russell County, AL': '113',
'Shelby County, AL': '117',
'St. Clair County, AL': '115',
'Sumter County, AL': '119',
'Talladega County, AL': '121',
'Tallapoosa County, AL': '123',
'Tuscaloosa County, AL': '125',
'Walker County, AL': '127',
'Washington County, AL': '129',
'Wilcox County, AL': '131',
'Winston County, AL': '133'},
'02': { 'Aleutians East Borough, AK': '013',
'Aleutians West Census Area, AK': '016',
'Anchorage Borough/municipality, AK': '020',
'Bethel Census Area, AK': '050',
'Bristol Bay Borough, AK': '060',
'Denali Borough, AK': '068',
'Dillingham Census Area, AK': '070',
'Fairbanks North Star Borough, AK': '090',
'Haines Borough, AK': '100',
'Juneau Borough/city, AK': '110',
'Kenai Peninsula Borough, AK': '122',
'Ketchikan Gateway Borough, AK': '130',
'Kodiak Island Borough, AK': '150',
'Lake and Peninsula Borough, AK': '164',
'Matanuska-Susitna Borough, AK': '170',
'Nome Census Area, AK': '180',
'North Slope Borough, AK': '185',
'Northwest Arctic Borough, AK': '188',
'Prince of Wales-Outer Ketchikan Census Area, AK': '201',
'Sitka Borough/city, AK': '220',
'Skagway-Hoonah-Angoon Census Area, AK': '232',
'Southeast Fairbanks Census Area, AK': '240',
'Valdez-Cordova Census Area, AK': '261',
'Wade Hampton Census Area, AK': '270',
'Wrangell-Petersburg Census Area, AK': '280',
'Yakutat Borough, AK': '282',
'Yukon-Koyukuk Census Area, AK': '290'},
'04': { 'Apache County, AZ': '001',
'Cochise County, AZ': '003',
'Coconino County, AZ': '005',
'Gila County, AZ': '007',
'Graham County, AZ': '009',
'Greenlee County, AZ': '011',
'La Paz County, AZ': '012',
'Maricopa County, AZ': '013',
'Mohave County, AZ': '015',
'Navajo County, AZ': '017',
'Pima County, AZ': '019',
'Pinal County, AZ': '021',
'Santa Cruz County, AZ': '023',
'Yavapai County, AZ': '025',
'Yuma County, AZ': '027'},
'05': { 'Arkansas County, AR': '001',
'Ashley County, AR': '003',
'Baxter County, AR': '005',
'Benton County, AR': '007',
'Boone County, AR': '009',
'Bradley County, AR': '011',
'Calhoun County, AR': '013',
'Carroll County, AR': '015',
'Chicot County, AR': '017',
'Clark County, AR': '019',
'Clay County, AR': '021',
'Cleburne County, AR': '023',
'Cleveland County, AR': '025',
'Columbia County, AR': '027',
'Conway County, AR': '029',
'Craighead County, AR': '031',
'Crawford County, AR': '033',
'Crittenden County, AR': '035',
'Cross County, AR': '037',
'Dallas County, AR': '039',
'Desha County, AR': '041',
'Drew County, AR': '043',
'Faulkner County, AR': '045',
'Franklin County, AR': '047',
'Fulton County, AR': '049',
'Garland County, AR': '051',
'Grant County, AR': '053',
'Greene County, AR': '055',
'Hempstead County, AR': '057',
'Hot Spring County, AR': '059',
'Howard County, AR': '061',
'Independence County, AR': '063',
'Izard County, AR': '065',
'Jackson County, AR': '067',
'Jefferson County, AR': '069',
'Johnson County, AR': '071',
'Lafayette County, AR': '073',
'Lawrence County, AR': '075',
'Lee County, AR': '077',
'Lincoln County, AR': '079',
'Little River County, AR': '081',
'Logan County, AR': '083',
'Lonoke County, AR': '085',
'Madison County, AR': '087',
'Marion County, AR': '089',
'Miller County, AR': '091',
'Mississippi County, AR': '093',
'Monroe County, AR': '095',
'Montgomery County, AR': '097',
'Nevada County, AR': '099',
'Newton County, AR': '101',
'Ouachita County, AR': '103',
'Perry County, AR': '105',
'Phillips County, AR': '107',
'Pike County, AR': '109',
'Poinsett County, AR': '111',
'Polk County, AR': '113',
'Pope County, AR': '115',
'Prairie County, AR': '117',
'Pulaski County, AR': '119',
'Randolph County, AR': '121',
'Saline County, AR': '125',
'Scott County, AR': '127',
'Searcy County, AR': '129',
'Sebastian County, AR': '131',
'Sevier County, AR': '133',
'Sharp County, AR': '135',
'St. Francis County, AR': '123',
'Stone County, AR': '137',
'Union County, AR': '139',
'Van Buren County, AR': '141',
'Washington County, AR': '143',
'White County, AR': '145',
'Woodruff County, AR': '147',
'Yell County, AR': '149'},
'06': { 'Alameda County, CA': '001',
'Alpine County, CA': '003',
'Amador County, CA': '005',
'Butte County, CA': '007',
'Calaveras County, CA': '009',
'Colusa County, CA': '011',
'Contra Costa County, CA': '013',
'Del Norte County, CA': '015',
'El Dorado County, CA': '017',
'Fresno County, CA': '019',
'Glenn County, CA': '021',
'Humboldt County, CA': '023',
'Imperial County, CA': '025',
'Inyo County, CA': '027',
'Kern County, CA': '029',
'Kings County, CA': '031',
'Lake County, CA': '033',
'Lassen County, CA': '035',
'Los Angeles County, CA': '037',
'Madera County, CA': '039',
'Marin County, CA': '041',
'Mariposa County, CA': '043',
'Mendocino County, CA': '045',
'Merced County, CA': '047',
'Modoc County, CA': '049',
'Mono County, CA': '051',
'Monterey County, CA': '053',
'Napa County, CA': '055',
'Nevada County, CA': '057',
'Orange County, CA': '059',
'Placer County, CA': '061',
'Plumas County, CA': '063',
'Riverside County, CA': '065',
'Sacramento County, CA': '067',
'San Benito County, CA': '069',
'San Bernardino County, CA': '071',
'San Diego County, CA': '073',
'San Francisco County/city, CA': '075',
'San Joaquin County, CA': '077',
'San Luis Obispo County, CA': '079',
'San Mateo County, CA': '081',
'Santa Barbara County, CA': '083',
'Santa Clara County, CA': '085',
'Santa Cruz County, CA': '087',
'Shasta County, CA': '089',
'Sierra County, CA': '091',
'Siskiyou County, CA': '093',
'Solano County, CA': '095',
'Sonoma County, CA': '097',
'Stanislaus County, CA': '099',
'Sutter County, CA': '101',
'Tehama County, CA': '103',
'Trinity County, CA': '105',
'Tulare County, CA': '107',
'Tuolumne County, CA': '109',
'Ventura County, CA': '111',
'Yolo County, CA': '113',
'Yuba County, CA': '115'},
'08': { 'Adams County, CO': '001',
'Alamosa County, CO': '003',
'Arapahoe County, CO': '005',
'Archuleta County, CO': '007',
'Baca County, CO': '009',
'Bent County, CO': '011',
'Boulder County, CO': '013',
'Broomfield County/city, CO': '014',
'Chaffee County, CO': '015',
'Cheyenne County, CO': '017',
'Clear Creek County, CO': '019',
'Conejos County, CO': '021',
'Costilla County, CO': '023',
'Crowley County, CO': '025',
'Custer County, CO': '027',
'Delta County, CO': '029',
'Denver County/city, CO': '031',
'Dolores County, CO': '033',
'Douglas County, CO': '035',
'Eagle County, CO': '037',
'El Paso County, CO': '041',
'Elbert County, CO': '039',
'Fremont County, CO': '043',
'Garfield County, CO': '045',
'Gilpin County, CO': '047',
'Grand County, CO': '049',
'Gunnison County, CO': '051',
'Hinsdale County, CO': '053',
'Huerfano County, CO': '055',
'Jackson County, CO': '057',
'Jefferson County, CO': '059',
'Kiowa County, CO': '061',
'Kit Carson County, CO': '063',
'La Plata County, CO': '067',
'Lake County, CO': '065',
'Larimer County, CO': '069',
'Las Animas County, CO': '071',
'Lincoln County, CO': '073',
'Logan County, CO': '075',
'Mesa County, CO': '077',
'Mineral County, CO': '079',
'Moffat County, CO': '081',
'Montezuma County, CO': '083',
'Montrose County, CO': '085',
'Morgan County, CO': '087',
'Otero County, CO': '089',
'Ouray County, CO': '091',
'Park County, CO': '093',
'Phillips County, CO': '095',
'Pitkin County, CO': '097',
'Prowers County, CO': '099',
'Pueblo County, CO': '101',
'Rio Blanco County, CO': '103',
'Rio Grande County, CO': '105',
'Routt County, CO': '107',
'Saguache County, CO': '109',
'San Juan County, CO': '111',
'San Miguel County, CO': '113',
'Sedgwick County, CO': '115',
'Summit County, CO': '117',
'Teller County, CO': '119',
'Washington County, CO': '121',
'Weld County, CO': '123',
'Yuma County, CO': '125'},
'09': { 'Fairfield County, CT': '001',
'Hartford County, CT': '003',
'Litchfield County, CT': '005',
'Middlesex County, CT': '007',
'New Haven County, CT': '009',
'New London County, CT': '011',
'Tolland County, CT': '013',
'Windham County, CT': '015'},
'10': { 'Kent County, DE': '001',
'New Castle County, DE': '003',
'Sussex County, DE': '005'},
'11': { 'District of Columbia': '001'},
'12': { 'Alachua County, FL': '001',
'Baker County, FL': '003',
'Bay County, FL': '005',
'Bradford County, FL': '007',
'Brevard County, FL': '009',
'Broward County, FL': '011',
'Calhoun County, FL': '013',
'Charlotte County, FL': '015',
'Citrus County, FL': '017',
'Clay County, FL': '019',
'Collier County, FL': '021',
'Columbia County, FL': '023',
'DeSoto County, FL': '027',
'Dixie County, FL': '029',
'Duval County, FL': '031',
'Escambia County, FL': '033',
'Flagler County, FL': '035',
'Franklin County, FL': '037',
'Gadsden County, FL': '039',
'Gilchrist County, FL': '041',
'Glades County, FL': '043',
'Gulf County, FL': '045',
'Hamilton County, FL': '047',
'Hardee County, FL': '049',
'Hendry County, FL': '051',
'Hernando County, FL': '053',
'Highlands County, FL': '055',
'Hillsborough County, FL': '057',
'Holmes County, FL': '059',
'Indian River County, FL': '061',
'Jackson County, FL': '063',
'Jefferson County, FL': '065',
'Lafayette County, FL': '067',
'Lake County, FL': '069',
'Lee County, FL': '071',
'Leon County, FL': '073',
'Levy County, FL': '075',
'Liberty County, FL': '077',
'Madison County, FL': '079',
'Manatee County, FL': '081',
'Marion County, FL': '083',
'Martin County, FL': '085',
'Miami-Dade County, FL': '086',
'Monroe County, FL': '087',
'Nassau County, FL': '089',
'Okaloosa County, FL': '091',
'Okeechobee County, FL': '093',
'Orange County, FL': '095',
'Osceola County, FL': '097',
'Palm Beach County, FL': '099',
'Pasco County, FL': '101',
'Pinellas County, FL': '103',
'Polk County, FL': '105',
'Putnam County, FL': '107',
'Santa Rosa County, FL': '113',
'Sarasota County, FL': '115',
'Seminole County, FL': '117',
'St. Johns County, FL': '109',
'St. Lucie County, FL': '111',
'Sumter County, FL': '119',
'Suwannee County, FL': '121',
'Taylor County, FL': '123',
'Union County, FL': '125',
'Volusia County, FL': '127',
'Wakulla County, FL': '129',
'Walton County, FL': '131',
'Washington County, FL': '133'},
'13': { 'Appling County, GA': '001',
'Atkinson County, GA': '003',
'Bacon County, GA': '005',
'Baker County, GA': '007',
'Baldwin County, GA': '009',
'Banks County, GA': '011',
'Barrow County, GA': '013',
'Bartow County, GA': '015',
'Ben Hill County, GA': '017',
'Berrien County, GA': '019',
'Bibb County, GA': '021',
'Bleckley County, GA': '023',
'Brantley County, GA': '025',
'Brooks County, GA': '027',
'Bryan County, GA': '029',
'Bulloch County, GA': '031',
'Burke County, GA': '033',
'Butts County, GA': '035',
'Calhoun County, GA': '037',
'Camden County, GA': '039',
'Candler County, GA': '043',
'Carroll County, GA': '045',
'Catoosa County, GA': '047',
'Charlton County, GA': '049',
'Chatham County, GA': '051',
'Chattahoochee County, GA': '053',
'Chattooga County, GA': '055',
'Cherokee County, GA': '057',
'Clarke County, GA': '059',
'Clay County, GA': '061',
'Clayton County, GA': '063',
'Clinch County, GA': '065',
'Cobb County, GA': '067',
'Coffee County, GA': '069',
'Colquitt County, GA': '071',
'Columbia County, GA': '073',
'Cook County, GA': '075',
'Coweta County, GA': '077',
'Crawford County, GA': '079',
'Crisp County, GA': '081',
'Dade County, GA': '083',
'Dawson County, GA': '085',
'DeKalb County, GA': '089',
'Decatur County, GA': '087',
'Dodge County, GA': '091',
'Dooly County, GA': '093',
'Dougherty County, GA': '095',
'Douglas County, GA': '097',
'Early County, GA': '099',
'Echols County, GA': '101',
'Effingham County, GA': '103',
'Elbert County, GA': '105',
'Emanuel County, GA': '107',
'Evans County, GA': '109',
'Fannin County, GA': '111',
'Fayette County, GA': '113',
'Floyd County, GA': '115',
'Forsyth County, GA': '117',
'Franklin County, GA': '119',
'Fulton County, GA': '121',
'Gilmer County, GA': '123',
'Glascock County, GA': '125',
'Glynn County, GA': '127',
'Gordon County, GA': '129',
'Grady County, GA': '131',
'Greene County, GA': '133',
'Gwinnett County, GA': '135',
'Habersham County, GA': '137',
'Hall County, GA': '139',
'Hancock County, GA': '141',
'Haralson County, GA': '143',
'Harris County, GA': '145',
'Hart County, GA': '147',
'Heard County, GA': '149',
'Henry County, GA': '151',
'Houston County, GA': '153',
'Irwin County, GA': '155',
'Jackson County, GA': '157',
'Jasper County, GA': '159',
'Jeff Davis County, GA': '161',
'Jefferson County, GA': '163',
'Jenkins County, GA': '165',
'Johnson County, GA': '167',
'Jones County, GA': '169',
'Lamar County, GA': '171',
'Lanier County, GA': '173',
'Laurens County, GA': '175',
'Lee County, GA': '177',
'Liberty County, GA': '179',
'Lincoln County, GA': '181',
'Long County, GA': '183',
'Lowndes County, GA': '185',
'Lumpkin County, GA': '187',
'Macon County, GA': '193',
'Madison County, GA': '195',
'Marion County, GA': '197',
'McDuffie County, GA': '189',
'McIntosh County, GA': '191',
'Meriwether County, GA': '199',
'Miller County, GA': '201',
'Mitchell County, GA': '205',
'Monroe County, GA': '207',
'Montgomery County, GA': '209',
'Morgan County, GA': '211',
'Murray County, GA': '213',
'Muscogee County, GA': '215',
'Newton County, GA': '217',
'Oconee County, GA': '219',
'Oglethorpe County, GA': '221',
'Paulding County, GA': '223',
'Peach County, GA': '225',
'Pickens County, GA': '227',
'Pierce County, GA': '229',
'Pike County, GA': '231',
'Polk County, GA': '233',
'Pulaski County, GA': '235',
'Putnam County, GA': '237',
'Quitman County, GA': '239',
'Rabun County, GA': '241',
'Randolph County, GA': '243',
'Richmond County, GA': '245',
'Rockdale County, GA': '247',
'Schley County, GA': '249',
'Screven County, GA': '251',
'Seminole County, GA': '253',
'Spalding County, GA': '255',
'Stephens County, GA': '257',
'Stewart County, GA': '259',
'Sumter County, GA': '261',
'Talbot County, GA': '263',
'Taliaferro County, GA': '265',
'Tattnall County, GA': '267',
'Taylor County, GA': '269',
'Telfair County, GA': '271',
'Terrell County, GA': '273',
'Thomas County, GA': '275',
'Tift County, GA': '277',
'Toombs County, GA': '279',
'Towns County, GA': '281',
'Treutlen County, GA': '283',
'Troup County, GA': '285',
'Turner County, GA': '287',
'Twiggs County, GA': '289',
'Union County, GA': '291',
'Upson County, GA': '293',
'Walker County, GA': '295',
'Walton County, GA': '297',
'Ware County, GA': '299',
'Warren County, GA': '301',
'Washington County, GA': '303',
'Wayne County, GA': '305',
'Webster County, GA': '307',
'Wheeler County, GA': '309',
'White County, GA': '311',
'Whitfield County, GA': '313',
'Wilcox County, GA': '315',
'Wilkes County, GA': '317',
'Wilkinson County, GA': '319',
'Worth County, GA': '321'},
'15': { 'Hawaii County, HI': '001',
'Honolulu County/city, HI': '003',
'Kauai County, HI': '007',
'Maui County, HI': '009'},
'16': { 'Ada County, ID': '001',
'Adams County, ID': '003',
'Bannock County, ID': '005',
'Bear Lake County, ID': '007',
'Benewah County, ID': '009',
'Bingham County, ID': '011',
'Blaine County, ID': '013',
'Boise County, ID': '015',
'Bonner County, ID': '017',
'Bonneville County, ID': '019',
'Boundary County, ID': '021',
'Butte County, ID': '023',
'Camas County, ID': '025',
'Canyon County, ID': '027',
'Caribou County, ID': '029',
'Cassia County, ID': '031',
'Clark County, ID': '033',
'Clearwater County, ID': '035',
'Custer County, ID': '037',
'Elmore County, ID': '039',
'Franklin County, ID': '041',
'Fremont County, ID': '043',
'Gem County, ID': '045',
'Gooding County, ID': '047',
'Idaho County, ID': '049',
'Jefferson County, ID': '051',
'Jerome County, ID': '053',
'Kootenai County, ID': '055',
'Latah County, ID': '057',
'Lemhi County, ID': '059',
'Lewis County, ID': '061',
'Lincoln County, ID': '063',
'Madison County, ID': '065',
'Minidoka County, ID': '067',
'Nez Perce County, ID': '069',
'Oneida County, ID': '071',
'Owyhee County, ID': '073',
'Payette County, ID': '075',
'Power County, ID': '077',
'Shoshone County, ID': '079',
'Teton County, ID': '081',
'Twin Falls County, ID': '083',
'Valley County, ID': '085',
'Washington County, ID': '087'},
'17': { 'Adams County, IL': '001',
'Alexander County, IL': '003',
'Bond County, IL': '005',
'Boone County, IL': '007',
'Brown County, IL': '009',
'Bureau County, IL': '011',
'Calhoun County, IL': '013',
'Carroll County, IL': '015',
'Cass County, IL': '017',
'Champaign County, IL': '019',
'Christian County, IL': '021',
'Clark County, IL': '023',
'Clay County, IL': '025',
'Clinton County, IL': '027',
'Coles County, IL': '029',
'Cook County, IL': '031',
'Crawford County, IL': '033',
'Cumberland County, IL': '035',
'De Witt County, IL': '039',
'DeKalb County, IL': '037',
'Douglas County, IL': '041',
'DuPage County, IL': '043',
'Edgar County, IL': '045',
'Edwards County, IL': '047',
'Effingham County, IL': '049',
'Fayette County, IL': '051',
'Ford County, IL': '053',
'Franklin County, IL': '055',
'Fulton County, IL': '057',
'Gallatin County, IL': '059',
'Greene County, IL': '061',
'Grundy County, IL': '063',
'Hamilton County, IL': '065',
'Hancock County, IL': '067',
'Hardin County, IL': '069',
'Henderson County, IL': '071',
'Henry County, IL': '073',
'Iroquois County, IL': '075',
'Jackson County, IL': '077',
'Jasper County, IL': '079',
'Jefferson County, IL': '081',
'Jersey County, IL': '083',
'Jo Daviess County, IL': '085',
'Johnson County, IL': '087',
'Kane County, IL': '089',
'Kankakee County, IL': '091',
'Kendall County, IL': '093',
'Knox County, IL': '095',
'La Salle County, IL': '099',
'Lake County, IL': '097',
'Lawrence County, IL': '101',
'Lee County, IL': '103',
'Livingston County, IL': '105',
'Logan County, IL': '107',
'Macon County, IL': '115',
'Macoupin County, IL': '117',
'Madison County, IL': '119',
'Marion County, IL': '121',
'Marshall County, IL': '123',
'Mason County, IL': '125',
'Massac County, IL': '127',
'McDonough County, IL': '109',
'McHenry County, IL': '111',
'McLean County, IL': '113',
'Menard County, IL': '129',
'Mercer County, IL': '131',
'Monroe County, IL': '133',
'Montgomery County, IL': '135',
'Morgan County, IL': '137',
'Moultrie County, IL': '139',
'Ogle County, IL': '141',
'Peoria County, IL': '143',
'Perry County, IL': '145',
'Piatt County, IL': '147',
'Pike County, IL': '149',
'Pope County, IL': '151',
'Pulaski County, IL': '153',
'Putnam County, IL': '155',
'Randolph County, IL': '157',
'Richland County, IL': '159',
'Rock Island County, IL': '161',
'Saline County, IL': '165',
'Sangamon County, IL': '167',
'Schuyler County, IL': '169',
'Scott County, IL': '171',
'Shelby County, IL': '173',
'St. Clair County, IL': '163',
'Stark County, IL': '175',
'Stephenson County, IL': '177',
'Tazewell County, IL': '179',
'Union County, IL': '181',
'Vermilion County, IL': '183',
'Wabash County, IL': '185',
'Warren County, IL': '187',
'Washington County, IL': '189',
'Wayne County, IL': '191',
'White County, IL': '193',
'Whiteside County, IL': '195',
'Will County, IL': '197',
'Williamson County, IL': '199',
'Winnebago County, IL': '201',
'Woodford County, IL': '203'},
'18': { 'Adams County, IN': '001',
'Allen County, IN': '003',
'Bartholomew County, IN': '005',
'Benton County, IN': '007',
'Blackford County, IN': '009',
'Boone County, IN': '011',
'Brown County, IN': '013',
'Carroll County, IN': '015',
'Cass County, IN': '017',
'Clark County, IN': '019',
'Clay County, IN': '021',
'Clinton County, IN': '023',
'Crawford County, IN': '025',
'Daviess County, IN': '027',
'DeKalb County, IN': '033',
'Dearborn County, IN': '029',
'Decatur County, IN': '031',
'Delaware County, IN': '035',
'Dubois County, IN': '037',
'Elkhart County, IN': '039',
'Fayette County, IN': '041',
'Floyd County, IN': '043',
'Fountain County, IN': '045',
'Franklin County, IN': '047',
'Fulton County, IN': '049',
'Gibson County, IN': '051',
'Grant County, IN': '053',
'Greene County, IN': '055',
'Hamilton County, IN': '057',
'Hancock County, IN': '059',
'Harrison County, IN': '061',
'Hendricks County, IN': '063',
'Henry County, IN': '065',
'Howard County, IN': '067',
'Huntington County, IN': '069',
'Jackson County, IN': '071',
'Jasper County, IN': '073',
'Jay County, IN': '075',
'Jefferson County, IN': '077',
'Jennings County, IN': '079',
'Johnson County, IN': '081',
'Knox County, IN': '083',
'Kosciusko County, IN': '085',
'LaGrange County, IN': '087',
'LaPorte County, IN': '091',
'Lake County, IN': '089',
'Lawrence County, IN': '093',
'Madison County, IN': '095',
'Marion County, IN': '097',
'Marshall County, IN': '099',
'Martin County, IN': '101',
'Miami County, IN': '103',
'Monroe County, IN': '105',
'Montgomery County, IN': '107',
'Morgan County, IN': '109',
'Newton County, IN': '111',
'Noble County, IN': '113',
'Ohio County, IN': '115',
'Orange County, IN': '117',
'Owen County, IN': '119',
'Parke County, IN': '121',
'Perry County, IN': '123',
'Pike County, IN': '125',
'Porter County, IN': '127',
'Posey County, IN': '129',
'Pulaski County, IN': '131',
'Putnam County, IN': '133',
'Randolph County, IN': '135',
'Ripley County, IN': '137',
'Rush County, IN': '139',
'Scott County, IN': '143',
'Shelby County, IN': '145',
'Spencer County, IN': '147',
'St. Joseph County, IN': '141',
'Starke County, IN': '149',
'Steuben County, IN': '151',
'Sullivan County, IN': '153',
'Switzerland County, IN': '155',
'Tippecanoe County, IN': '157',
'Tipton County, IN': '159',
'Union County, IN': '161',
'Vanderburgh County, IN': '163',
'Vermillion County, IN': '165',
'Vigo County, IN': '167',
'Wabash County, IN': '169',
'Warren County, IN': '171',
'Warrick County, IN': '173',
'Washington County, IN': '175',
'Wayne County, IN': '177',
'Wells County, IN': '179',
'White County, IN': '181',
'Whitley County, IN': '183'},
'19': { 'Adair County, IA': '001',
'Adams County, IA': '003',
'Allamakee County, IA': '005',
'Appanoose County, IA': '007',
'Audubon County, IA': '009',
'Benton County, IA': '011',
'Black Hawk County, IA': '013',
'Boone County, IA': '015',
'Bremer County, IA': '017',
'Buchanan County, IA': '019',
'Buena Vista County, IA': '021',
'Butler County, IA': '023',
'Calhoun County, IA': '025',
'Carroll County, IA': '027',
'Cass County, IA': '029',
'Cedar County, IA': '031',
'Cerro Gordo County, IA': '033',
'Cherokee County, IA': '035',
'Chickasaw County, IA': '037',
'Clarke County, IA': '039',
'Clay County, IA': '041',
'Clayton County, IA': '043',
'Clinton County, IA': '045',
'Crawford County, IA': '047',
'Dallas County, IA': '049',
'Davis County, IA': '051',
'Decatur County, IA': '053',
'Delaware County, IA': '055',
'Des Moines County, IA': '057',
'Dickinson County, IA': '059',
'Dubuque County, IA': '061',
'Emmet County, IA': '063',
'Fayette County, IA': '065',
'Floyd County, IA': '067',
'Franklin County, IA': '069',
'Fremont County, IA': '071',
'Greene County, IA': '073',
'Grundy County, IA': '075',
'Guthrie County, IA': '077',
'Hamilton County, IA': '079',
'Hancock County, IA': '081',
'Hardin County, IA': '083',
'Harrison County, IA': '085',
'Henry County, IA': '087',
'Howard County, IA': '089',
'Humboldt County, IA': '091',
'Ida County, IA': '093',
'Iowa County, IA': '095',
'Jackson County, IA': '097',
'Jasper County, IA': '099',
'Jefferson County, IA': '101',
'Johnson County, IA': '103',
'Jones County, IA': '105',
'Keokuk County, IA': '107',
'Kossuth County, IA': '109',
'Lee County, IA': '111',
'Linn County, IA': '113',
'Louisa County, IA': '115',
'Lucas County, IA': '117',
'Lyon County, IA': '119',
'Madison County, IA': '121',
'Mahaska County, IA': '123',
'Marion County, IA': '125',
'Marshall County, IA': '127',
'Mills County, IA': '129',
'Mitchell County, IA': '131',
'Monona County, IA': '133',
'Monroe County, IA': '135',
'Montgomery County, IA': '137',
'Muscatine County, IA': '139',
"O'Brien County, IA": '141',
'Osceola County, IA': '143',
'Page County, IA': '145',
'Palo Alto County, IA': '147',
'Plymouth County, IA': '149',
'Pocahontas County, IA': '151',
'Polk County, IA': '153',
'Pottawattamie County, IA': '155',
'Poweshiek County, IA': '157',
'Ringgold County, IA': '159',
'Sac County, IA': '161',
'Scott County, IA': '163',
'Shelby County, IA': '165',
'Sioux County, IA': '167',
'Story County, IA': '169',
'Tama County, IA': '171',
'Taylor County, IA': '173',
'Union County, IA': '175',
'Van Buren County, IA': '177',
'Wapello County, IA': '179',
'Warren County, IA': '181',
'Washington County, IA': '183',
'Wayne County, IA': '185',
'Webster County, IA': '187',
'Winnebago County, IA': '189',
'Winneshiek County, IA': '191',
'Woodbury County, IA': '193',
'Worth County, IA': '195',
'Wright County, IA': '197'},
'20': { 'Allen County, KS': '001',
'Anderson County, KS': '003',
'Atchison County, KS': '005',
'Barber County, KS': '007',
'Barton County, KS': '009',
'Bourbon County, KS': '011',
'Brown County, KS': '013',
'Butler County, KS': '015',
'Chase County, KS': '017',
'Chautauqua County, KS': '019',
'Cherokee County, KS': '021',
'Cheyenne County, KS': '023',
'Clark County, KS': '025',
'Clay County, KS': '027',
'Cloud County, KS': '029',
'Coffey County, KS': '031',
'Comanche County, KS': '033',
'Cowley County, KS': '035',
'Crawford County, KS': '037',
'Decatur County, KS': '039',
'Dickinson County, KS': '041',
'Doniphan County, KS': '043',
'Douglas County, KS': '045',
'Edwards County, KS': '047',
'Elk County, KS': '049',
'Ellis County, KS': '051',
'Ellsworth County, KS': '053',
'Finney County, KS': '055',
'Ford County, KS': '057',
'Franklin County, KS': '059',
'Geary County, KS': '061',
'Gove County, KS': '063',
'Graham County, KS': '065',
'Grant County, KS': '067',
'Gray County, KS': '069',
'Greeley County, KS': '071',
'Greenwood County, KS': '073',
'Hamilton County, KS': '075',
'Harper County, KS': '077',
'Harvey County, KS': '079',
'Haskell County, KS': '081',
'Hodgeman County, KS': '083',
'Jackson County, KS': '085',
'Jefferson County, KS': '087',
'Jewell County, KS': '089',
'Johnson County, KS': '091',
'Kearny County, KS': '093',
'Kingman County, KS': '095',
'Kiowa County, KS': '097',
'Labette County, KS': '099',
'Lane County, KS': '101',
'Leavenworth County, KS': '103',
'Lincoln County, KS': '105',
'Linn County, KS': '107',
'Logan County, KS': '109',
'Lyon County, KS': '111',
'Marion County, KS': '115',
'Marshall County, KS': '117',
'McPherson County, KS': '113',
'Meade County, KS': '119',
'Miami County, KS': '121',
'Mitchell County, KS': '123',
'Montgomery County, KS': '125',
'Morris County, KS': '127',
'Morton County, KS': '129',
'Nemaha County, KS': '131',
'Neosho County, KS': '133',
'Ness County, KS': '135',
'Norton County, KS': '137',
'Osage County, KS': '139',
'Osborne County, KS': '141',
'Ottawa County, KS': '143',
'Pawnee County, KS': '145',
'Phillips County, KS': '147',
'Pottawatomie County, KS': '149',
'Pratt County, KS': '151',
'Rawlins County, KS': '153',
'Reno County, KS': '155',
'Republic County, KS': '157',
'Rice County, KS': '159',
'Riley County, KS': '161',
'Rooks County, KS': '163',
'Rush County, KS': '165',
'Russell County, KS': '167',
'Saline County, KS': '169',
'Scott County, KS': '171',
'Sedgwick County, KS': '173',
'Seward County, KS': '175',
'Shawnee County, KS': '177',
'Sheridan County, KS': '179',
'Sherman County, KS': '181',
'Smith County, KS': '183',
'Stafford County, KS': '185',
'Stanton County, KS': '187',
'Stevens County, KS': '189',
'Sumner County, KS': '191',
'Thomas County, KS': '193',
'Trego County, KS': '195',
'Wabaunsee County, KS': '197',
'Wallace County, KS': '199',
'Washington County, KS': '201',
'Wichita County, KS': '203',
'Wilson County, KS': '205',
'Woodson County, KS': '207',
'Wyandotte County, KS': '209'},
'21': { 'Adair County, KY': '001',
'Allen County, KY': '003',
'Anderson County, KY': '005',
'Ballard County, KY': '007',
'Barren County, KY': '009',
'Bath County, KY': '011',
'Bell County, KY': '013',
'Boone County, KY': '015',
'Bourbon County, KY': '017',
'Boyd County, KY': '019',
'Boyle County, KY': '021',
'Bracken County, KY': '023',
'Breathitt County, KY': '025',
'Breckinridge County, KY': '027',
'Bullitt County, KY': '029',
'Butler County, KY': '031',
'Caldwell County, KY': '033',
'Calloway County, KY': '035',
'Campbell County, KY': '037',
'Carlisle County, KY': '039',
'Carroll County, KY': '041',
'Carter County, KY': '043',
'Casey County, KY': '045',
'Christian County, KY': '047',
'Clark County, KY': '049',
'Clay County, KY': '051',
'Clinton County, KY': '053',
'Crittenden County, KY': '055',
'Cumberland County, KY': '057',
'Daviess County, KY': '059',
'Edmonson County, KY': '061',
'Elliott County, KY': '063',
'Estill County, KY': '065',
'Fayette County, KY': '067',
'Fleming County, KY': '069',
'Floyd County, KY': '071',
'Franklin County, KY': '073',
'Fulton County, KY': '075',
'Gallatin County, KY': '077',
'Garrard County, KY': '079',
'Grant County, KY': '081',
'Graves County, KY': '083',
'Grayson County, KY': '085',
'Green County, KY': '087',
'Greenup County, KY': '089',
'Hancock County, KY': '091',
'Hardin County, KY': '093',
'Harlan County, KY': '095',
'Harrison County, KY': '097',
'Hart County, KY': '099',
'Henderson County, KY': '101',
'Henry County, KY': '103',
'Hickman County, KY': '105',
'Hopkins County, KY': '107',
'Jackson County, KY': '109',
'Jefferson County, KY': '111',
'Jessamine County, KY': '113',
'Johnson County, KY': '115',
'Kenton County, KY': '117',
'Knott County, KY': '119',
'Knox County, KY': '121',
'Larue County, KY': '123',
'Laurel County, KY': '125',
'Lawrence County, KY': '127',
'Lee County, KY': '129',
'Leslie County, KY': '131',
'Letcher County, KY': '133',
'Lewis County, KY': '135',
'Lincoln County, KY': '137',
'Livingston County, KY': '139',
'Logan County, KY': '141',
'Lyon County, KY': '143',
'Madison County, KY': '151',
'Magoffin County, KY': '153',
'Marion County, KY': '155',
'Marshall County, KY': '157',
'Martin County, KY': '159',
'Mason County, KY': '161',
'McCracken County, KY': '145',
'McCreary County, KY': '147',
'McLean County, KY': '149',
'Meade County, KY': '163',
'Menifee County, KY': '165',
'Mercer County, KY': '167',
'Metcalfe County, KY': '169',
'Monroe County, KY': '171',
'Montgomery County, KY': '173',
'Morgan County, KY': '175',
'Muhlenberg County, KY': '177',
'Nelson County, KY': '179',
'Nicholas County, KY': '181',
'Ohio County, KY': '183',
'Oldham County, KY': '185',
'Owen County, KY': '187',
'Owsley County, KY': '189',
'Pendleton County, KY': '191',
'Perry County, KY': '193',
'Pike County, KY': '195',
'Powell County, KY': '197',
'Pulaski County, KY': '199',
'Robertson County, KY': '201',
'Rockcastle County, KY': '203',
'Rowan County, KY': '205',
'Russell County, KY': '207',
'Scott County, KY': '209',
'Shelby County, KY': '211',
'Simpson County, KY': '213',
'Spencer County, KY': '215',
'Taylor County, KY': '217',
'Todd County, KY': '219',
'Trigg County, KY': '221',
'Trimble County, KY': '223',
'Union County, KY': '225',
'Warren County, KY': '227',
'Washington County, KY': '229',
'Wayne County, KY': '231',
'Webster County, KY': '233',
'Whitley County, KY': '235',
'Wolfe County, KY': '237',
'Woodford County, KY': '239'},
'22': { 'Acadia Parish, LA': '001',
'Allen Parish, LA': '003',
'Ascension Parish, LA': '005',
'Assumption Parish, LA': '007',
'Avoyelles Parish, LA': '009',
'Beauregard Parish, LA': '011',
'Bienville Parish, LA': '013',
'Bossier Parish, LA': '015',
'Caddo Parish, LA': '017',
'Calcasieu Parish, LA': '019',
'Caldwell Parish, LA': '021',
'Cameron Parish, LA': '023',
'Catahoula Parish, LA': '025',
'Claiborne Parish, LA': '027',
'Concordia Parish, LA': '029',
'De Soto Parish, LA': '031',
'East Baton Rouge Parish, LA': '033',
'East Carroll Parish, LA': '035',
'East Feliciana Parish, LA': '037',
'Evangeline Parish, LA': '039',
'Franklin Parish, LA': '041',
'Grant Parish, LA': '043',
'Iberia Parish, LA': '045',
'Iberville Parish, LA': '047',
'Jackson Parish, LA': '049',
'Jefferson Davis Parish, LA': '053',
'Jefferson Parish, LA': '051',
'La Salle Parish, LA': '059',
'Lafayette Parish, LA': '055',
'Lafourche Parish, LA': '057',
'Lincoln Parish, LA': '061',
'Livingston Parish, LA': '063',
'Madison Parish, LA': '065',
'Morehouse Parish, LA': '067',
'Natchitoches Parish, LA': '069',
'Orleans Parish, LA': '071',
'Ouachita Parish, LA': '073',
'Plaquemines Parish, LA': '075',
'Pointe Coupee Parish, LA': '077',
'Rapides Parish, LA': '079',
'Red River Parish, LA': '081',
'Richland Parish, LA': '083',
'Sabine Parish, LA': '085',
'St. Bernard Parish, LA': '087',
'St. Charles Parish, LA': '089',
'St. Helena Parish, LA': '091',
'St. James Parish, LA': '093',
'St. John the Baptist Parish, LA': '095',
'St. Landry Parish, LA': '097',
'St. Martin Parish, LA': '099',
'St. Mary Parish, LA': '101',
'St. Tammany Parish, LA': '103',
'Tangipahoa Parish, LA': '105',
'Tensas Parish, LA': '107',
'Terrebonne Parish, LA': '109',
'Union Parish, LA': '111',
'Vermilion Parish, LA': '113',
'Vernon Parish, LA': '115',
'Washington Parish, LA': '117',
'Webster Parish, LA': '119',
'West Baton Rouge Parish, LA': '121',
'West Carroll Parish, LA': '123',
'West Feliciana Parish, LA': '125',
'Winn Parish, LA': '127'},
'23': { 'Androscoggin County, ME': '001',
'Aroostook County, ME': '003',
'Cumberland County, ME': '005',
'Franklin County, ME': '007',
'Hancock County, ME': '009',
'Kennebec County, ME': '011',
'Knox County, ME': '013',
'Lincoln County, ME': '015',
'Oxford County, ME': '017',
'Penobscot County, ME': '019',
'Piscataquis County, ME': '021',
'Sagadahoc County, ME': '023',
'Somerset County, ME': '025',
'Waldo County, ME': '027',
'Washington County, ME': '029',
'York County, ME': '031'},
'24': { 'Allegany County, MD': '001',
'Anne Arundel County, MD': '003',
'Baltimore County, MD': '005',
'Baltimore city, MD': '510',
'Calvert County, MD': '009',
'Caroline County, MD': '011',
'Carroll County, MD': '013',
'Cecil County, MD': '015',
'Charles County, MD': '017',
'Dorchester County, MD': '019',
'Frederick County, MD': '021',
'Garrett County, MD': '023',
'Harford County, MD': '025',
'Howard County, MD': '027',
'Kent County, MD': '029',
'Montgomery County, MD': '031',
"Prince George's County, MD": '033',
"Queen Anne's County, MD": '035',
'Somerset County, MD': '039',
"St. Mary's County, MD": '037',
'Talbot County, MD': '041',
'Washington County, MD': '043',
'Wicomico County, MD': '045',
'Worcester County, MD': '047'},
'25': { 'Barnstable County, MA': '001',
'Berkshire County, MA': '003',
'Bristol County, MA': '005',
'Dukes County, MA': '007',
'Essex County, MA': '009',
'Franklin County, MA': '011',
'Hampden County, MA': '013',
'Hampshire County, MA': '015',
'Middlesex County, MA': '017',
'Nantucket County/town, MA': '019',
'Norfolk County, MA': '021',
'Plymouth County, MA': '023',
'Suffolk County, MA': '025',
'Worcester County, MA': '027'},
'26': { 'Alcona County, MI': '001',
'Alger County, MI': '003',
'Allegan County, MI': '005',
'Alpena County, MI': '007',
'Antrim County, MI': '009',
'Arenac County, MI': '011',
'Baraga County, MI': '013',
'Barry County, MI': '015',
'Bay County, MI': '017',
'Benzie County, MI': '019',
'Berrien County, MI': '021',
'Branch County, MI': '023',
'Calhoun County, MI': '025',
'Cass County, MI': '027',
'Charlevoix County, MI': '029',
'Cheboygan County, MI': '031',
'Chippewa County, MI': '033',
'Clare County, MI': '035',
'Clinton County, MI': '037',
'Crawford County, MI': '039',
'Delta County, MI': '041',
'Dickinson County, MI': '043',
'Eaton County, MI': '045',
'Emmet County, MI': '047',
'Genesee County, MI': '049',
'Gladwin County, MI': '051',
'Gogebic County, MI': '053',
'Grand Traverse County, MI': '055',
'Gratiot County, MI': '057',
'Hillsdale County, MI': '059',
'Houghton County, MI': '061',
'Huron County, MI': '063',
'Ingham County, MI': '065',
'Ionia County, MI': '067',
'Iosco County, MI': '069',
'Iron County, MI': '071',
'Isabella County, MI': '073',
'Jackson County, MI': '075',
'Kalamazoo County, MI': '077',
'Kalkaska County, MI': '079',
'Kent County, MI': '081',
'Keweenaw County, MI': '083',
'Lake County, MI': '085',
'Lapeer County, MI': '087',
'Leelanau County, MI': '089',
'Lenawee County, MI': '091',
'Livingston County, MI': '093',
'Luce County, MI': '095',
'Mackinac County, MI': '097',
'Macomb County, MI': '099',
'Manistee County, MI': '101',
'Marquette County, MI': '103',
'Mason County, MI': '105',
'Mecosta County, MI': '107',
'Menominee County, MI': '109',
'Midland County, MI': '111',
'Missaukee County, MI': '113',
'Monroe County, MI': '115',
'Montcalm County, MI': '117',
'Montmorency County, MI': '119',
'Muskegon County, MI': '121',
'Newaygo County, MI': '123',
'Oakland County, MI': '125',
'Oceana County, MI': '127',
'Ogemaw County, MI': '129',
'Ontonagon County, MI': '131',
'Osceola County, MI': '133',
'Oscoda County, MI': '135',
'Otsego County, MI': '137',
'Ottawa County, MI': '139',
'Presque Isle County, MI': '141',
'Roscommon County, MI': '143',
'Saginaw County, MI': '145',
'Sanilac County, MI': '151',
'Schoolcraft County, MI': '153',
'Shiawassee County, MI': '155',
'St. Clair County, MI': '147',
'St. Joseph County, MI': '149',
'Tuscola County, MI': '157',
'Van Buren County, MI': '159',
'Washtenaw County, MI': '161',
'Wayne County, MI': '163',
'Wexford County, MI': '165'},
'27': { 'Aitkin County, MN': '001',
'Anoka County, MN': '003',
'Becker County, MN': '005',
'Beltrami County, MN': '007',
'Benton County, MN': '009',
'Big Stone County, MN': '011',
'Blue Earth County, MN': '013',
'Brown County, MN': '015',
'Carlton County, MN': '017',
'Carver County, MN': '019',
'Cass County, MN': '021',
'Chippewa County, MN': '023',
'Chisago County, MN': '025',
'Clay County, MN': '027',
'Clearwater County, MN': '029',
'Cook County, MN': '031',
'Cottonwood County, MN': '033',
'Crow Wing County, MN': '035',
'Dakota County, MN': '037',
'Dodge County, MN': '039',
'Douglas County, MN': '041',
'Faribault County, MN': '043',
'Fillmore County, MN': '045',
'Freeborn County, MN': '047',
'Goodhue County, MN': '049',
'Grant County, MN': '051',
'Hennepin County, MN': '053',
'Houston County, MN': '055',
'Hubbard County, MN': '057',
'Isanti County, MN': '059',
'Itasca County, MN': '061',
'Jackson County, MN': '063',
'Kanabec County, MN': '065',
'Kandiyohi County, MN': '067',
'Kittson County, MN': '069',
'Koochiching County, MN': '071',
'Lac qui Parle County, MN': '073',
'Lake County, MN': '075',
'Lake of the Woods County, MN': '077',
'Le Sueur County, MN': '079',
'Lincoln County, MN': '081',
'Lyon County, MN': '083',
'Mahnomen County, MN': '087',
'Marshall County, MN': '089',
'Martin County, MN': '091',
'McLeod County, MN': '085',
'Meeker County, MN': '093',
'Mille Lacs County, MN': '095',
'Morrison County, MN': '097',
'Mower County, MN': '099',
'Murray County, MN': '101',
'Nicollet County, MN': '103',
'Nobles County, MN': '105',
'Norman County, MN': '107',
'Olmsted County, MN': '109',
'Otter Tail County, MN': '111',
'Pennington County, MN': '113',
'Pine County, MN': '115',
'Pipestone County, MN': '117',
'Polk County, MN': '119',
'Pope County, MN': '121',
'Ramsey County, MN': '123',
'Red Lake County, MN': '125',
'Redwood County, MN': '127',
'Renville County, MN': '129',
'Rice County, MN': '131',
'Rock County, MN': '133',
'Roseau County, MN': '135',
'Scott County, MN': '139',
'Sherburne County, MN': '141',
'Sibley County, MN': '143',
'St. Louis County, MN': '137',
'Stearns County, MN': '145',
'Steele County, MN': '147',
'Stevens County, MN': '149',
'Swift County, MN': '151',
'Todd County, MN': '153',
'Traverse County, MN': '155',
'Wabasha County, MN': '157',
'Wadena County, MN': '159',
'Waseca County, MN': '161',
'Washington County, MN': '163',
'Watonwan County, MN': '165',
'Wilkin County, MN': '167',
'Winona County, MN': '169',
'Wright County, MN': '171',
'Yellow Medicine County, MN': '173'},
'28': { 'Adams County, MS': '001',
'Alcorn County, MS': '003',
'Amite County, MS': '005',
'Attala County, MS': '007',
'Benton County, MS': '009',
'Bolivar County, MS': '011',
'Calhoun County, MS': '013',
'Carroll County, MS': '015',
'Chickasaw County, MS': '017',
'Choctaw County, MS': '019',
'Claiborne County, MS': '021',
'Clarke County, MS': '023',
'Clay County, MS': '025',
'Coahoma County, MS': '027',
'Copiah County, MS': '029',
'Covington County, MS': '031',
'DeSoto County, MS': '033',
'Forrest County, MS': '035',
'Franklin County, MS': '037',
'George County, MS': '039',
'Greene County, MS': '041',
'Grenada County, MS': '043',
'Hancock County, MS': '045',
'Harrison County, MS': '047',
'Hinds County, MS': '049',
'Holmes County, MS': '051',
'Humphreys County, MS': '053',
'Issaquena County, MS': '055',
'Itawamba County, MS': '057',
'Jackson County, MS': '059',
'Jasper County, MS': '061',
'Jefferson County, MS': '063',
'Jefferson Davis County, MS': '065',
'Jones County, MS': '067',
'Kemper County, MS': '069',
'Lafayette County, MS': '071',
'Lamar County, MS': '073',
'Lauderdale County, MS': '075',
'Lawrence County, MS': '077',
'Leake County, MS': '079',
'Lee County, MS': '081',
'Leflore County, MS': '083',
'Lincoln County, MS': '085',
'Lowndes County, MS': '087',
'Madison County, MS': '089',
'Marion County, MS': '091',
'Marshall County, MS': '093',
'Monroe County, MS': '095',
'Montgomery County, MS': '097',
'Neshoba County, MS': '099',
'Newton County, MS': '101',
'Noxubee County, MS': '103',
'Oktibbeha County, MS': '105',
'Panola County, MS': '107',
'Pearl River County, MS': '109',
'Perry County, MS': '111',
'Pike County, MS': '113',
'Pontotoc County, MS': '115',
'Prentiss County, MS': '117',
'Quitman County, MS': '119',
'Rankin County, MS': '121',
'Scott County, MS': '123',
'Sharkey County, MS': '125',
'Simpson County, MS': '127',
'Smith County, MS': '129',
'Stone County, MS': '131',
'Sunflower County, MS': '133',
'Tallahatchie County, MS': '135',
'Tate County, MS': '137',
'Tippah County, MS': '139',
'Tishomingo County, MS': '141',
'Tunica County, MS': '143',
'Union County, MS': '145',
'Walthall County, MS': '147',
'Warren County, MS': '149',
'Washington County, MS': '151',
'Wayne County, MS': '153',
'Webster County, MS': '155',
'Wilkinson County, MS': '157',
'Winston County, MS': '159',
'Yalobusha County, MS': '161',
'Yazoo County, MS': '163'},
'29': { 'Adair County, MO': '001',
'Andrew County, MO': '003',
'Atchison County, MO': '005',
'Audrain County, MO': '007',
'Barry County, MO': '009',
'Barton County, MO': '011',
'Bates County, MO': '013',
'Benton County, MO': '015',
'Bollinger County, MO': '017',
'Boone County, MO': '019',
'Buchanan County, MO': '021',
'Butler County, MO': '023',
'Caldwell County, MO': '025',
'Callaway County, MO': '027',
'Camden County, MO': '029',
'Cape Girardeau County, MO': '031',
'Carroll County, MO': '033',
'Carter County, MO': '035',
'Cass County, MO': '037',
'Cedar County, MO': '039',
'Chariton County, MO': '041',
'Christian County, MO': '043',
'Clark County, MO': '045',
'Clay County, MO': '047',
'Clinton County, MO': '049',
'Cole County, MO': '051',
'Cooper County, MO': '053',
'Crawford County, MO': '055',
'Dade County, MO': '057',
'Dallas County, MO': '059',
'Daviess County, MO': '061',
'DeKalb County, MO': '063',
'Dent County, MO': '065',
'Douglas County, MO': '067',
'Dunklin County, MO': '069',
'Franklin County, MO': '071',
'Gasconade County, MO': '073',
'Gentry County, MO': '075',
'Greene County, MO': '077',
'Grundy County, MO': '079',
'Harrison County, MO': '081',
'Henry County, MO': '083',
'Hickory County, MO': '085',
'Holt County, MO': '087',
'Howard County, MO': '089',
'Howell County, MO': '091',
'Iron County, MO': '093',
'Jackson County, MO': '095',
'Jasper County, MO': '097',
'Jefferson County, MO': '099',
'Johnson County, MO': '101',
'Knox County, MO': '103',
'Laclede County, MO': '105',
'Lafayette County, MO': '107',
'Lawrence County, MO': '109',
'Lewis County, MO': '111',
'Lincoln County, MO': '113',
'Linn County, MO': '115',
'Livingston County, MO': '117',
'Macon County, MO': '121',
'Madison County, MO': '123',
'Maries County, MO': '125',
'Marion County, MO': '127',
'McDonald County, MO': '119',
'Mercer County, MO': '129',
'Miller County, MO': '131',
'Mississippi County, MO': '133',
'Moniteau County, MO': '135',
'Monroe County, MO': '137',
'Montgomery County, MO': '139',
'Morgan County, MO': '141',
'New Madrid County, MO': '143',
'Newton County, MO': '145',
'Nodaway County, MO': '147',
'Oregon County, MO': '149',
'Osage County, MO': '151',
'Ozark County, MO': '153',
'Pemiscot County, MO': '155',
'Perry County, MO': '157',
'Pettis County, MO': '159',
'Phelps County, MO': '161',
'Pike County, MO': '163',
'Platte County, MO': '165',
'Polk County, MO': '167',
'Pulaski County, MO': '169',
'Putnam County, MO': '171',
'Ralls County, MO': '173',
'Randolph County, MO': '175',
'Ray County, MO': '177',
'Reynolds County, MO': '179',
'Ripley County, MO': '181',
'Saline County, MO': '195',
'Schuyler County, MO': '197',
'Scotland County, MO': '199',
'Scott County, MO': '201',
'Shannon County, MO': '203',
'Shelby County, MO': '205',
'St. Charles County, MO': '183',
'St. Clair County, MO': '185',
'St. Francois County, MO': '187',
'St. Louis County, MO': '189',
'St. Louis city, MO': '510',
'Ste. Genevieve County, MO': '186',
'Stoddard County, MO': '207',
'Stone County, MO': '209',
'Sullivan County, MO': '211',
'Taney County, MO': '213',
'Texas County, MO': '215',
'Vernon County, MO': '217',
'Warren County, MO': '219',
'Washington County, MO': '221',
'Wayne County, MO': '223',
'Webster County, MO': '225',
'Worth County, MO': '227',
'Wright County, MO': '229'},
'30': { 'Beaverhead County, MT': '001',
'Big Horn County, MT': '003',
'Blaine County, MT': '005',
'Broadwater County, MT': '007',
'Carbon County, MT': '009',
'Carter County, MT': '011',
'Cascade County, MT': '013',
'Chouteau County, MT': '015',
'Custer County, MT': '017',
'Daniels County, MT': '019',
'Dawson County, MT': '021',
'Deer Lodge County, MT': '023',
'Fallon County, MT': '025',
'Fergus County, MT': '027',
'Flathead County, MT': '029',
'Gallatin County, MT': '031',
'Garfield County, MT': '033',
'Glacier County, MT': '035',
'Golden Valley County, MT': '037',
'Granite County, MT': '039',
'Hill County, MT': '041',
'Jefferson County, MT': '043',
'Judith Basin County, MT': '045',
'Lake County, MT': '047',
'Lewis and Clark County, MT': '049',
'Liberty County, MT': '051',
'Lincoln County, MT': '053',
'Madison County, MT': '057',
'McCone County, MT': '055',
'Meagher County, MT': '059',
'Mineral County, MT': '061',
'Missoula County, MT': '063',
'Musselshell County, MT': '065',
'Park County, MT': '067',
'Petroleum County, MT': '069',
'Phillips County, MT': '071',
'Pondera County, MT': '073',
'Powder River County, MT': '075',
'Powell County, MT': '077',
'Prairie County, MT': '079',
'Ravalli County, MT': '081',
'Richland County, MT': '083',
'Roosevelt County, MT': '085',
'Rosebud County, MT': '087',
'Sanders County, MT': '089',
'Sheridan County, MT': '091',
'Silver Bow County, MT': '093',
'Stillwater County, MT': '095',
'Sweet Grass County, MT': '097',
'Teton County, MT': '099',
'Toole County, MT': '101',
'Treasure County, MT': '103',
'Valley County, MT': '105',
'Wheatland County, MT': '107',
'Wibaux County, MT': '109',
'Yellowstone County, MT': '111'},
'31': { 'Adams County, NE': '001',
'Antelope County, NE': '003',
'Arthur County, NE': '005',
'Banner County, NE': '007',
'Blaine County, NE': '009',
'Boone County, NE': '011',
'Box Butte County, NE': '013',
'Boyd County, NE': '015',
'Brown County, NE': '017',
'Buffalo County, NE': '019',
'Burt County, NE': '021',
'Butler County, NE': '023',
'Cass County, NE': '025',
'Cedar County, NE': '027',
'Chase County, NE': '029',
'Cherry County, NE': '031',
'Cheyenne County, NE': '033',
'Clay County, NE': '035',
'Colfax County, NE': '037',
'Cuming County, NE': '039',
'Custer County, NE': '041',
'Dakota County, NE': '043',
'Dawes County, NE': '045',
'Dawson County, NE': '047',
'Deuel County, NE': '049',
'Dixon County, NE': '051',
'Dodge County, NE': '053',
'Douglas County, NE': '055',
'Dundy County, NE': '057',
'Fillmore County, NE': '059',
'Franklin County, NE': '061',
'Frontier County, NE': '063',
'Furnas County, NE': '065',
'Gage County, NE': '067',
'Garden County, NE': '069',
'Garfield County, NE': '071',
'Gosper County, NE': '073',
'Grant County, NE': '075',
'Greeley County, NE': '077',
'Hall County, NE': '079',
'Hamilton County, NE': '081',
'Harlan County, NE': '083',
'Hayes County, NE': '085',
'Hitchcock County, NE': '087',
'Holt County, NE': '089',
'Hooker County, NE': '091',
'Howard County, NE': '093',
'Jefferson County, NE': '095',
'Johnson County, NE': '097',
'Kearney County, NE': '099',
'Keith County, NE': '101',
'Keya Paha County, NE': '103',
'Kimball County, NE': '105',
'Knox County, NE': '107',
'Lancaster County, NE': '109',
'Lincoln County, NE': '111',
'Logan County, NE': '113',
'Loup County, NE': '115',
'Madison County, NE': '119',
'McPherson County, NE': '117',
'Merrick County, NE': '121',
'Morrill County, NE': '123',
'Nance County, NE': '125',
'Nemaha County, NE': '127',
'Nuckolls County, NE': '129',
'Otoe County, NE': '131',
'Pawnee County, NE': '133',
'Perkins County, NE': '135',
'Phelps County, NE': '137',
'Pierce County, NE': '139',
'Platte County, NE': '141',
'Polk County, NE': '143',
'Red Willow County, NE': '145',
'Richardson County, NE': '147',
'Rock County, NE': '149',
'Saline County, NE': '151',
'Sarpy County, NE': '153',
'Saunders County, NE': '155',
'Scotts Bluff County, NE': '157',
'Seward County, NE': '159',
'Sheridan County, NE': '161',
'Sherman County, NE': '163',
'Sioux County, NE': '165',
'Stanton County, NE': '167',
'Thayer County, NE': '169',
'Thomas County, NE': '171',
'Thurston County, NE': '173',
'Valley County, NE': '175',
'Washington County, NE': '177',
'Wayne County, NE': '179',
'Webster County, NE': '181',
'Wheeler County, NE': '183',
'York County, NE': '185'},
'32': { 'Carson City, NV': '510',
'Churchill County, NV': '001',
'Clark County, NV': '003',
'Douglas County, NV': '005',
'Elko County, NV': '007',
'Esmeralda County, NV': '009',
'Eureka County, NV': '011',
'Humboldt County, NV': '013',
'Lander County, NV': '015',
'Lincoln County, NV': '017',
'Lyon County, NV': '019',
'Mineral County, NV': '021',
'Nye County, NV': '023',
'Pershing County, NV': '027',
'Storey County, NV': '029',
'Washoe County, NV': '031',
'White Pine County, NV': '033'},
'33': { 'Belknap County, NH': '001',
'Carroll County, NH': '003',
'Cheshire County, NH': '005',
'Coos County, NH': '007',
'Grafton County, NH': '009',
'Hillsborough County, NH': '011',
'Merrimack County, NH': '013',
'Rockingham County, NH': '015',
'Strafford County, NH': '017',
'Sullivan County, NH': '019'},
'34': { 'Atlantic County, NJ': '001',
'Bergen County, NJ': '003',
'Burlington County, NJ': '005',
'Camden County, NJ': '007',
'Cape May County, NJ': '009',
'Cumberland County, NJ': '011',
'Essex County, NJ': '013',
'Gloucester County, NJ': '015',
'Hudson County, NJ': '017',
'Hunterdon County, NJ': '019',
'Mercer County, NJ': '021',
'Middlesex County, NJ': '023',
'Monmouth County, NJ': '025',
'Morris County, NJ': '027',
'Ocean County, NJ': '029',
'Passaic County, NJ': '031',
'Salem County, NJ': '033',
'Somerset County, NJ': '035',
'Sussex County, NJ': '037',
'Union County, NJ': '039',
'Warren County, NJ': '041'},
'35': { 'Bernalillo County, NM': '001',
'Catron County, NM': '003',
'Chaves County, NM': '005',
'Cibola County, NM': '006',
'Colfax County, NM': '007',
'Curry County, NM': '009',
'DeBaca County, NM': '011',
'Dona Ana County, NM': '013',
'Eddy County, NM': '015',
'Grant County, NM': '017',
'Guadalupe County, NM': '019',
'Harding County, NM': '021',
'Hidalgo County, NM': '023',
'Lea County, NM': '025',
'Lincoln County, NM': '027',
'Los Alamos County, NM': '028',
'Luna County, NM': '029',
'McKinley County, NM': '031',
'Mora County, NM': '033',
'Otero County, NM': '035',
'Quay County, NM': '037',
'Rio Arriba County, NM': '039',
'Roosevelt County, NM': '041',
'San Juan County, NM': '045',
'San Miguel County, NM': '047',
'Sandoval County, NM': '043',
'Santa Fe County, NM': '049',
'Sierra County, NM': '051',
'Socorro County, NM': '053',
'Taos County, NM': '055',
'Torrance County, NM': '057',
'Union County, NM': '059',
'Valencia County, NM': '061'},
'36': { 'Albany County, NY': '001',
'Allegany County, NY': '003',
'Bronx County, NY': '005',
'Broome County, NY': '007',
'Cattaraugus County, NY': '009',
'Cayuga County, NY': '011',
'Chautauqua County, NY': '013',
'Chemung County, NY': '015',
'Chenango County, NY': '017',
'Clinton County, NY': '019',
'Columbia County, NY': '021',
'Cortland County, NY': '023',
'Delaware County, NY': '025',
'Dutchess County, NY': '027',
'Erie County, NY': '029',
'Essex County, NY': '031',
'Franklin County, NY': '033',
'Fulton County, NY': '035',
'Genesee County, NY': '037',
'Greene County, NY': '039',
'Hamilton County, NY': '041',
'Herkimer County, NY': '043',
'Jefferson County, NY': '045',
'Kings County, NY': '047',
'Lewis County, NY': '049',
'Livingston County, NY': '051',
'Madison County, NY': '053',
'Monroe County, NY': '055',
'Montgomery County, NY': '057',
'Nassau County, NY': '059',
'New York County, NY': '061',
'Niagara County, NY': '063',
'Oneida County, NY': '065',
'Onondaga County, NY': '067',
'Ontario County, NY': '069',
'Orange County, NY': '071',
'Orleans County, NY': '073',
'Oswego County, NY': '075',
'Otsego County, NY': '077',
'Putnam County, NY': '079',
'Queens County, NY': '081',
'Rensselaer County, NY': '083',
'Richmond County, NY': '085',
'Rockland County, NY': '087',
'Saratoga County, NY': '091',
'Schenectady County, NY': '093',
'Schoharie County, NY': '095',
'Schuyler County, NY': '097',
'Seneca County, NY': '099',
'St. Lawrence County, NY': '089',
'Steuben County, NY': '101',
'Suffolk County, NY': '103',
'Sullivan County, NY': '105',
'Tioga County, NY': '107',
'Tompkins County, NY': '109',
'Ulster County, NY': '111',
'Warren County, NY': '113',
'Washington County, NY': '115',
'Wayne County, NY': '117',
'Westchester County, NY': '119',
'Wyoming County, NY': '121',
'Yates County, NY': '123'},
'37': { 'Alamance County, NC': '001',
'Alexander County, NC': '003',
'Alleghany County, NC': '005',
'Anson County, NC': '007',
'Ashe County, NC': '009',
'Avery County, NC': '011',
'Beaufort County, NC': '013',
'Bertie County, NC': '015',
'Bladen County, NC': '017',
'Brunswick County, NC': '019',
'Buncombe County, NC': '021',
'Burke County, NC': '023',
'Cabarrus County, NC': '025',
'Caldwell County, NC': '027',
'Camden County, NC': '029',
'Carteret County, NC': '031',
'Caswell County, NC': '033',
'Catawba County, NC': '035',
'Chatham County, NC': '037',
'Cherokee County, NC': '039',
'Chowan County, NC': '041',
'Clay County, NC': '043',
'Cleveland County, NC': '045',
'Columbus County, NC': '047',
'Craven County, NC': '049',
'Cumberland County, NC': '051',
'Currituck County, NC': '053',
'Dare County, NC': '055',
'Davidson County, NC': '057',
'Davie County, NC': '059',
'Duplin County, NC': '061',
'Durham County, NC': '063',
'Edgecombe County, NC': '065',
'Forsyth County, NC': '067',
'Franklin County, NC': '069',
'Gaston County, NC': '071',
'Gates County, NC': '073',
'Graham County, NC': '075',
'Granville County, NC': '077',
'Greene County, NC': '079',
'Guilford County, NC': '081',
'Halifax County, NC': '083',
'Harnett County, NC': '085',
'Haywood County, NC': '087',
'Henderson County, NC': '089',
'Hertford County, NC': '091',
'Hoke County, NC': '093',
'Hyde County, NC': '095',
'Iredell County, NC': '097',
'Jackson County, NC': '099',
'Johnston County, NC': '101',
'Jones County, NC': '103',
'Lee County, NC': '105',
'Lenoir County, NC': '107',
'Lincoln County, NC': '109',
'Macon County, NC': '113',
'Madison County, NC': '115',
'Martin County, NC': '117',
'McDowell County, NC': '111',
'Mecklenburg County, NC': '119',
'Mitchell County, NC': '121',
'Montgomery County, NC': '123',
'Moore County, NC': '125',
'Nash County, NC': '127',
'New Hanover County, NC': '129',
'Northampton County, NC': '131',
'Onslow County, NC': '133',
'Orange County, NC': '135',
'Pamlico County, NC': '137',
'Pasquotank County, NC': '139',
'Pender County, NC': '141',
'Perquimans County, NC': '143',
'Person County, NC': '145',
'Pitt County, NC': '147',
'Polk County, NC': '149',
'Randolph County, NC': '151',
'Richmond County, NC': '153',
'Robeson County, NC': '155',
'Rockingham County, NC': '157',
'Rowan County, NC': '159',
'Rutherford County, NC': '161',
'Sampson County, NC': '163',
'Scotland County, NC': '165',
'Stanly County, NC': '167',
'Stokes County, NC': '169',
'Surry County, NC': '171',
'Swain County, NC': '173',
'Transylvania County, NC': '175',
'Tyrrell County, NC': '177',
'Union County, NC': '179',
'Vance County, NC': '181',
'Wake County, NC': '183',
'Warren County, NC': '185',
'Washington County, NC': '187',
'Watauga County, NC': '189',
'Wayne County, NC': '191',
'Wilkes County, NC': '193',
'Wilson County, NC': '195',
'Yadkin County, NC': '197',
'Yancey County, NC': '199'},
'38': { 'Adams County, ND': '001',
'Barnes County, ND': '003',
'Benson County, ND': '005',
'Billings County, ND': '007',
'Bottineau County, ND': '009',
'Bowman County, ND': '011',
'Burke County, ND': '013',
'Burleigh County, ND': '015',
'Cass County, ND': '017',
'Cavalier County, ND': '019',
'Dickey County, ND': '021',
'Divide County, ND': '023',
'Dunn County, ND': '025',
'Eddy County, ND': '027',
'Emmons County, ND': '029',
'Foster County, ND': '031',
'Golden Valley County, ND': '033',
'Grand Forks County, ND': '035',
'Grant County, ND': '037',
'Griggs County, ND': '039',
'Hettinger County, ND': '041',
'Kidder County, ND': '043',
'LaMoure County, ND': '045',
'Logan County, ND': '047',
'McHenry County, ND': '049',
'McIntosh County, ND': '051',
'McKenzie County, ND': '053',
'McLean County, ND': '055',
'Mercer County, ND': '057',
'Morton County, ND': '059',
'Mountrail County, ND': '061',
'Nelson County, ND': '063',
'Oliver County, ND': '065',
'Pembina County, ND': '067',
'Pierce County, ND': '069',
'Ramsey County, ND': '071',
'Ransom County, ND': '073',
'Renville County, ND': '075',
'Richland County, ND': '077',
'Rolette County, ND': '079',
'Sargent County, ND': '081',
'Sheridan County, ND': '083',
'Sioux County, ND': '085',
'Slope County, ND': '087',
'Stark County, ND': '089',
'Steele County, ND': '091',
'Stutsman County, ND': '093',
'Towner County, ND': '095',
'Traill County, ND': '097',
'Walsh County, ND': '099',
'Ward County, ND': '101',
'Wells County, ND': '103',
'Williams County, ND': '105'},
'39': { 'Adams County, OH': '001',
'Allen County, OH': '003',
'Ashland County, OH': '005',
'Ashtabula County, OH': '007',
'Athens County, OH': '009',
'Auglaize County, OH': '011',
'Belmont County, OH': '013',
'Brown County, OH': '015',
'Butler County, OH': '017',
'Carroll County, OH': '019',
'Champaign County, OH': '021',
'Clark County, OH': '023',
'Clermont County, OH': '025',
'Clinton County, OH': '027',
'Columbiana County, OH': '029',
'Coshocton County, OH': '031',
'Crawford County, OH': '033',
'Cuyahoga County, OH': '035',
'Darke County, OH': '037',
'Defiance County, OH': '039',
'Delaware County, OH': '041',
'Erie County, OH': '043',
'Fairfield County, OH': '045',
'Fayette County, OH': '047',
'Franklin County, OH': '049',
'Fulton County, OH': '051',
'Gallia County, OH': '053',
'Geauga County, OH': '055',
'Greene County, OH': '057',
'Guernsey County, OH': '059',
'Hamilton County, OH': '061',
'Hancock County, OH': '063',
'Hardin County, OH': '065',
'Harrison County, OH': '067',
'Henry County, OH': '069',
'Highland County, OH': '071',
'Hocking County, OH': '073',
'Holmes County, OH': '075',
'Huron County, OH': '077',
'Jackson County, OH': '079',
'Jefferson County, OH': '081',
'Knox County, OH': '083',
'Lake County, OH': '085',
'Lawrence County, OH': '087',
'Licking County, OH': '089',
'Logan County, OH': '091',
'Lorain County, OH': '093',
'Lucas County, OH': '095',
'Madison County, OH': '097',
'Mahoning County, OH': '099',
'Marion County, OH': '101',
'Medina County, OH': '103',
'Meigs County, OH': '105',
'Mercer County, OH': '107',
'Miami County, OH': '109',
'Monroe County, OH': '111',
'Montgomery County, OH': '113',
'Morgan County, OH': '115',
'Morrow County, OH': '117',
'Muskingum County, OH': '119',
'Noble County, OH': '121',
'Ottawa County, OH': '123',
'Paulding County, OH': '125',
'Perry County, OH': '127',
'Pickaway County, OH': '129',
'Pike County, OH': '131',
'Portage County, OH': '133',
'Preble County, OH': '135',
'Putnam County, OH': '137',
'Richland County, OH': '139',
'Ross County, OH': '141',
'Sandusky County, OH': '143',
'Scioto County, OH': '145',
'Seneca County, OH': '147',
'Shelby County, OH': '149',
'Stark County, OH': '151',
'Summit County, OH': '153',
'Trumbull County, OH': '155',
'Tuscarawas County, OH': '157',
'Union County, OH': '159',
'Van Wert County, OH': '161',
'Vinton County, OH': '163',
'Warren County, OH': '165',
'Washington County, OH': '167',
'Wayne County, OH': '169',
'Williams County, OH': '171',
'Wood County, OH': '173',
'Wyandot County, OH': '175'},
'40': { 'Adair County, OK': '001',
'Alfalfa County, OK': '003',
'Atoka County, OK': '005',
'Beaver County, OK': '007',
'Beckham County, OK': '009',
'Blaine County, OK': '011',
'Bryan County, OK': '013',
'Caddo County, OK': '015',
'Canadian County, OK': '017',
'Carter County, OK': '019',
'Cherokee County, OK': '021',
'Choctaw County, OK': '023',
'Cimarron County, OK': '025',
'Cleveland County, OK': '027',
'Coal County, OK': '029',
'Comanche County, OK': '031',
'Cotton County, OK': '033',
'Craig County, OK': '035',
'Creek County, OK': '037',
'Custer County, OK': '039',
'Delaware County, OK': '041',
'Dewey County, OK': '043',
'Ellis County, OK': '045',
'Garfield County, OK': '047',
'Garvin County, OK': '049',
'Grady County, OK': '051',
'Grant County, OK': '053',
'Greer County, OK': '055',
'Harmon County, OK': '057',
'Harper County, OK': '059',
'Haskell County, OK': '061',
'Hughes County, OK': '063',
'Jackson County, OK': '065',
'Jefferson County, OK': '067',
'Johnston County, OK': '069',
'Kay County, OK': '071',
'Kingfisher County, OK': '073',
'Kiowa County, OK': '075',
'Latimer County, OK': '077',
'Le Flore County, OK': '079',
'Lincoln County, OK': '081',
'Logan County, OK': '083',
'Love County, OK': '085',
'Major County, OK': '093',
'Marshall County, OK': '095',
'Mayes County, OK': '097',
'McClain County, OK': '087',
'McCurtain County, OK': '089',
'McIntosh County, OK': '091',
'Murray County, OK': '099',
'Muskogee County, OK': '101',
'Noble County, OK': '103',
'Nowata County, OK': '105',
'Okfuskee County, OK': '107',
'Oklahoma County, OK': '109',
'Okmulgee County, OK': '111',
'Osage County, OK': '113',
'Ottawa County, OK': '115',
'Pawnee County, OK': '117',
'Payne County, OK': '119',
'Pittsburg County, OK': '121',
'Pontotoc County, OK': '123',
'Pottawatomie County, OK': '125',
'Pushmataha County, OK': '127',
'Roger Mills County, OK': '129',
'Rogers County, OK': '131',
'Seminole County, OK': '133',
'Sequoyah County, OK': '135',
'Stephens County, OK': '137',
'Texas County, OK': '139',
'Tillman County, OK': '141',
'Tulsa County, OK': '143',
'Wagoner County, OK': '145',
'Washington County, OK': '147',
'Washita County, OK': '149',
'Woods County, OK': '151',
'Woodward County, OK': '153'},
'41': { 'Baker County, OR': '001',
'Benton County, OR': '003',
'Clackamas County, OR': '005',
'Clatsop County, OR': '007',
'Columbia County, OR': '009',
'Coos County, OR': '011',
'Crook County, OR': '013',
'Curry County, OR': '015',
'Deschutes County, OR': '017',
'Douglas County, OR': '019',
'Gilliam County, OR': '021',
'Grant County, OR': '023',
'Harney County, OR': '025',
'Hood River County, OR': '027',
'Jackson County, OR': '029',
'Jefferson County, OR': '031',
'Josephine County, OR': '033',
'Klamath County, OR': '035',
'Lake County, OR': '037',
'Lane County, OR': '039',
'Lincoln County, OR': '041',
'Linn County, OR': '043',
'Malheur County, OR': '045',
'Marion County, OR': '047',
'Morrow County, OR': '049',
'Multnomah County, OR': '051',
'Polk County, OR': '053',
'Sherman County, OR': '055',
'Tillamook County, OR': '057',
'Umatilla County, OR': '059',
'Union County, OR': '061',
'Wallowa County, OR': '063',
'Wasco County, OR': '065',
'Washington County, OR': '067',
'Wheeler County, OR': '069',
'Yamhill County, OR': '071'},
'42': { 'Adams County, PA': '001',
'Allegheny County, PA': '003',
'Armstrong County, PA': '005',
'Beaver County, PA': '007',
'Bedford County, PA': '009',
'Berks County, PA': '011',
'Blair County, PA': '013',
'Bradford County, PA': '015',
'Bucks County, PA': '017',
'Butler County, PA': '019',
'Cambria County, PA': '021',
'Cameron County, PA': '023',
'Carbon County, PA': '025',
'Centre County, PA': '027',
'Chester County, PA': '029',
'Clarion County, PA': '031',
'Clearfield County, PA': '033',
'Clinton County, PA': '035',
'Columbia County, PA': '037',
'Crawford County, PA': '039',
'Cumberland County, PA': '041',
'Dauphin County, PA': '043',
'Delaware County, PA': '045',
'Elk County, PA': '047',
'Erie County, PA': '049',
'Fayette County, PA': '051',
'Forest County, PA': '053',
'Franklin County, PA': '055',
'Fulton County, PA': '057',
'Greene County, PA': '059',
'Huntingdon County, PA': '061',
'Indiana County, PA': '063',
'Jefferson County, PA': '065',
'Juniata County, PA': '067',
'Lackawanna County, PA': '069',
'Lancaster County, PA': '071',
'Lawrence County, PA': '073',
'Lebanon County, PA': '075',
'Lehigh County, PA': '077',
'Luzerne County, PA': '079',
'Lycoming County, PA': '081',
'McKean County, PA': '083',
'Mercer County, PA': '085',
'Mifflin County, PA': '087',
'Monroe County, PA': '089',
'Montgomery County, PA': '091',
'Montour County, PA': '093',
'Northampton County, PA': '095',
'Northumberland County, PA': '097',
'Perry County, PA': '099',
'Philadelphia County/city, PA': '101',
'Pike County, PA': '103',
'Potter County, PA': '105',
'Schuylkill County, PA': '107',
'Snyder County, PA': '109',
'Somerset County, PA': '111',
'Sullivan County, PA': '113',
'Susquehanna County, PA': '115',
'Tioga County, PA': '117',
'Union County, PA': '119',
'Venango County, PA': '121',
'Warren County, PA': '123',
'Washington County, PA': '125',
'Wayne County, PA': '127',
'Westmoreland County, PA': '129',
'Wyoming County, PA': '131',
'York County, PA': '133'},
'44': { 'Bristol County, RI': '001',
'Kent County, RI': '003',
'Newport County, RI': '005',
'Providence County, RI': '007',
'Washington County, RI': '009'},
'45': { 'Abbeville County, SC': '001',
'Aiken County, SC': '003',
'Allendale County, SC': '005',
'Anderson County, SC': '007',
'Bamberg County, SC': '009',
'Barnwell County, SC': '011',
'Beaufort County, SC': '013',
'Berkeley County, SC': '015',
'Calhoun County, SC': '017',
'Charleston County, SC': '019',
'Cherokee County, SC': '021',
'Chester County, SC': '023',
'Chesterfield County, SC': '025',
'Clarendon County, SC': '027',
'Colleton County, SC': '029',
'Darlington County, SC': '031',
'Dillon County, SC': '033',
'Dorchester County, SC': '035',
'Edgefield County, SC': '037',
'Fairfield County, SC': '039',
'Florence County, SC': '041',
'Georgetown County, SC': '043',
'Greenville County, SC': '045',
'Greenwood County, SC': '047',
'Hampton County, SC': '049',
'Horry County, SC': '051',
'Jasper County, SC': '053',
'Kershaw County, SC': '055',
'Lancaster County, SC': '057',
'Laurens County, SC': '059',
'Lee County, SC': '061',
'Lexington County, SC': '063',
'Marion County, SC': '067',
'Marlboro County, SC': '069',
'McCormick County, SC': '065',
'Newberry County, SC': '071',
'Oconee County, SC': '073',
'Orangeburg County, SC': '075',
'Pickens County, SC': '077',
'Richland County, SC': '079',
'Saluda County, SC': '081',
'Spartanburg County, SC': '083',
'Sumter County, SC': '085',
'Union County, SC': '087',
'Williamsburg County, SC': '089',
'York County, SC': '091'},
'46': { 'Aurora County, SD': '003',
'Beadle County, SD': '005',
'Bennett County, SD': '007',
'Bon Homme County, SD': '009',
'Brookings County, SD': '011',
'Brown County, SD': '013',
'Brule County, SD': '015',
'Buffalo County, SD': '017',
'Butte County, SD': '019',
'Campbell County, SD': '021',
'Charles Mix County, SD': '023',
'Clark County, SD': '025',
'Clay County, SD': '027',
'Codington County, SD': '029',
'Corson County, SD': '031',
'Custer County, SD': '033',
'Davison County, SD': '035',
'Day County, SD': '037',
'Deuel County, SD': '039',
'Dewey County, SD': '041',
'Douglas County, SD': '043',
'Edmunds County, SD': '045',
'Fall River County, SD': '047',
'Faulk County, SD': '049',
'Grant County, SD': '051',
'Gregory County, SD': '053',
'Haakon County, SD': '055',
'Hamlin County, SD': '057',
'Hand County, SD': '059',
'Hanson County, SD': '061',
'Harding County, SD': '063',
'Hughes County, SD': '065',
'Hutchinson County, SD': '067',
'Hyde County, SD': '069',
'Jackson County, SD': '071',
'Jerauld County, SD': '073',
'Jones County, SD': '075',
'Kingsbury County, SD': '077',
'Lake County, SD': '079',
'Lawrence County, SD': '081',
'Lincoln County, SD': '083',
'Lyman County, SD': '085',
'Marshall County, SD': '091',
'McCook County, SD': '087',
'McPherson County, SD': '089',
'Meade County, SD': '093',
'Mellette County, SD': '095',
'Miner County, SD': '097',
'Minnehaha County, SD': '099',
'Moody County, SD': '101',
'Pennington County, SD': '103',
'Perkins County, SD': '105',
'Potter County, SD': '107',
'Roberts County, SD': '109',
'Sanborn County, SD': '111',
'Shannon County, SD': '113',
'Spink County, SD': '115',
'Stanley County, SD': '117',
'Sully County, SD': '119',
'Todd County, SD': '121',
'Tripp County, SD': '123',
'Turner County, SD': '125',
'Union County, SD': '127',
'Walworth County, SD': '129',
'Yankton County, SD': '135',
'Ziebach County, SD': '137'},
'47': { 'Anderson County, TN': '001',
'Bedford County, TN': '003',
'Benton County, TN': '005',
'Bledsoe County, TN': '007',
'Blount County, TN': '009',
'Bradley County, TN': '011',
'Campbell County, TN': '013',
'Cannon County, TN': '015',
'Carroll County, TN': '017',
'Carter County, TN': '019',
'Cheatham County, TN': '021',
'Chester County, TN': '023',
'Claiborne County, TN': '025',
'Clay County, TN': '027',
'Cocke County, TN': '029',
'Coffee County, TN': '031',
'Crockett County, TN': '033',
'Cumberland County, TN': '035',
'Davidson County, TN': '037',
'DeKalb County, TN': '041',
'Decatur County, TN': '039',
'Dickson County, TN': '043',
'Dyer County, TN': '045',
'Fayette County, TN': '047',
'Fentress County, TN': '049',
'Franklin County, TN': '051',
'Gibson County, TN': '053',
'Giles County, TN': '055',
'Grainger County, TN': '057',
'Greene County, TN': '059',
'Grundy County, TN': '061',
'Hamblen County, TN': '063',
'Hamilton County, TN': '065',
'Hancock County, TN': '067',
'Hardeman County, TN': '069',
'Hardin County, TN': '071',
'Hawkins County, TN': '073',
'Haywood County, TN': '075',
'Henderson County, TN': '077',
'Henry County, TN': '079',
'Hickman County, TN': '081',
'Houston County, TN': '083',
'Humphreys County, TN': '085',
'Jackson County, TN': '087',
'Jefferson County, TN': '089',
'Johnson County, TN': '091',
'Knox County, TN': '093',
'Lake County, TN': '095',
'Lauderdale County, TN': '097',
'Lawrence County, TN': '099',
'Lewis County, TN': '101',
'Lincoln County, TN': '103',
'Loudon County, TN': '105',
'Macon County, TN': '111',
'Madison County, TN': '113',
'Marion County, TN': '115',
'Marshall County, TN': '117',
'Maury County, TN': '119',
'McMinn County, TN': '107',
'McNairy County, TN': '109',
'Meigs County, TN': '121',
'Monroe County, TN': '123',
'Montgomery County, TN': '125',
'Moore County, TN': '127',
'Morgan County, TN': '129',
'Obion County, TN': '131',
'Overton County, TN': '133',
'Perry County, TN': '135',
'Pickett County, TN': '137',
'Polk County, TN': '139',
'Putnam County, TN': '141',
'Rhea County, TN': '143',
'Roane County, TN': '145',
'Robertson County, TN': '147',
'Rutherford County, TN': '149',
'Scott County, TN': '151',
'Sequatchie County, TN': '153',
'Sevier County, TN': '155',
'Shelby County, TN': '157',
'Smith County, TN': '159',
'Stewart County, TN': '161',
'Sullivan County, TN': '163',
'Sumner County, TN': '165',
'Tipton County, TN': '167',
'Trousdale County, TN': '169',
'Unicoi County, TN': '171',
'Union County, TN': '173',
'Van Buren County, TN': '175',
'Warren County, TN': '177',
'Washington County, TN': '179',
'Wayne County, TN': '181',
'Weakley County, TN': '183',
'White County, TN': '185',
'Williamson County, TN': '187',
'Wilson County, TN': '189'},
'48': { 'Anderson County, TX': '001',
'Andrews County, TX': '003',
'Angelina County, TX': '005',
'Aransas County, TX': '007',
'Archer County, TX': '009',
'Armstrong County, TX': '011',
'Atascosa County, TX': '013',
'Austin County, TX': '015',
'Bailey County, TX': '017',
'Bandera County, TX': '019',
'Bastrop County, TX': '021',
'Baylor County, TX': '023',
'Bee County, TX': '025',
'Bell County, TX': '027',
'Bexar County, TX': '029',
'Blanco County, TX': '031',
'Borden County, TX': '033',
'Bosque County, TX': '035',
'Bowie County, TX': '037',
'Brazoria County, TX': '039',
'Brazos County, TX': '041',
'Brewster County, TX': '043',
'Briscoe County, TX': '045',
'Brooks County, TX': '047',
'Brown County, TX': '049',
'Burleson County, TX': '051',
'Burnet County, TX': '053',
'Caldwell County, TX': '055',
'Calhoun County, TX': '057',
'Callahan County, TX': '059',
'Cameron County, TX': '061',
'Camp County, TX': '063',
'Carson County, TX': '065',
'Cass County, TX': '067',
'Castro County, TX': '069',
'Chambers County, TX': '071',
'Cherokee County, TX': '073',
'Childress County, TX': '075',
'Clay County, TX': '077',
'Cochran County, TX': '079',
'Coke County, TX': '081',
'Coleman County, TX': '083',
'Collin County, TX': '085',
'Collingsworth County, TX': '087',
'Colorado County, TX': '089',
'Comal County, TX': '091',
'Comanche County, TX': '093',
'Concho County, TX': '095',
'Cooke County, TX': '097',
'Coryell County, TX': '099',
'Cottle County, TX': '101',
'Crane County, TX': '103',
'Crockett County, TX': '105',
'Crosby County, TX': '107',
'Culberson County, TX': '109',
'Dallam County, TX': '111',
'Dallas County, TX': '113',
'Dawson County, TX': '115',
'DeWitt County, TX': '123',
'Deaf Smith County, TX': '117',
'Delta County, TX': '119',
'Denton County, TX': '121',
'Dickens County, TX': '125',
'Dimmit County, TX': '127',
'Donley County, TX': '129',
'Duval County, TX': '131',
'Eastland County, TX': '133',
'Ector County, TX': '135',
'Edwards County, TX': '137',
'El Paso County, TX': '141',
'Ellis County, TX': '139',
'Erath County, TX': '143',
'Falls County, TX': '145',
'Fannin County, TX': '147',
'Fayette County, TX': '149',
'Fisher County, TX': '151',
'Floyd County, TX': '153',
'Foard County, TX': '155',
'Fort Bend County, TX': '157',
'Franklin County, TX': '159',
'Freestone County, TX': '161',
'Frio County, TX': '163',
'Gaines County, TX': '165',
'Galveston County, TX': '167',
'Garza County, TX': '169',
'Gillespie County, TX': '171',
'Glasscock County, TX': '173',
'Goliad County, TX': '175',
'Gonzales County, TX': '177',
'Gray County, TX': '179',
'Grayson County, TX': '181',
'Gregg County, TX': '183',
'Grimes County, TX': '185',
'Guadalupe County, TX': '187',
'Hale County, TX': '189',
'Hall County, TX': '191',
'Hamilton County, TX': '193',
'Hansford County, TX': '195',
'Hardeman County, TX': '197',
'Hardin County, TX': '199',
'Harris County, TX': '201',
'Harrison County, TX': '203',
'Hartley County, TX': '205',
'Haskell County, TX': '207',
'Hays County, TX': '209',
'Hemphill County, TX': '211',
'Henderson County, TX': '213',
'Hidalgo County, TX': '215',
'Hill County, TX': '217',
'Hockley County, TX': '219',
'Hood County, TX': '221',
'Hopkins County, TX': '223',
'Houston County, TX': '225',
'Howard County, TX': '227',
'Hudspeth County, TX': '229',
'Hunt County, TX': '231',
'Hutchinson County, TX': '233',
'Irion County, TX': '235',
'Jack County, TX': '237',
'Jackson County, TX': '239',
'Jasper County, TX': '241',
'Jeff Davis County, TX': '243',
'Jefferson County, TX': '245',
'Jim Hogg County, TX': '247',
'Jim Wells County, TX': '249',
'Johnson County, TX': '251',
'Jones County, TX': '253',
'Karnes County, TX': '255',
'Kaufman County, TX': '257',
'Kendall County, TX': '259',
'Kenedy County, TX': '261',
'Kent County, TX': '263',
'Kerr County, TX': '265',
'Kimble County, TX': '267',
'King County, TX': '269',
'Kinney County, TX': '271',
'Kleberg County, TX': '273',
'Knox County, TX': '275',
'La Salle County, TX': '283',
'Lamar County, TX': '277',
'Lamb County, TX': '279',
'Lampasas County, TX': '281',
'Lavaca County, TX': '285',
'Lee County, TX': '287',
'Leon County, TX': '289',
'Liberty County, TX': '291',
'Limestone County, TX': '293',
'Lipscomb County, TX': '295',
'Live Oak County, TX': '297',
'Llano County, TX': '299',
'Loving County, TX': '301',
'Lubbock County, TX': '303',
'Lynn County, TX': '305',
'Madison County, TX': '313',
'Marion County, TX': '315',
'Martin County, TX': '317',
'Mason County, TX': '319',
'Matagorda County, TX': '321',
'Maverick County, TX': '323',
'McCulloch County, TX': '307',
'McLennan County, TX': '309',
'McMullen County, TX': '311',
'Medina County, TX': '325',
'Menard County, TX': '327',
'Midland County, TX': '329',
'Milam County, TX': '331',
'Mills County, TX': '333',
'Mitchell County, TX': '335',
'Montague County, TX': '337',
'Montgomery County, TX': '339',
'Moore County, TX': '341',
'Morris County, TX': '343',
'Motley County, TX': '345',
'Nacogdoches County, TX': '347',
'Navarro County, TX': '349',
'Newton County, TX': '351',
'Nolan County, TX': '353',
'Nueces County, TX': '355',
'Ochiltree County, TX': '357',
'Oldham County, TX': '359',
'Orange County, TX': '361',
'Palo Pinto County, TX': '363',
'Panola County, TX': '365',
'Parker County, TX': '367',
'Parmer County, TX': '369',
'Pecos County, TX': '371',
'Polk County, TX': '373',
'Potter County, TX': '375',
'Presidio County, TX': '377',
'Rains County, TX': '379',
'Randall County, TX': '381',
'Reagan County, TX': '383',
'Real County, TX': '385',
'Red River County, TX': '387',
'Reeves County, TX': '389',
'Refugio County, TX': '391',
'Roberts County, TX': '393',
'Robertson County, TX': '395',
'Rockwall County, TX': '397',
'Runnels County, TX': '399',
'Rusk County, TX': '401',
'Sabine County, TX': '403',
'San Augustine County, TX': '405',
'San Jacinto County, TX': '407',
'San Patricio County, TX': '409',
'San Saba County, TX': '411',
'Schleicher County, TX': '413',
'Scurry County, TX': '415',
'Shackelford County, TX': '417',
'Shelby County, TX': '419',
'Sherman County, TX': '421',
'Smith County, TX': '423',
'Somervell County, TX': '425',
'Starr County, TX': '427',
'Stephens County, TX': '429',
'Sterling County, TX': '431',
'Stonewall County, TX': '433',
'Sutton County, TX': '435',
'Swisher County, TX': '437',
'Tarrant County, TX': '439',
'Taylor County, TX': '441',
'Terrell County, TX': '443',
'Terry County, TX': '445',
'Throckmorton County, TX': '447',
'Titus County, TX': '449',
'Tom Green County, TX': '451',
'Travis County, TX': '453',
'Trinity County, TX': '455',
'Tyler County, TX': '457',
'Upshur County, TX': '459',
'Upton County, TX': '461',
'Uvalde County, TX': '463',
'Val Verde County, TX': '465',
'Van Zandt County, TX': '467',
'Victoria County, TX': '469',
'Walker County, TX': '471',
'Waller County, TX': '473',
'Ward County, TX': '475',
'Washington County, TX': '477',
'Webb County, TX': '479',
'Wharton County, TX': '481',
'Wheeler County, TX': '483',
'Wichita County, TX': '485',
'Wilbarger County, TX': '487',
'Willacy County, TX': '489',
'Williamson County, TX': '491',
'Wilson County, TX': '493',
'Winkler County, TX': '495',
'Wise County, TX': '497',
'Wood County, TX': '499',
'Yoakum County, TX': '501',
'Young County, TX': '503',
'Zapata County, TX': '505',
'Zavala County, TX': '507'},
'49': { 'Beaver County, UT': '001',
'Box Elder County, UT': '003',
'Cache County, UT': '005',
'Carbon County, UT': '007',
'Daggett County, UT': '009',
'Davis County, UT': '011',
'Duchesne County, UT': '013',
'Emery County, UT': '015',
'Garfield County, UT': '017',
'Grand County, UT': '019',
'Iron County, UT': '021',
'Juab County, UT': '023',
'Kane County, UT': '025',
'Millard County, UT': '027',
'Morgan County, UT': '029',
'Piute County, UT': '031',
'Rich County, UT': '033',
'Salt Lake County, UT': '035',
'San Juan County, UT': '037',
'Sanpete County, UT': '039',
'Sevier County, UT': '041',
'Summit County, UT': '043',
'Tooele County, UT': '045',
'Uintah County, UT': '047',
'Utah County, UT': '049',
'Wasatch County, UT': '051',
'Washington County, UT': '053',
'Wayne County, UT': '055',
'Weber County, UT': '057'},
'50': { 'Addison County, VT': '001',
'Bennington County, VT': '003',
'Caledonia County, VT': '005',
'Chittenden County, VT': '007',
'Essex County, VT': '009',
'Franklin County, VT': '011',
'Grand Isle County, VT': '013',
'Lamoille County, VT': '015',
'Orange County, VT': '017',
'Orleans County, VT': '019',
'Rutland County, VT': '021',
'Washington County, VT': '023',
'Windham County, VT': '025',
'Windsor County, VT': '027'},
'51': { 'Accomack County, VA': '001',
'Albemarle County, VA': '003',
'Alexandria city, VA': '510',
'Alleghany County, VA': '005',
'Amelia County, VA': '007',
'Amherst County, VA': '009',
'Appomattox County, VA': '011',
'Arlington County, VA': '013',
'Augusta County, VA': '015',
'Bath County, VA': '017',
'Bedford County, VA': '019',
'Bedford city, VA': '515',
'Bland County, VA': '021',
'Botetourt County, VA': '023',
'Bristol city, VA': '520',
'Brunswick County, VA': '025',
'Buchanan County, VA': '027',
'Buckingham County, VA': '029',
'Buena Vista city, VA': '530',
'Campbell County, VA': '031',
'Caroline County, VA': '033',
'Carroll County, VA': '035',
'Charles City County, VA': '036',
'Charlotte County, VA': '037',
'Charlottesville city, VA': '540',
'Chesapeake city, VA': '550',
'Chesterfield County, VA': '041',
'Clarke County, VA': '043',
'Colonial Heights city, VA': '570',
'Covington city, VA': '580',
'Craig County, VA': '045',
'Culpeper County, VA': '047',
'Cumberland County, VA': '049',
'Danville city, VA': '590',
'Dickenson County, VA': '051',
'Dinwiddie County, VA': '053',
'Emporia city, VA': '595',
'Essex County, VA': '057',
'Fairfax County, VA': '059',
'Fairfax city, VA': '600',
'Falls Church city, VA': '610',
'Fauquier County, VA': '061',
'Floyd County, VA': '063',
'Fluvanna County, VA': '065',
'Franklin County, VA': '067',
'Franklin city, VA': '620',
'Frederick County, VA': '069',
'Fredericksburg city, VA': '630',
'Galax city, VA': '640',
'Giles County, VA': '071',
'Gloucester County, VA': '073',
'Goochland County, VA': '075',
'Grayson County, VA': '077',
'Greene County, VA': '079',
'Greensville County, VA': '081',
'Halifax County, VA': '083',
'Hampton city, VA': '650',
'Hanover County, VA': '085',
'Harrisonburg city, VA': '660',
'Henrico County, VA': '087',
'Henry County, VA': '089',
'Highland County, VA': '091',
'Hopewell city, VA': '670',
'Isle of Wight County, VA': '093',
'James City County, VA': '095',
'King George County, VA': '099',
'King William County, VA': '101',
'King and Queen County, VA': '097',
'Lancaster County, VA': '103',
'Lee County, VA': '105',
'Lexington city, VA': '678',
'Loudoun County, VA': '107',
'Louisa County, VA': '109',
'Lunenburg County, VA': '111',
'Lynchburg city, VA': '680',
'Madison County, VA': '113',
'Manassas Park city, VA': '685',
'Manassas city, VA': '683',
'Martinsville city, VA': '690',
'Mathews County, VA': '115',
'Mecklenburg County, VA': '117',
'Middlesex County, VA': '119',
'Montgomery County, VA': '121',
'Nelson County, VA': '125',
'New Kent County, VA': '127',
'Newport News city, VA': '700',
'Norfolk city, VA': '710',
'Northampton County, VA': '131',
'Northumberland County, VA': '133',
'Norton city, VA': '720',
'Nottoway County, VA': '135',
'Orange County, VA': '137',
'Page County, VA': '139',
'Patrick County, VA': '141',
'Petersburg city, VA': '730',
'Pittsylvania County, VA': '143',
'Poquoson city, VA': '735',
'Portsmouth city, VA': '740',
'Powhatan County, VA': '145',
'Prince Edward County, VA': '147',
'Prince George County, VA': '149',
'Prince William County, VA': '153',
'Pulaski County, VA': '155',
'Radford city, VA': '750',
'Rappahannock County, VA': '157',
'Richmond County, VA': '159',
'Richmond city, VA': '760',
'Roanoke County, VA': '161',
'Roanoke city, VA': '770',
'Rockbridge County, VA': '163',
'Rockingham County, VA': '165',
'Russell County, VA': '167',
'Salem city, VA': '775',
'Scott County, VA': '169',
'Shenandoah County, VA': '171',
'Smyth County, VA': '173',
'Southampton County, VA': '175',
'Spotsylvania County, VA': '177',
'Stafford County, VA': '179',
'Staunton city, VA': '790',
'Suffolk city, VA': '800',
'Surry County, VA': '181',
'Sussex County, VA': '183',
'Tazewell County, VA': '185',
'Virginia Beach city, VA': '810',
'Warren County, VA': '187',
'Washington County, VA': '191',
'Waynesboro city, VA': '820',
'Westmoreland County, VA': '193',
'Williamsburg city, VA': '830',
'Winchester city, VA': '840',
'Wise County, VA': '195',
'Wythe County, VA': '197',
'York County, VA': '199'},
'53': { 'Adams County, WA': '001',
'Asotin County, WA': '003',
'Benton County, WA': '005',
'Chelan County, WA': '007',
'Clallam County, WA': '009',
'Clark County, WA': '011',
'Columbia County, WA': '013',
'Cowlitz County, WA': '015',
'Douglas County, WA': '017',
'Ferry County, WA': '019',
'Franklin County, WA': '021',
'Garfield County, WA': '023',
'Grant County, WA': '025',
'Grays Harbor County, WA': '027',
'Island County, WA': '029',
'Jefferson County, WA': '031',
'King County, WA': '033',
'Kitsap County, WA': '035',
'Kittitas County, WA': '037',
'Klickitat County, WA': '039',
'Lewis County, WA': '041',
'Lincoln County, WA': '043',
'Mason County, WA': '045',
'Okanogan County, WA': '047',
'Pacific County, WA': '049',
'Pend Oreille County, WA': '051',
'Pierce County, WA': '053',
'San Juan County, WA': '055',
'Skagit County, WA': '057',
'Skamania County, WA': '059',
'Snohomish County, WA': '061',
'Spokane County, WA': '063',
'Stevens County, WA': '065',
'Thurston County, WA': '067',
'Wahkiakum County, WA': '069',
'Walla Walla County, WA': '071',
'Whatcom County, WA': '073',
'Whitman County, WA': '075',
'Yakima County, WA': '077'},
'54': { 'Barbour County, WV': '001',
'Berkeley County, WV': '003',
'Boone County, WV': '005',
'Braxton County, WV': '007',
'Brooke County, WV': '009',
'Cabell County, WV': '011',
'Calhoun County, WV': '013',
'Clay County, WV': '015',
'Doddridge County, WV': '017',
'Fayette County, WV': '019',
'Gilmer County, WV': '021',
'Grant County, WV': '023',
'Greenbrier County, WV': '025',
'Hampshire County, WV': '027',
'Hancock County, WV': '029',
'Hardy County, WV': '031',
'Harrison County, WV': '033',
'Jackson County, WV': '035',
'Jefferson County, WV': '037',
'Kanawha County, WV': '039',
'Lewis County, WV': '041',
'Lincoln County, WV': '043',
'Logan County, WV': '045',
'Marion County, WV': '049',
'Marshall County, WV': '051',
'Mason County, WV': '053',
'McDowell County, WV': '047',
'Mercer County, WV': '055',
'Mineral County, WV': '057',
'Mingo County, WV': '059',
'Monongalia County, WV': '061',
'Monroe County, WV': '063',
'Morgan County, WV': '065',
'Nicholas County, WV': '067',
'Ohio County, WV': '069',
'Pendleton County, WV': '071',
'Pleasants County, WV': '073',
'Pocahontas County, WV': '075',
'Preston County, WV': '077',
'Putnam County, WV': '079',
'Raleigh County, WV': '081',
'Randolph County, WV': '083',
'Ritchie County, WV': '085',
'Roane County, WV': '087',
'Summers County, WV': '089',
'Taylor County, WV': '091',
'Tucker County, WV': '093',
'Tyler County, WV': '095',
'Upshur County, WV': '097',
'Wayne County, WV': '099',
'Webster County, WV': '101',
'Wetzel County, WV': '103',
'Wirt County, WV': '105',
'Wood County, WV': '107',
'Wyoming County, WV': '109'},
'55': { 'Adams County, WI': '001',
'Ashland County, WI': '003',
'Barron County, WI': '005',
'Bayfield County, WI': '007',
'Brown County, WI': '009',
'Buffalo County, WI': '011',
'Burnett County, WI': '013',
'Calumet County, WI': '015',
'Chippewa County, WI': '017',
'Clark County, WI': '019',
'Columbia County, WI': '021',
'Crawford County, WI': '023',
'Dane County, WI': '025',
'Dodge County, WI': '027',
'Door County, WI': '029',
'Douglas County, WI': '031',
'Dunn County, WI': '033',
'Eau Claire County, WI': '035',
'Florence County, WI': '037',
'Fond du Lac County, WI': '039',
'Forest County, WI': '041',
'Grant County, WI': '043',
'Green County, WI': '045',
'Green Lake County, WI': '047',
'Iowa County, WI': '049',
'Iron County, WI': '051',
'Jackson County, WI': '053',
'Jefferson County, WI': '055',
'Juneau County, WI': '057',
'Kenosha County, WI': '059',
'Kewaunee County, WI': '061',
'La Crosse County, WI': '063',
'Lafayette County, WI': '065',
'Langlade County, WI': '067',
'Lincoln County, WI': '069',
'Manitowoc County, WI': '071',
'Marathon County, WI': '073',
'Marinette County, WI': '075',
'Marquette County, WI': '077',
'Menominee County, WI': '078',
'Milwaukee County, WI': '079',
'Monroe County, WI': '081',
'Oconto County, WI': '083',
'Oneida County, WI': '085',
'Outagamie County, WI': '087',
'Ozaukee County, WI': '089',
'Pepin County, WI': '091',
'Pierce County, WI': '093',
'Polk County, WI': '095',
'Portage County, WI': '097',
'Price County, WI': '099',
'Racine County, WI': '101',
'Richland County, WI': '103',
'Rock County, WI': '105',
'Rusk County, WI': '107',
'Sauk County, WI': '111',
'Sawyer County, WI': '113',
'Shawano County, WI': '115',
'Sheboygan County, WI': '117',
'St. Croix County, WI': '109',
'Taylor County, WI': '119',
'Trempealeau County, WI': '121',
'Vernon County, WI': '123',
'Vilas County, WI': '125',
'Walworth County, WI': '127',
'Washburn County, WI': '129',
'Washington County, WI': '131',
'Waukesha County, WI': '133',
'Waupaca County, WI': '135',
'Waushara County, WI': '137',
'Winnebago County, WI': '139',
'Wood County, WI': '141'},
'56': { 'Albany County, WY': '001',
'Big Horn County, WY': '003',
'Campbell County, WY': '005',
'Carbon County, WY': '007',
'Converse County, WY': '009',
'Crook County, WY': '011',
'Fremont County, WY': '013',
'Goshen County, WY': '015',
'Hot Springs County, WY': '017',
'Johnson County, WY': '019',
'Laramie County, WY': '021',
'Lincoln County, WY': '023',
'Natrona County, WY': '025',
'Niobrara County, WY': '027',
'Park County, WY': '029',
'Platte County, WY': '031',
'Sheridan County, WY': '033',
'Sublette County, WY': '035',
'Sweetwater County, WY': '037',
'Teton County, WY': '039',
'Uinta County, WY': '041',
'Washakie County, WY': '043',
'Weston County, WY': '045'},
'72': { 'Adjuntas Municipio, PR': '001',
'Aguada Municipio, PR': '003',
'Aguadilla Municipio, PR': '005',
'Aguas Buenas Municipio, PR': '007',
'Aibonito Municipio, PR': '009',
'Anasco Municipio, PR': '011',
'Arecibo Municipio, PR': '013',
'Arroyo Municipio, PR': '015',
'Barceloneta Municipio, PR': '017',
'Barranquitas Municipio, PR': '019',
'Bayamon Municipio, PR': '021',
'Cabo Rojo Municipio, PR': '023',
'Caguas Municipio, PR': '025',
'Camuy Municipio, PR': '027',
'Canovanas Municipio, PR': '029',
'Carolina Municipio, PR': '031',
'Catano Municipio, PR': '033',
'Cayey Municipio, PR': '035',
'Ceiba Municipio, PR': '037',
'Ciales Municipio, PR': '039',
'Cidra Municipio, PR': '041',
'Coamo Municipio, PR': '043',
'Comerio Municipio, PR': '045',
'Corozal Municipio, PR': '047',
'Culebra Municipio, PR': '049',
'Dorado Municipio, PR': '051',
'Fajardo Municipio, PR': '053',
'Florida Municipio, PR': '054',
'Guanica Municipio, PR': '055',
'Guayama Municipio, PR': '057',
'Guayanilla Municipio, PR': '059',
'Guaynabo Municipio, PR': '061',
'Gurabo Municipio, PR': '063',
'Hatillo Municipio, PR': '065',
'Hormigueros Municipio, PR': '067',
'Humacao Municipio, PR': '069',
'Isabela Municipio, PR': '071',
'Jayuya Municipio, PR': '073',
'Juana Diaz Municipio, PR': '075',
'Juncos Municipio, PR': '077',
'Lajas Municipio, PR': '079',
'Lares Municipio, PR': '081',
'Las Marias Municipio, PR': '083',
'Las Piedras Municipio, PR': '085',
'Loiza Municipio, PR': '087',
'Luquillo Municipio, PR': '089',
'Manati Municipio, PR': '091',
'Maricao Municipio, PR': '093',
'Maunabo Municipio, PR': '095',
'Mayaguez Municipio, PR': '097',
'Moca Municipio, PR': '099',
'Morovis Municipio, PR': '101',
'Naguabo Municipio, PR': '103',
'Naranjito Municipio, PR': '105',
'Orocovis Municipio, PR': '107',
'Patillas Municipio, PR': '109',
'Penuelas Municipio, PR': '111',
'Ponce Municipio, PR': '113',
'Quebradillas Municipio, PR': '115',
'Rincon Municipio, PR': '117',
'Rio Grande Municipio, PR': '119',
'Sabana Grande Municipio, PR': '121',
'Salinas Municipio, PR': '123',
'San German Municipio, PR': '125',
'San Juan Municipio, PR': '127',
'San Lorenzo Municipio, PR': '129',
'San Sebastian Municipio, PR': '131',
'Santa Isabel Municipio, PR': '133',
'Toa Alta Municipio, PR': '135',
'Toa Baja Municipio, PR': '137',
'Trujillo Alto Municipio, PR': '139',
'Utuado Municipio, PR': '141',
'Vega Alta Municipio, PR': '143',
'Vega Baja Municipio, PR': '145',
'Vieques Municipio, PR': '147',
'Villalba Municipio, PR': '149',
'Yabucoa Municipio, PR': '151',
'Yauco Municipio, PR': '153'},
"CA01": { '--All--': '%', },
"CA02": { '--All--': '%', },
"CA03": { '--All--': '%', },
"CA04": { '--All--': '%', },
"CA05": { '--All--': '%', },
"CA13": { '--All--': '%', },
"CA07": { '--All--': '%', },
"CA14": { '--All--': '%', },
"CA08": { '--All--': '%', },
"CA09": { '--All--': '%', },
"CA10": { '--All--': '%', },
"CA11": { '--All--': '%', },
"CA12": { '--All--': '%', },
}
if __name__ == "__main__":
from sys import argv
from pprint import PrettyPrinter
pp = PrettyPrinter(indent=2)
import csv
fipsreader = csv.reader(open(argv[1],'rb'), delimiter=',', quotechar='"')
for row in fipsreader:
try:
FIPS_COUNTIES[int(row[1])][row[3]] = row[2]
except KeyError:
FIPS_COUNTIES[int(row[1])] = {'--All--': '%'}
FIPS_COUNTIES[int(row[1])][row[3]] = row[2]
pp.pprint(FIPS_COUNTIES)
chirp-0.3.1/share/ 0000755 0000161 0177776 00000000000 12130403637 015116 5 ustar jenkins nogroup 0000000 0000000 chirp-0.3.1/share/chirp.png 0000644 0000161 0000750 00000022727 11717005656 015313 0 ustar jenkins 0000000 0000000 ‰PNG
IHDR ÿ h >k&1 sBIT|dˆ pHYs
×
×B(›x tEXtSoftware www.inkscape.org›î< IDATxœíy|ÕÚÇ3™$ÝÓ–¦mé-´¥ÊÚBYd‡{yµ_à*Vy¯+‚x\P/ïå•÷¾(ÈEe¸ˆ ˆ€¥‚ÚÒ
ººo”¦K–™yÿh3$m’&™$Mh¾ŸO>Éœ9ó<çLæ9Ûœó‚eYA) –‹Åâ‘AxÐ4M)•JÂhNœ8±$I²$I*Y–•Ñ4`3˲G½žèÍø ‚p°W,'ËårAdd$’’’ˆ€€ H$˜R€ØÖH³#Ü{Ï·#ÜCÀòé4UI’¨©©AII nß¾ŒŒ¶¹¹™*š¦HeY¶ÍƒÆOÄF‘H´R(
ž{î9Ìš5&%²/!ˆžK‡9õôL{Óm2322ðñÇãØ±c`FÅ0ÌG,ËþI§`è1~‚ \(ŠºÆ²lÌ3Ï<ƒÅ‹ÃÃÃCŸ»Äù:žkÈ´7ݶYUU…W^yçÎA¹ÃŒfY¶£Ç5ÝŸ ˆ±XœáêêêµiÓ&>\§2{Çþ´M5dÚ›nGÒóõ×_ã…^ MÓÍ4MdY¶D+ަñá&‹«ƒ‚‚<·nÝ
‰rœ¡ý걆L{Óm/2³³³1{öl¶…¦é Íq RóŠ¢®º¸¸ôÃwdÝ}©Ç2ÿud>§OŸ&H’ô"Iòªæ9Îø ‚Ø æ£>rhÃ7¾¥°-tÛ£{K»£Ü7cõXZf||<>ýôS°,Óeç ºŒŸ 7‘HôʳÏ>ë°}|5ÎÄ~ô8kxû‘9þ|Ìœ9$I¾Lt¾¾çjþ]b±XðÌ3ÏðR`¯ô×ÄQk*SÂl¥Ûõ˜*óŸÿü'H’¤ 캌_$=±dɸ¹¹ñJ̃ˆ#?¶Òã¬á«ÇR2ýýý‘œœ’$ç ID²B¡LŸ>ÝâJm³±®kÈì÷Íž
×_|ÃPA$S ^4h‚ƒƒy%ÐÑÑwƒÛÚÚŸŸœœ¦i º§cªÃ4Ïu#Âàysd›š]ñ¹V},þîa¦Ü#’$áêê
www¸»»ÃÃÃQQQˆ‹‹C\\$I´âA/\áááÁÊd²—(±X