Rewrote geolocation code (more features and size optimisations coming soon

This commit is contained in:
Luke Rogers 2012-09-05 16:25:51 +12:00
parent 4562f59cab
commit 21153b8246
7 changed files with 2163 additions and 38 deletions

647
lib/pygeoip/__init__.py Normal file
View File

@ -0,0 +1,647 @@
"""
Pure Python GeoIP API. The API is based off of U{MaxMind's C-based Python API<http://www.maxmind.com/app/python>},
but the code itself is based on the U{pure PHP5 API<http://pear.php.net/package/Net_GeoIP/>}
by Jim Winstead and Hans Lellelid.
It is mostly a drop-in replacement, except the
C{new} and C{open} methods are gone. You should instantiate the L{GeoIP} class yourself:
C{gi = GeoIP('/path/to/GeoIP.dat', pygeoip.MEMORY_CACHE)}
@author: Jennifer Ennis <zaylea at gmail dot com>
@license:
Copyright(C) 2004 MaxMind LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
"""
from __future__ import with_statement, absolute_import, division
import os
import math
import socket
import mmap
import gzip
import codecs
from StringIO import StringIO
from . import const
from .util import ip2long
from .timezone import time_zone_by_country_and_region
import six
MMAP_CACHE = const.MMAP_CACHE
MEMORY_CACHE = const.MEMORY_CACHE
STANDARD = const.STANDARD
class GeoIPError(Exception):
pass
class GeoIPMetaclass(type):
def __new__(cls, *args, **kwargs):
"""
Singleton method to gets an instance without reparsing the db. Unique
instances are instantiated based on the filename of the db. Flags are
ignored for this, i.e. if you initialize one with STANDARD flag (default)
and then try later to initialize with MEMORY_CACHE, it will still
return the STANDARD one.
"""
if not hasattr(cls, '_instances'):
cls._instances = {}
if len(args) > 0:
filename = args[0]
elif 'filename' in kwargs:
filename = kwargs['filename']
if not filename in cls._instances:
cls._instances[filename] = type.__new__(cls, *args, **kwargs)
return cls._instances[filename]
GeoIPBase = GeoIPMetaclass('GeoIPBase', (object,), {})
class GeoIP(GeoIPBase):
def __init__(self, filename, flags=0):
"""
Initialize the class.
@param filename: path to a geoip database. If MEMORY_CACHE is used,
the file can be gzipped.
@type filename: str
@param flags: flags that affect how the database is processed.
Currently the only supported flags are STANDARD (the default),
MEMORY_CACHE (preload the whole file into memory), and
MMAP_CACHE (access the file via mmap).
@type flags: int
"""
self._filename = filename
self._flags = flags
if self._flags & const.MMAP_CACHE:
with open(filename, 'rb') as f:
self._filehandle = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
elif self._flags & const.MEMORY_CACHE:
if filename.endswith('.gz'):
opener = gzip.open
else:
opener = open
with opener(filename, 'rb') as f:
self._memoryBuffer = f.read()
self._filehandle = StringIO(self._memoryBuffer)
else:
self._filehandle = codecs.open(filename, 'rb','latin_1')
self._setup_segments()
def _setup_segments(self):
"""
Parses the database file to determine what kind of database is being used and setup
segment sizes and start points that will be used by the seek*() methods later.
"""
self._databaseType = const.COUNTRY_EDITION
self._recordLength = const.STANDARD_RECORD_LENGTH
filepos = self._filehandle.tell()
self._filehandle.seek(-3, os.SEEK_END)
for i in range(const.STRUCTURE_INFO_MAX_SIZE):
delim = self._filehandle.read(3)
if delim == six.u(chr(255) * 3):
self._databaseType = ord(self._filehandle.read(1))
if (self._databaseType >= 106):
# backwards compatibility with databases from April 2003 and earlier
self._databaseType -= 105
if self._databaseType == const.REGION_EDITION_REV0:
self._databaseSegments = const.STATE_BEGIN_REV0
elif self._databaseType == const.REGION_EDITION_REV1:
self._databaseSegments = const.STATE_BEGIN_REV1
elif self._databaseType in (const.CITY_EDITION_REV0,
const.CITY_EDITION_REV1,
const.ORG_EDITION,
const.ISP_EDITION,
const.ASNUM_EDITION):
self._databaseSegments = 0
buf = self._filehandle.read(const.SEGMENT_RECORD_LENGTH)
for j in range(const.SEGMENT_RECORD_LENGTH):
self._databaseSegments += (ord(buf[j]) << (j * 8))
if self._databaseType in (const.ORG_EDITION, const.ISP_EDITION):
self._recordLength = const.ORG_RECORD_LENGTH
break
else:
self._filehandle.seek(-4, os.SEEK_CUR)
if self._databaseType == const.COUNTRY_EDITION:
self._databaseSegments = const.COUNTRY_BEGIN
self._filehandle.seek(filepos, os.SEEK_SET)
def _lookup_country_id(self, addr):
"""
Get the country index.
This method is called by the _lookupCountryCode and _lookupCountryName
methods. It looks up the index ('id') for the country which is the key
for the code and name.
@param addr: The IP address
@type addr: str
@return: network byte order 32-bit integer
@rtype: int
"""
ipnum = ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
if self._databaseType != const.COUNTRY_EDITION:
raise GeoIPError('Invalid database type; country_* methods expect '\
'Country database')
return self._seek_country(ipnum) - const.COUNTRY_BEGIN
def _seek_country(self, ipnum):
"""
Using the record length and appropriate start points, seek to the
country that corresponds to the converted IP address integer.
@param ipnum: result of ip2long conversion
@type ipnum: int
@return: offset of start of record
@rtype: int
"""
offset = 0
for depth in range(31, -1, -1):
if self._flags & const.MEMORY_CACHE:
startIndex = 2 * self._recordLength * offset
length = 2 * self._recordLength
endIndex = startIndex + length
buf = self._memoryBuffer[startIndex:endIndex]
else:
self._filehandle.seek(2 * self._recordLength * offset, os.SEEK_SET)
buf = self._filehandle.read(2 * self._recordLength)
x = [0,0]
for i in range(2):
for j in range(self._recordLength):
x[i] += ord(buf[self._recordLength * i + j]) << (j * 8)
if ipnum & (1 << depth):
if x[1] >= self._databaseSegments:
return x[1]
offset = x[1]
else:
if x[0] >= self._databaseSegments:
return x[0]
offset = x[0]
raise Exception('Error traversing database - perhaps it is corrupt?')
def _get_org(self, ipnum):
"""
Seek and return organization (or ISP) name for converted IP addr.
@param ipnum: Converted IP address
@type ipnum: int
@return: org/isp name
@rtype: str
"""
seek_org = self._seek_country(ipnum)
if seek_org == self._databaseSegments:
return None
record_pointer = seek_org + (2 * self._recordLength - 1) * self._databaseSegments
self._filehandle.seek(record_pointer, os.SEEK_SET)
org_buf = self._filehandle.read(const.MAX_ORG_RECORD_LENGTH)
return org_buf[:org_buf.index(chr(0))]
def _get_region(self, ipnum):
"""
Seek and return the region info (dict containing country_code and region_name).
@param ipnum: converted IP address
@type ipnum: int
@return: dict containing country_code and region_name
@rtype: dict
"""
country_code = ''
region = ''
if self._databaseType == const.REGION_EDITION_REV0:
seek_country = self._seek_country(ipnum)
seek_region = seek_country - const.STATE_BEGIN_REV0
if seek_region >= 1000:
country_code = 'US'
region = ''.join([chr((seek_region // 1000) // 26 + 65), chr((seek_region // 1000) % 26 + 65)])
else:
country_code = const.COUNTRY_CODES[seek_region]
region = ''
elif self._databaseType == const.REGION_EDITION_REV1:
seek_country = self._seek_country(ipnum)
seek_region = seek_country - const.STATE_BEGIN_REV1
if seek_region < const.US_OFFSET:
country_code = '';
region = ''
elif seek_region < const.CANADA_OFFSET:
country_code = 'US'
region = ''.join([chr((seek_region - const.US_OFFSET) // 26 + 65), chr((seek_region - const.US_OFFSET) % 26 + 65)])
elif seek_region < const.WORLD_OFFSET:
country_code = 'CA'
region = ''.join([chr((seek_region - const.CANADA_OFFSET) // 26 + 65), chr((seek_region - const.CANADA_OFFSET) % 26 + 65)])
else:
i = (seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE
if i < len(const.COUNTRY_CODES):
#country_code = const.COUNTRY_CODES[(seek_region - const.WORLD_OFFSET) // const.FIPS_RANGE]
country_code = const.COUNTRY_CODES[i]
else:
country_code = ''
region = ''
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
rec = self._get_record(ipnum)
country_code = rec['country_code'] if 'country_code' in rec else ''
region = rec['region_name'] if 'region_name' in rec else ''
return {'country_code' : country_code, 'region_name' : region }
def _get_record(self, ipnum):
"""
Populate location dict for converted IP.
@param ipnum: converted IP address
@type ipnum: int
@return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
@rtype: dict
"""
seek_country = self._seek_country(ipnum)
if seek_country == self._databaseSegments:
return None
record_pointer = seek_country + (2 * self._recordLength - 1) * self._databaseSegments
self._filehandle.seek(record_pointer, os.SEEK_SET)
record_buf = self._filehandle.read(const.FULL_RECORD_LENGTH)
record = {}
record_buf_pos = 0
char = ord(record_buf[record_buf_pos])
#char = record_buf[record_buf_pos] if six.PY3 else ord(record_buf[record_buf_pos])
record['country_code'] = const.COUNTRY_CODES[char]
record['country_code3'] = const.COUNTRY_CODES3[char]
record['country_name'] = const.COUNTRY_NAMES[char]
record_buf_pos += 1
str_length = 0
# get region
char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
if str_length > 0:
record['region_name'] = record_buf[record_buf_pos:record_buf_pos+str_length]
record_buf_pos += str_length + 1
str_length = 0
# get city
char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
if str_length > 0:
record['city'] = record_buf[record_buf_pos:record_buf_pos+str_length]
else:
record['city'] = ''
record_buf_pos += str_length + 1
str_length = 0
# get the postal code
char = ord(record_buf[record_buf_pos+str_length])
while (char != 0):
str_length += 1
char = ord(record_buf[record_buf_pos+str_length])
if str_length > 0:
record['postal_code'] = record_buf[record_buf_pos:record_buf_pos+str_length]
else:
record['postal_code'] = None
record_buf_pos += str_length + 1
str_length = 0
latitude = 0
longitude = 0
for j in range(3):
char = ord(record_buf[record_buf_pos])
record_buf_pos += 1
latitude += (char << (j * 8))
record['latitude'] = (latitude/10000.0) - 180.0
for j in range(3):
char = ord(record_buf[record_buf_pos])
record_buf_pos += 1
longitude += (char << (j * 8))
record['longitude'] = (longitude/10000.0) - 180.0
if self._databaseType == const.CITY_EDITION_REV1:
dmaarea_combo = 0
if record['country_code'] == 'US':
for j in range(3):
char = ord(record_buf[record_buf_pos])
record_buf_pos += 1
dmaarea_combo += (char << (j*8))
record['dma_code'] = int(math.floor(dmaarea_combo/1000))
record['area_code'] = dmaarea_combo%1000
else:
record['dma_code'] = 0
record['area_code'] = 0
if 'dma_code' in record and record['dma_code'] in const.DMA_MAP:
record['metro_code'] = const.DMA_MAP[record['dma_code']]
else:
record['metro_code'] = ''
if 'country_code' in record:
record['time_zone'] = time_zone_by_country_and_region(
record['country_code'], record.get('region_name')) or ''
else:
record['time_zone'] = ''
return record
def country_code_by_addr(self, addr):
"""
Returns 2-letter country code (e.g. 'US') for specified IP address.
Use this method if you have a Country, Region, or City database.
@param addr: IP address
@type addr: str
@return: 2-letter country code
@rtype: str
"""
try:
if self._databaseType == const.COUNTRY_EDITION:
country_id = self._lookup_country_id(addr)
return const.COUNTRY_CODES[country_id]
elif self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
return self.region_by_addr(addr)['country_code']
else:
raise GeoIPError('Invalid database type; country_* methods expect '\
'Country, City, or Region database')
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
def country_code_by_name(self, hostname):
"""
Returns 2-letter country code (e.g. 'US') for specified hostname.
Use this method if you have a Country, Region, or City database.
@param hostname: host name
@type hostname: str
@return: 2-letter country code
@rtype: str
"""
addr = socket.gethostbyname(hostname)
return self.country_code_by_addr(addr)
def country_name_by_addr(self, addr):
"""
Returns full country name for specified IP address.
Use this method if you have a Country or City database.
@param addr: IP address
@type addr: str
@return: country name
@rtype: str
"""
try:
if self._databaseType == const.COUNTRY_EDITION:
country_id = self._lookup_country_id(addr)
return const.COUNTRY_NAMES[country_id]
elif self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
return self.record_by_addr(addr)['country_name']
else:
raise GeoIPError('Invalid database type; country_* methods expect '\
'Country or City database')
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
def country_name_by_name(self, hostname):
"""
Returns full country name for specified hostname.
Use this method if you have a Country database.
@param hostname: host name
@type hostname: str
@return: country name
@rtype: str
"""
addr = socket.gethostbyname(hostname)
return self.country_name_by_addr(addr)
def org_by_addr(self, addr):
"""
Lookup the organization (or ISP) for given IP address.
Use this method if you have an Organization/ISP database.
@param addr: IP address
@type addr: str
@return: organization or ISP name
@rtype: str
"""
try:
ipnum = ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
if self._databaseType not in (const.ORG_EDITION, const.ISP_EDITION, const.ASNUM_EDITION):
raise GeoIPError('Invalid database type; org_* methods expect '\
'Org/ISP database')
return self._get_org(ipnum)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
def org_by_name(self, hostname):
"""
Lookup the organization (or ISP) for hostname.
Use this method if you have an Organization/ISP database.
@param hostname: host name
@type hostname: str
@return: organization or ISP name
@rtype: str
"""
addr = socket.gethostbyname(hostname)
return self.org_by_addr(addr)
def record_by_addr(self, addr):
"""
Look up the record for a given IP address.
Use this method if you have a City database.
@param addr: IP address
@type addr: str
@return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
@rtype: dict
"""
try:
ipnum = ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
if not self._databaseType in (const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; record_* methods expect City database')
return self._get_record(ipnum)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
def record_by_name(self, hostname):
"""
Look up the record for a given hostname.
Use this method if you have a City database.
@param hostname: host name
@type hostname: str
@return: dict with country_code, country_code3, country_name,
region, city, postal_code, latitude, longitude,
dma_code, metro_code, area_code, region_name, time_zone
@rtype: dict
"""
addr = socket.gethostbyname(hostname)
return self.record_by_addr(addr)
def region_by_addr(self, addr):
"""
Lookup the region for given IP address.
Use this method if you have a Region database.
@param addr: IP address
@type addr: str
@return: dict containing country_code, region,
and region_name
@rtype: dict
"""
try:
ipnum = ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; region_* methods expect '\
'Region or City database')
return self._get_region(ipnum)
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
def region_by_name(self, hostname):
"""
Lookup the region for given hostname.
Use this method if you have a Region database.
@param hostname: host name
@type hostname: str
@return: dict containing country_code, region,
and region_name
@rtype: dict
"""
addr = socket.gethostbyname(hostname)
return self.region_by_addr(addr)
def time_zone_by_addr(self, addr):
"""
Look up the time zone for a given IP address.
Use this method if you have a Region or City database.
@param hostname: IP address
@type hostname: str
@return: Time zone
@rtype: str
"""
try:
ipnum = ip2long(addr)
if not ipnum:
raise ValueError("Invalid IP address: %s" % addr)
if not self._databaseType in (const.REGION_EDITION_REV0, const.REGION_EDITION_REV1,
const.CITY_EDITION_REV0, const.CITY_EDITION_REV1):
raise GeoIPError('Invalid database type; region_* methods expect '\
'Region or City database')
return self._get_record(ipnum)['time_zone']
except ValueError:
raise GeoIPError('*_by_addr methods only accept IP addresses. Use *_by_name for hostnames. (Address: %s)' % addr)
def time_zone_by_name(self, hostname):
"""
Look up the time zone for a given hostname.
Use this method if you have a Region or City database.
@param hostname: host name
@type hostname: str
@return: Time zone
@rtype: str
"""
addr = socket.gethostbyname(hostname)
return self.time_zone_by_addr(addr)

382
lib/pygeoip/const.py Normal file
View File

@ -0,0 +1,382 @@
"""
Constants needed for parsing binary GeoIP databases. It is part of the pygeoip
package.
@author: Jennifer Ennis <zaylea at gmail dot com>
@license:
Copyright(C) 2004 MaxMind LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
"""
GEOIP_STANDARD = 0
GEOIP_MEMORY_CACHE = 1
DMA_MAP = {
500 : 'Portland-Auburn, ME',
501 : 'New York, NY',
502 : 'Binghamton, NY',
503 : 'Macon, GA',
504 : 'Philadelphia, PA',
505 : 'Detroit, MI',
506 : 'Boston, MA',
507 : 'Savannah, GA',
508 : 'Pittsburgh, PA',
509 : 'Ft Wayne, IN',
510 : 'Cleveland, OH',
511 : 'Washington, DC',
512 : 'Baltimore, MD',
513 : 'Flint, MI',
514 : 'Buffalo, NY',
515 : 'Cincinnati, OH',
516 : 'Erie, PA',
517 : 'Charlotte, NC',
518 : 'Greensboro, NC',
519 : 'Charleston, SC',
520 : 'Augusta, GA',
521 : 'Providence, RI',
522 : 'Columbus, GA',
523 : 'Burlington, VT',
524 : 'Atlanta, GA',
525 : 'Albany, GA',
526 : 'Utica-Rome, NY',
527 : 'Indianapolis, IN',
528 : 'Miami, FL',
529 : 'Louisville, KY',
530 : 'Tallahassee, FL',
531 : 'Tri-Cities, TN',
532 : 'Albany-Schenectady-Troy, NY',
533 : 'Hartford, CT',
534 : 'Orlando, FL',
535 : 'Columbus, OH',
536 : 'Youngstown-Warren, OH',
537 : 'Bangor, ME',
538 : 'Rochester, NY',
539 : 'Tampa, FL',
540 : 'Traverse City-Cadillac, MI',
541 : 'Lexington, KY',
542 : 'Dayton, OH',
543 : 'Springfield-Holyoke, MA',
544 : 'Norfolk-Portsmouth, VA',
545 : 'Greenville-New Bern-Washington, NC',
546 : 'Columbia, SC',
547 : 'Toledo, OH',
548 : 'West Palm Beach, FL',
549 : 'Watertown, NY',
550 : 'Wilmington, NC',
551 : 'Lansing, MI',
552 : 'Presque Isle, ME',
553 : 'Marquette, MI',
554 : 'Wheeling, WV',
555 : 'Syracuse, NY',
556 : 'Richmond-Petersburg, VA',
557 : 'Knoxville, TN',
558 : 'Lima, OH',
559 : 'Bluefield-Beckley-Oak Hill, WV',
560 : 'Raleigh-Durham, NC',
561 : 'Jacksonville, FL',
563 : 'Grand Rapids, MI',
564 : 'Charleston-Huntington, WV',
565 : 'Elmira, NY',
566 : 'Harrisburg-Lancaster-Lebanon-York, PA',
567 : 'Greenville-Spartenburg, SC',
569 : 'Harrisonburg, VA',
570 : 'Florence-Myrtle Beach, SC',
571 : 'Ft Myers, FL',
573 : 'Roanoke-Lynchburg, VA',
574 : 'Johnstown-Altoona, PA',
575 : 'Chattanooga, TN',
576 : 'Salisbury, MD',
577 : 'Wilkes Barre-Scranton, PA',
581 : 'Terre Haute, IN',
582 : 'Lafayette, IN',
583 : 'Alpena, MI',
584 : 'Charlottesville, VA',
588 : 'South Bend, IN',
592 : 'Gainesville, FL',
596 : 'Zanesville, OH',
597 : 'Parkersburg, WV',
598 : 'Clarksburg-Weston, WV',
600 : 'Corpus Christi, TX',
602 : 'Chicago, IL',
603 : 'Joplin-Pittsburg, MO',
604 : 'Columbia-Jefferson City, MO',
605 : 'Topeka, KS',
606 : 'Dothan, AL',
609 : 'St Louis, MO',
610 : 'Rockford, IL',
611 : 'Rochester-Mason City-Austin, MN',
612 : 'Shreveport, LA',
613 : 'Minneapolis-St Paul, MN',
616 : 'Kansas City, MO',
617 : 'Milwaukee, WI',
618 : 'Houston, TX',
619 : 'Springfield, MO',
620 : 'Tuscaloosa, AL',
622 : 'New Orleans, LA',
623 : 'Dallas-Fort Worth, TX',
624 : 'Sioux City, IA',
625 : 'Waco-Temple-Bryan, TX',
626 : 'Victoria, TX',
627 : 'Wichita Falls, TX',
628 : 'Monroe, LA',
630 : 'Birmingham, AL',
631 : 'Ottumwa-Kirksville, IA',
632 : 'Paducah, KY',
633 : 'Odessa-Midland, TX',
634 : 'Amarillo, TX',
635 : 'Austin, TX',
636 : 'Harlingen, TX',
637 : 'Cedar Rapids-Waterloo, IA',
638 : 'St Joseph, MO',
639 : 'Jackson, TN',
640 : 'Memphis, TN',
641 : 'San Antonio, TX',
642 : 'Lafayette, LA',
643 : 'Lake Charles, LA',
644 : 'Alexandria, LA',
646 : 'Anniston, AL',
647 : 'Greenwood-Greenville, MS',
648 : 'Champaign-Springfield-Decatur, IL',
649 : 'Evansville, IN',
650 : 'Oklahoma City, OK',
651 : 'Lubbock, TX',
652 : 'Omaha, NE',
656 : 'Panama City, FL',
657 : 'Sherman, TX',
658 : 'Green Bay-Appleton, WI',
659 : 'Nashville, TN',
661 : 'San Angelo, TX',
662 : 'Abilene-Sweetwater, TX',
669 : 'Madison, WI',
670 : 'Ft Smith-Fay-Springfield, AR',
671 : 'Tulsa, OK',
673 : 'Columbus-Tupelo-West Point, MS',
675 : 'Peoria-Bloomington, IL',
676 : 'Duluth, MN',
678 : 'Wichita, KS',
679 : 'Des Moines, IA',
682 : 'Davenport-Rock Island-Moline, IL',
686 : 'Mobile, AL',
687 : 'Minot-Bismarck-Dickinson, ND',
691 : 'Huntsville, AL',
692 : 'Beaumont-Port Author, TX',
693 : 'Little Rock-Pine Bluff, AR',
698 : 'Montgomery, AL',
702 : 'La Crosse-Eau Claire, WI',
705 : 'Wausau-Rhinelander, WI',
709 : 'Tyler-Longview, TX',
710 : 'Hattiesburg-Laurel, MS',
711 : 'Meridian, MS',
716 : 'Baton Rouge, LA',
717 : 'Quincy, IL',
718 : 'Jackson, MS',
722 : 'Lincoln-Hastings, NE',
724 : 'Fargo-Valley City, ND',
725 : 'Sioux Falls, SD',
734 : 'Jonesboro, AR',
736 : 'Bowling Green, KY',
737 : 'Mankato, MN',
740 : 'North Platte, NE',
743 : 'Anchorage, AK',
744 : 'Honolulu, HI',
745 : 'Fairbanks, AK',
746 : 'Biloxi-Gulfport, MS',
747 : 'Juneau, AK',
749 : 'Laredo, TX',
751 : 'Denver, CO',
752 : 'Colorado Springs, CO',
753 : 'Phoenix, AZ',
754 : 'Butte-Bozeman, MT',
755 : 'Great Falls, MT',
756 : 'Billings, MT',
757 : 'Boise, ID',
758 : 'Idaho Falls-Pocatello, ID',
759 : 'Cheyenne, WY',
760 : 'Twin Falls, ID',
762 : 'Missoula, MT',
764 : 'Rapid City, SD',
765 : 'El Paso, TX',
766 : 'Helena, MT',
767 : 'Casper-Riverton, WY',
770 : 'Salt Lake City, UT',
771 : 'Yuma, AZ',
773 : 'Grand Junction, CO',
789 : 'Tucson, AZ',
790 : 'Albuquerque, NM',
798 : 'Glendive, MT',
800 : 'Bakersfield, CA',
801 : 'Eugene, OR',
802 : 'Eureka, CA',
803 : 'Los Angeles, CA',
804 : 'Palm Springs, CA',
807 : 'San Francisco, CA',
810 : 'Yakima-Pasco, WA',
811 : 'Reno, NV',
813 : 'Medford-Klamath Falls, OR',
819 : 'Seattle-Tacoma, WA',
820 : 'Portland, OR',
821 : 'Bend, OR',
825 : 'San Diego, CA',
828 : 'Monterey-Salinas, CA',
839 : 'Las Vegas, NV',
855 : 'Santa Barbara, CA',
862 : 'Sacramento, CA',
866 : 'Fresno, CA',
868 : 'Chico-Redding, CA',
881 : 'Spokane, WA'
}
COUNTRY_CODES = (
'', 'AP', 'EU', 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ',
'AR', 'AS', 'AT', 'AU', 'AW', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH',
'BI', 'BJ', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ', 'CA',
'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',
'CV', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG',
'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'FX', 'GA', 'GB',
'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT',
'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN',
'IO', 'IQ', 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM',
'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS',
'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN',
'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA',
'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA',
'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY',
'QA', 'RE', 'RO', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI',
'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY', 'SZ', 'TC', 'TD',
'TF', 'TG', 'TH', 'TJ', 'TK', 'TM', 'TN', 'TO', 'TL', 'TR', 'TT', 'TV', 'TW',
'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN',
'VU', 'WF', 'WS', 'YE', 'YT', 'RS', 'ZA', 'ZM', 'ME', 'ZW', 'A1', 'A2', 'O1',
'AX', 'GG', 'IM', 'JE', 'BL', 'MF'
)
COUNTRY_CODES3 = (
'','AP','EU','AND','ARE','AFG','ATG','AIA','ALB','ARM','ANT','AGO','AQ','ARG',
'ASM','AUT','AUS','ABW','AZE','BIH','BRB','BGD','BEL','BFA','BGR','BHR','BDI',
'BEN','BMU','BRN','BOL','BRA','BHS','BTN','BV','BWA','BLR','BLZ','CAN','CC',
'COD','CAF','COG','CHE','CIV','COK','CHL','CMR','CHN','COL','CRI','CUB','CPV',
'CX','CYP','CZE','DEU','DJI','DNK','DMA','DOM','DZA','ECU','EST','EGY','ESH',
'ERI','ESP','ETH','FIN','FJI','FLK','FSM','FRO','FRA','FX','GAB','GBR','GRD',
'GEO','GUF','GHA','GIB','GRL','GMB','GIN','GLP','GNQ','GRC','GS','GTM','GUM',
'GNB','GUY','HKG','HM','HND','HRV','HTI','HUN','IDN','IRL','ISR','IND','IO',
'IRQ','IRN','ISL','ITA','JAM','JOR','JPN','KEN','KGZ','KHM','KIR','COM','KNA',
'PRK','KOR','KWT','CYM','KAZ','LAO','LBN','LCA','LIE','LKA','LBR','LSO','LTU',
'LUX','LVA','LBY','MAR','MCO','MDA','MDG','MHL','MKD','MLI','MMR','MNG','MAC',
'MNP','MTQ','MRT','MSR','MLT','MUS','MDV','MWI','MEX','MYS','MOZ','NAM','NCL',
'NER','NFK','NGA','NIC','NLD','NOR','NPL','NRU','NIU','NZL','OMN','PAN','PER',
'PYF','PNG','PHL','PAK','POL','SPM','PCN','PRI','PSE','PRT','PLW','PRY','QAT',
'REU','ROU','RUS','RWA','SAU','SLB','SYC','SDN','SWE','SGP','SHN','SVN','SJM',
'SVK','SLE','SMR','SEN','SOM','SUR','STP','SLV','SYR','SWZ','TCA','TCD','TF',
'TGO','THA','TJK','TKL','TLS','TKM','TUN','TON','TUR','TTO','TUV','TWN','TZA',
'UKR','UGA','UM','USA','URY','UZB','VAT','VCT','VEN','VGB','VIR','VNM','VUT',
'WLF','WSM','YEM','YT','SRB','ZAF','ZMB','MNE','ZWE','A1','A2','O1',
'ALA','GGY','IMN','JEY','BLM','MAF'
)
COUNTRY_NAMES = (
"", "Asia/Pacific Region", "Europe", "Andorra", "United Arab Emirates",
"Afghanistan", "Antigua and Barbuda", "Anguilla", "Albania", "Armenia",
"Netherlands Antilles", "Angola", "Antarctica", "Argentina", "American Samoa",
"Austria", "Australia", "Aruba", "Azerbaijan", "Bosnia and Herzegovina",
"Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria", "Bahrain",
"Burundi", "Benin", "Bermuda", "Brunei Darussalam", "Bolivia", "Brazil",
"Bahamas", "Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize",
"Canada", "Cocos (Keeling) Islands", "Congo, The Democratic Republic of the",
"Central African Republic", "Congo", "Switzerland", "Cote D'Ivoire", "Cook Islands",
"Chile", "Cameroon", "China", "Colombia", "Costa Rica", "Cuba", "Cape Verde",
"Christmas Island", "Cyprus", "Czech Republic", "Germany", "Djibouti",
"Denmark", "Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia",
"Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia", "Finland", "Fiji",
"Falkland Islands (Malvinas)", "Micronesia, Federated States of", "Faroe Islands",
"France", "France, Metropolitan", "Gabon", "United Kingdom",
"Grenada", "Georgia", "French Guiana", "Ghana", "Gibraltar", "Greenland",
"Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece",
"South Georgia and the South Sandwich Islands",
"Guatemala", "Guam", "Guinea-Bissau",
"Guyana", "Hong Kong", "Heard Island and McDonald Islands", "Honduras",
"Croatia", "Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "India",
"British Indian Ocean Territory", "Iraq", "Iran, Islamic Republic of",
"Iceland", "Italy", "Jamaica", "Jordan", "Japan", "Kenya", "Kyrgyzstan",
"Cambodia", "Kiribati", "Comoros", "Saint Kitts and Nevis",
"Korea, Democratic People's Republic of",
"Korea, Republic of", "Kuwait", "Cayman Islands",
"Kazakstan", "Lao People's Democratic Republic", "Lebanon", "Saint Lucia",
"Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg",
"Latvia", "Libyan Arab Jamahiriya", "Morocco", "Monaco", "Moldova, Republic of",
"Madagascar", "Marshall Islands", "Macedonia",
"Mali", "Myanmar", "Mongolia", "Macau", "Northern Mariana Islands",
"Martinique", "Mauritania", "Montserrat", "Malta", "Mauritius", "Maldives",
"Malawi", "Mexico", "Malaysia", "Mozambique", "Namibia", "New Caledonia",
"Niger", "Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway",
"Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru", "French Polynesia",
"Papua New Guinea", "Philippines", "Pakistan", "Poland", "Saint Pierre and Miquelon",
"Pitcairn Islands", "Puerto Rico", "Palestinian Territory",
"Portugal", "Palau", "Paraguay", "Qatar", "Reunion", "Romania",
"Russian Federation", "Rwanda", "Saudi Arabia", "Solomon Islands",
"Seychelles", "Sudan", "Sweden", "Singapore", "Saint Helena", "Slovenia",
"Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino", "Senegal",
"Somalia", "Suriname", "Sao Tome and Principe", "El Salvador", "Syrian Arab Republic",
"Swaziland", "Turks and Caicos Islands", "Chad", "French Southern Territories",
"Togo", "Thailand", "Tajikistan", "Tokelau", "Turkmenistan",
"Tunisia", "Tonga", "Timor-Leste", "Turkey", "Trinidad and Tobago", "Tuvalu",
"Taiwan", "Tanzania, United Republic of", "Ukraine",
"Uganda", "United States Minor Outlying Islands", "United States", "Uruguay",
"Uzbekistan", "Holy See (Vatican City State)", "Saint Vincent and the Grenadines",
"Venezuela", "Virgin Islands, British", "Virgin Islands, U.S.",
"Vietnam", "Vanuatu", "Wallis and Futuna", "Samoa", "Yemen", "Mayotte",
"Serbia", "South Africa", "Zambia", "Montenegro", "Zimbabwe",
"Anonymous Proxy","Satellite Provider","Other",
"Aland Islands","Guernsey","Isle of Man","Jersey","Saint Barthelemy","Saint Martin"
)
# storage / caching flags
STANDARD = 0
MEMORY_CACHE = 1
MMAP_CACHE = 8
# Database structure constants
COUNTRY_BEGIN = 16776960
STATE_BEGIN_REV0 = 16700000
STATE_BEGIN_REV1 = 16000000
STRUCTURE_INFO_MAX_SIZE = 20
DATABASE_INFO_MAX_SIZE = 100
# Database editions
COUNTRY_EDITION = 1
REGION_EDITION_REV0 = 7
REGION_EDITION_REV1 = 3
CITY_EDITION_REV0 = 6
CITY_EDITION_REV1 = 2
ORG_EDITION = 5
ISP_EDITION = 4
PROXY_EDITION = 8
ASNUM_EDITION = 9
NETSPEED_EDITION = 11
COUNTRY_EDITION_V6 = 12
SEGMENT_RECORD_LENGTH = 3
STANDARD_RECORD_LENGTH = 3
ORG_RECORD_LENGTH = 4
MAX_RECORD_LENGTH = 4
MAX_ORG_RECORD_LENGTH = 300
FULL_RECORD_LENGTH = 50
US_OFFSET = 1
CANADA_OFFSET = 677
WORLD_OFFSET = 1353
FIPS_RANGE = 360

714
lib/pygeoip/timezone.py Normal file
View File

@ -0,0 +1,714 @@
__all__ = ['time_zone_by_country_and_region']
_country = {}
_country["AD"] = "Europe/Andorra"
_country["AE"] = "Asia/Dubai"
_country["AF"] = "Asia/Kabul"
_country["AG"] = "America/Antigua"
_country["AI"] = "America/Anguilla"
_country["AL"] = "Europe/Tirane"
_country["AM"] = "Asia/Yerevan"
_country["AO"] = "Africa/Luanda"
_country["AR"] = {}
_country["AR"]["01"] = "America/Argentina/Buenos_Aires"
_country["AR"]["02"] = "America/Argentina/Catamarca"
_country["AR"]["03"] = "America/Argentina/Tucuman"
_country["AR"]["04"] = "America/Argentina/Rio_Gallegos"
_country["AR"]["05"] = "America/Argentina/Cordoba"
_country["AR"]["06"] = "America/Argentina/Tucuman"
_country["AR"]["07"] = "America/Argentina/Buenos_Aires"
_country["AR"]["08"] = "America/Argentina/Buenos_Aires"
_country["AR"]["09"] = "America/Argentina/Tucuman"
_country["AR"]["10"] = "America/Argentina/Jujuy"
_country["AR"]["11"] = "America/Argentina/San_Luis"
_country["AR"]["12"] = "America/Argentina/La_Rioja"
_country["AR"]["13"] = "America/Argentina/Mendoza"
_country["AR"]["14"] = "America/Argentina/Buenos_Aires"
_country["AR"]["15"] = "America/Argentina/San_Luis"
_country["AR"]["16"] = "America/Argentina/Buenos_Aires"
_country["AR"]["17"] = "America/Argentina/Salta"
_country["AR"]["18"] = "America/Argentina/San_Juan"
_country["AR"]["19"] = "America/Argentina/San_Luis"
_country["AR"]["20"] = "America/Argentina/Rio_Gallegos"
_country["AR"]["21"] = "America/Argentina/Buenos_Aires"
_country["AR"]["22"] = "America/Argentina/Catamarca"
_country["AR"]["23"] = "America/Argentina/Ushuaia"
_country["AR"]["24"] = "America/Argentina/Tucuman"
_country["AS"] = "US/Samoa"
_country["AT"] = "Europe/Vienna"
_country["AU"] = {}
_country["AU"]["01"] = "Australia/Canberra"
_country["AU"]["02"] = "Australia/NSW"
_country["AU"]["03"] = "Australia/North"
_country["AU"]["04"] = "Australia/Queensland"
_country["AU"]["05"] = "Australia/South"
_country["AU"]["06"] = "Australia/Tasmania"
_country["AU"]["07"] = "Australia/Victoria"
_country["AU"]["08"] = "Australia/West"
_country["AW"] = "America/Aruba"
_country["AX"] = "Europe/Mariehamn"
_country["AZ"] = "Asia/Baku"
_country["BA"] = "Europe/Sarajevo"
_country["BB"] = "America/Barbados"
_country["BD"] = "Asia/Dhaka"
_country["BE"] = "Europe/Brussels"
_country["BF"] = "Africa/Ouagadougou"
_country["BG"] = "Europe/Sofia"
_country["BH"] = "Asia/Bahrain"
_country["BI"] = "Africa/Bujumbura"
_country["BJ"] = "Africa/Porto-Novo"
_country["BL"] = "America/St_Barthelemy"
_country["BM"] = "Atlantic/Bermuda"
_country["BN"] = "Asia/Brunei"
_country["BO"] = "America/La_Paz"
_country["BQ"] = "America/Curacao"
_country["BR"] = {}
_country["BR"]["01"] = "America/Rio_Branco"
_country["BR"]["02"] = "America/Maceio"
_country["BR"]["03"] = "America/Sao_Paulo"
_country["BR"]["04"] = "America/Manaus"
_country["BR"]["05"] = "America/Bahia"
_country["BR"]["06"] = "America/Fortaleza"
_country["BR"]["07"] = "America/Sao_Paulo"
_country["BR"]["08"] = "America/Sao_Paulo"
_country["BR"]["11"] = "America/Campo_Grande"
_country["BR"]["13"] = "America/Belem"
_country["BR"]["14"] = "America/Cuiaba"
_country["BR"]["15"] = "America/Sao_Paulo"
_country["BR"]["16"] = "America/Belem"
_country["BR"]["17"] = "America/Recife"
_country["BR"]["18"] = "America/Sao_Paulo"
_country["BR"]["20"] = "America/Fortaleza"
_country["BR"]["21"] = "America/Sao_Paulo"
_country["BR"]["22"] = "America/Recife"
_country["BR"]["23"] = "America/Sao_Paulo"
_country["BR"]["24"] = "America/Porto_Velho"
_country["BR"]["25"] = "America/Boa_Vista"
_country["BR"]["26"] = "America/Sao_Paulo"
_country["BR"]["27"] = "America/Sao_Paulo"
_country["BR"]["28"] = "America/Maceio"
_country["BR"]["29"] = "America/Sao_Paulo"
_country["BR"]["30"] = "America/Recife"
_country["BR"]["31"] = "America/Araguaina"
_country["BS"] = "America/Nassau"
_country["BT"] = "Asia/Thimphu"
_country["BW"] = "Africa/Gaborone"
_country["BY"] = "Europe/Minsk"
_country["BZ"] = "America/Belize"
_country["CA"] = {}
_country["CA"]["AB"] = "America/Edmonton"
_country["CA"]["BC"] = "America/Vancouver"
_country["CA"]["MB"] = "America/Winnipeg"
_country["CA"]["NB"] = "America/Halifax"
_country["CA"]["NL"] = "America/St_Johns"
_country["CA"]["NS"] = "America/Halifax"
_country["CA"]["NT"] = "America/Yellowknife"
_country["CA"]["NU"] = "America/Rankin_Inlet"
_country["CA"]["ON"] = "America/Rainy_River"
_country["CA"]["PE"] = "America/Halifax"
_country["CA"]["QC"] = "America/Montreal"
_country["CA"]["SK"] = "America/Regina"
_country["CA"]["YT"] = "America/Whitehorse"
_country["CC"] = "Indian/Cocos"
_country["CD"] = {}
_country["CD"]["02"] = "Africa/Kinshasa"
_country["CD"]["05"] = "Africa/Lubumbashi"
_country["CD"]["06"] = "Africa/Kinshasa"
_country["CD"]["08"] = "Africa/Kinshasa"
_country["CD"]["10"] = "Africa/Lubumbashi"
_country["CD"]["11"] = "Africa/Lubumbashi"
_country["CD"]["12"] = "Africa/Lubumbashi"
_country["CF"] = "Africa/Bangui"
_country["CG"] = "Africa/Brazzaville"
_country["CH"] = "Europe/Zurich"
_country["CI"] = "Africa/Abidjan"
_country["CK"] = "Pacific/Rarotonga"
_country["CL"] = "Chile/Continental"
_country["CM"] = "Africa/Lagos"
_country["CN"] = {}
_country["CN"]["01"] = "Asia/Shanghai"
_country["CN"]["02"] = "Asia/Shanghai"
_country["CN"]["03"] = "Asia/Shanghai"
_country["CN"]["04"] = "Asia/Shanghai"
_country["CN"]["05"] = "Asia/Harbin"
_country["CN"]["06"] = "Asia/Chongqing"
_country["CN"]["07"] = "Asia/Shanghai"
_country["CN"]["08"] = "Asia/Harbin"
_country["CN"]["09"] = "Asia/Shanghai"
_country["CN"]["10"] = "Asia/Shanghai"
_country["CN"]["11"] = "Asia/Chongqing"
_country["CN"]["12"] = "Asia/Shanghai"
_country["CN"]["13"] = "Asia/Urumqi"
_country["CN"]["14"] = "Asia/Chongqing"
_country["CN"]["15"] = "Asia/Chongqing"
_country["CN"]["16"] = "Asia/Chongqing"
_country["CN"]["18"] = "Asia/Chongqing"
_country["CN"]["19"] = "Asia/Harbin"
_country["CN"]["20"] = "Asia/Harbin"
_country["CN"]["21"] = "Asia/Chongqing"
_country["CN"]["22"] = "Asia/Harbin"
_country["CN"]["23"] = "Asia/Shanghai"
_country["CN"]["24"] = "Asia/Chongqing"
_country["CN"]["25"] = "Asia/Shanghai"
_country["CN"]["26"] = "Asia/Chongqing"
_country["CN"]["28"] = "Asia/Shanghai"
_country["CN"]["29"] = "Asia/Chongqing"
_country["CN"]["30"] = "Asia/Chongqing"
_country["CN"]["31"] = "Asia/Chongqing"
_country["CN"]["32"] = "Asia/Chongqing"
_country["CN"]["33"] = "Asia/Chongqing"
_country["CO"] = "America/Bogota"
_country["CR"] = "America/Costa_Rica"
_country["CU"] = "America/Havana"
_country["CV"] = "Atlantic/Cape_Verde"
_country["CW"] = "America/Curacao"
_country["CX"] = "Indian/Christmas"
_country["CY"] = "Asia/Nicosia"
_country["CZ"] = "Europe/Prague"
_country["DE"] = "Europe/Berlin"
_country["DJ"] = "Africa/Djibouti"
_country["DK"] = "Europe/Copenhagen"
_country["DM"] = "America/Dominica"
_country["DO"] = "America/Santo_Domingo"
_country["DZ"] = "Africa/Algiers"
_country["EC"] = {}
_country["EC"]["01"] = "Pacific/Galapagos"
_country["EC"]["02"] = "America/Guayaquil"
_country["EC"]["03"] = "America/Guayaquil"
_country["EC"]["04"] = "America/Guayaquil"
_country["EC"]["05"] = "America/Guayaquil"
_country["EC"]["06"] = "America/Guayaquil"
_country["EC"]["07"] = "America/Guayaquil"
_country["EC"]["08"] = "America/Guayaquil"
_country["EC"]["09"] = "America/Guayaquil"
_country["EC"]["10"] = "America/Guayaquil"
_country["EC"]["11"] = "America/Guayaquil"
_country["EC"]["12"] = "America/Guayaquil"
_country["EC"]["13"] = "America/Guayaquil"
_country["EC"]["14"] = "America/Guayaquil"
_country["EC"]["15"] = "America/Guayaquil"
_country["EC"]["17"] = "America/Guayaquil"
_country["EC"]["18"] = "America/Guayaquil"
_country["EC"]["19"] = "America/Guayaquil"
_country["EC"]["20"] = "America/Guayaquil"
_country["EC"]["22"] = "America/Guayaquil"
_country["EE"] = "Europe/Tallinn"
_country["EG"] = "Africa/Cairo"
_country["EH"] = "Africa/El_Aaiun"
_country["ER"] = "Africa/Asmera"
_country["ES"] = {}
_country["ES"]["07"] = "Europe/Madrid"
_country["ES"]["27"] = "Europe/Madrid"
_country["ES"]["29"] = "Europe/Madrid"
_country["ES"]["31"] = "Europe/Madrid"
_country["ES"]["32"] = "Europe/Madrid"
_country["ES"]["34"] = "Europe/Madrid"
_country["ES"]["39"] = "Europe/Madrid"
_country["ES"]["51"] = "Africa/Ceuta"
_country["ES"]["52"] = "Europe/Madrid"
_country["ES"]["53"] = "Atlantic/Canary"
_country["ES"]["54"] = "Europe/Madrid"
_country["ES"]["55"] = "Europe/Madrid"
_country["ES"]["56"] = "Europe/Madrid"
_country["ES"]["57"] = "Europe/Madrid"
_country["ES"]["58"] = "Europe/Madrid"
_country["ES"]["59"] = "Europe/Madrid"
_country["ES"]["60"] = "Europe/Madrid"
_country["ET"] = "Africa/Addis_Ababa"
_country["FI"] = "Europe/Helsinki"
_country["FJ"] = "Pacific/Fiji"
_country["FK"] = "Atlantic/Stanley"
_country["FO"] = "Atlantic/Faeroe"
_country["FR"] = "Europe/Paris"
_country["GA"] = "Africa/Libreville"
_country["GB"] = "Europe/London"
_country["GD"] = "America/Grenada"
_country["GE"] = "Asia/Tbilisi"
_country["GF"] = "America/Cayenne"
_country["GG"] = "Europe/Guernsey"
_country["GH"] = "Africa/Accra"
_country["GI"] = "Europe/Gibraltar"
_country["GL"] = {}
_country["GL"]["01"] = "America/Thule"
_country["GL"]["02"] = "America/Godthab"
_country["GL"]["03"] = "America/Godthab"
_country["GM"] = "Africa/Banjul"
_country["GN"] = "Africa/Conakry"
_country["GP"] = "America/Guadeloupe"
_country["GQ"] = "Africa/Malabo"
_country["GR"] = "Europe/Athens"
_country["GS"] = "Atlantic/South_Georgia"
_country["GT"] = "America/Guatemala"
_country["GU"] = "Pacific/Guam"
_country["GW"] = "Africa/Bissau"
_country["GY"] = "America/Guyana"
_country["HK"] = "Asia/Hong_Kong"
_country["HN"] = "America/Tegucigalpa"
_country["HR"] = "Europe/Zagreb"
_country["HT"] = "America/Port-au-Prince"
_country["HU"] = "Europe/Budapest"
_country["ID"] = {}
_country["ID"]["01"] = "Asia/Pontianak"
_country["ID"]["02"] = "Asia/Makassar"
_country["ID"]["03"] = "Asia/Jakarta"
_country["ID"]["04"] = "Asia/Jakarta"
_country["ID"]["05"] = "Asia/Jakarta"
_country["ID"]["06"] = "Asia/Jakarta"
_country["ID"]["07"] = "Asia/Jakarta"
_country["ID"]["08"] = "Asia/Jakarta"
_country["ID"]["09"] = "Asia/Jayapura"
_country["ID"]["10"] = "Asia/Jakarta"
_country["ID"]["11"] = "Asia/Pontianak"
_country["ID"]["12"] = "Asia/Makassar"
_country["ID"]["13"] = "Asia/Makassar"
_country["ID"]["14"] = "Asia/Makassar"
_country["ID"]["15"] = "Asia/Jakarta"
_country["ID"]["16"] = "Asia/Makassar"
_country["ID"]["17"] = "Asia/Makassar"
_country["ID"]["18"] = "Asia/Makassar"
_country["ID"]["19"] = "Asia/Pontianak"
_country["ID"]["20"] = "Asia/Makassar"
_country["ID"]["21"] = "Asia/Makassar"
_country["ID"]["22"] = "Asia/Makassar"
_country["ID"]["23"] = "Asia/Makassar"
_country["ID"]["24"] = "Asia/Jakarta"
_country["ID"]["25"] = "Asia/Pontianak"
_country["ID"]["26"] = "Asia/Pontianak"
_country["ID"]["30"] = "Asia/Jakarta"
_country["ID"]["31"] = "Asia/Makassar"
_country["ID"]["33"] = "Asia/Jakarta"
_country["IE"] = "Europe/Dublin"
_country["IL"] = "Asia/Jerusalem"
_country["IM"] = "Europe/Isle_of_Man"
_country["IN"] = "Asia/Calcutta"
_country["IO"] = "Indian/Chagos"
_country["IQ"] = "Asia/Baghdad"
_country["IR"] = "Asia/Tehran"
_country["IS"] = "Atlantic/Reykjavik"
_country["IT"] = "Europe/Rome"
_country["JE"] = "Europe/Jersey"
_country["JM"] = "America/Jamaica"
_country["JO"] = "Asia/Amman"
_country["JP"] = "Asia/Tokyo"
_country["KE"] = "Africa/Nairobi"
_country["KG"] = "Asia/Bishkek"
_country["KH"] = "Asia/Phnom_Penh"
_country["KI"] = "Pacific/Tarawa"
_country["KM"] = "Indian/Comoro"
_country["KN"] = "America/St_Kitts"
_country["KP"] = "Asia/Pyongyang"
_country["KR"] = "Asia/Seoul"
_country["KW"] = "Asia/Kuwait"
_country["KY"] = "America/Cayman"
_country["KZ"] = {}
_country["KZ"]["01"] = "Asia/Almaty"
_country["KZ"]["02"] = "Asia/Almaty"
_country["KZ"]["03"] = "Asia/Qyzylorda"
_country["KZ"]["04"] = "Asia/Aqtobe"
_country["KZ"]["05"] = "Asia/Qyzylorda"
_country["KZ"]["06"] = "Asia/Aqtau"
_country["KZ"]["07"] = "Asia/Oral"
_country["KZ"]["08"] = "Asia/Qyzylorda"
_country["KZ"]["09"] = "Asia/Aqtau"
_country["KZ"]["10"] = "Asia/Qyzylorda"
_country["KZ"]["11"] = "Asia/Almaty"
_country["KZ"]["12"] = "Asia/Qyzylorda"
_country["KZ"]["13"] = "Asia/Aqtobe"
_country["KZ"]["14"] = "Asia/Qyzylorda"
_country["KZ"]["15"] = "Asia/Almaty"
_country["KZ"]["16"] = "Asia/Aqtobe"
_country["KZ"]["17"] = "Asia/Almaty"
_country["LA"] = "Asia/Vientiane"
_country["LB"] = "Asia/Beirut"
_country["LC"] = "America/St_Lucia"
_country["LI"] = "Europe/Vaduz"
_country["LK"] = "Asia/Colombo"
_country["LR"] = "Africa/Monrovia"
_country["LS"] = "Africa/Maseru"
_country["LT"] = "Europe/Vilnius"
_country["LU"] = "Europe/Luxembourg"
_country["LV"] = "Europe/Riga"
_country["LY"] = "Africa/Tripoli"
_country["MA"] = "Africa/Casablanca"
_country["MC"] = "Europe/Monaco"
_country["MD"] = "Europe/Chisinau"
_country["ME"] = "Europe/Podgorica"
_country["MF"] = "America/Marigot"
_country["MG"] = "Indian/Antananarivo"
_country["MK"] = "Europe/Skopje"
_country["ML"] = "Africa/Bamako"
_country["MM"] = "Asia/Rangoon"
_country["MN"] = "Asia/Choibalsan"
_country["MO"] = "Asia/Macao"
_country["MP"] = "Pacific/Saipan"
_country["MQ"] = "America/Martinique"
_country["MR"] = "Africa/Nouakchott"
_country["MS"] = "America/Montserrat"
_country["MT"] = "Europe/Malta"
_country["MU"] = "Indian/Mauritius"
_country["MV"] = "Indian/Maldives"
_country["MW"] = "Africa/Blantyre"
_country["MX"] = {}
_country["MX"]["01"] = "America/Mexico_City"
_country["MX"]["02"] = "America/Tijuana"
_country["MX"]["03"] = "America/Hermosillo"
_country["MX"]["04"] = "America/Merida"
_country["MX"]["05"] = "America/Mexico_City"
_country["MX"]["06"] = "America/Chihuahua"
_country["MX"]["07"] = "America/Monterrey"
_country["MX"]["08"] = "America/Mexico_City"
_country["MX"]["09"] = "America/Mexico_City"
_country["MX"]["10"] = "America/Mazatlan"
_country["MX"]["11"] = "America/Mexico_City"
_country["MX"]["12"] = "America/Mexico_City"
_country["MX"]["13"] = "America/Mexico_City"
_country["MX"]["14"] = "America/Mazatlan"
_country["MX"]["15"] = "America/Chihuahua"
_country["MX"]["16"] = "America/Mexico_City"
_country["MX"]["17"] = "America/Mexico_City"
_country["MX"]["18"] = "America/Mazatlan"
_country["MX"]["19"] = "America/Monterrey"
_country["MX"]["20"] = "America/Mexico_City"
_country["MX"]["21"] = "America/Mexico_City"
_country["MX"]["22"] = "America/Mexico_City"
_country["MX"]["23"] = "America/Cancun"
_country["MX"]["24"] = "America/Mexico_City"
_country["MX"]["25"] = "America/Mazatlan"
_country["MX"]["26"] = "America/Hermosillo"
_country["MX"]["27"] = "America/Merida"
_country["MX"]["28"] = "America/Monterrey"
_country["MX"]["29"] = "America/Mexico_City"
_country["MX"]["30"] = "America/Mexico_City"
_country["MX"]["31"] = "America/Merida"
_country["MX"]["32"] = "America/Monterrey"
_country["MY"] = {}
_country["MY"]["01"] = "Asia/Kuala_Lumpur"
_country["MY"]["02"] = "Asia/Kuala_Lumpur"
_country["MY"]["03"] = "Asia/Kuala_Lumpur"
_country["MY"]["04"] = "Asia/Kuala_Lumpur"
_country["MY"]["05"] = "Asia/Kuala_Lumpur"
_country["MY"]["06"] = "Asia/Kuala_Lumpur"
_country["MY"]["07"] = "Asia/Kuala_Lumpur"
_country["MY"]["08"] = "Asia/Kuala_Lumpur"
_country["MY"]["09"] = "Asia/Kuala_Lumpur"
_country["MY"]["11"] = "Asia/Kuching"
_country["MY"]["12"] = "Asia/Kuala_Lumpur"
_country["MY"]["13"] = "Asia/Kuala_Lumpur"
_country["MY"]["14"] = "Asia/Kuala_Lumpur"
_country["MY"]["15"] = "Asia/Kuching"
_country["MY"]["16"] = "Asia/Kuching"
_country["MZ"] = "Africa/Maputo"
_country["NA"] = "Africa/Windhoek"
_country["NC"] = "Pacific/Noumea"
_country["NE"] = "Africa/Niamey"
_country["NF"] = "Pacific/Norfolk"
_country["NG"] = "Africa/Lagos"
_country["NI"] = "America/Managua"
_country["NL"] = "Europe/Amsterdam"
_country["NO"] = "Europe/Oslo"
_country["NP"] = "Asia/Katmandu"
_country["NR"] = "Pacific/Nauru"
_country["NU"] = "Pacific/Niue"
_country["NZ"] = {}
_country["NZ"]["85"] = "Pacific/Auckland"
_country["NZ"]["E7"] = "Pacific/Auckland"
_country["NZ"]["E8"] = "Pacific/Auckland"
_country["NZ"]["E9"] = "Pacific/Auckland"
_country["NZ"]["F1"] = "Pacific/Auckland"
_country["NZ"]["F2"] = "Pacific/Auckland"
_country["NZ"]["F3"] = "Pacific/Auckland"
_country["NZ"]["F4"] = "Pacific/Auckland"
_country["NZ"]["F5"] = "Pacific/Auckland"
_country["NZ"]["F7"] = "Pacific/Chatham"
_country["NZ"]["F8"] = "Pacific/Auckland"
_country["NZ"]["F9"] = "Pacific/Auckland"
_country["NZ"]["G1"] = "Pacific/Auckland"
_country["NZ"]["G2"] = "Pacific/Auckland"
_country["NZ"]["G3"] = "Pacific/Auckland"
_country["OM"] = "Asia/Muscat"
_country["PA"] = "America/Panama"
_country["PE"] = "America/Lima"
_country["PF"] = "Pacific/Marquesas"
_country["PG"] = "Pacific/Port_Moresby"
_country["PH"] = "Asia/Manila"
_country["PK"] = "Asia/Karachi"
_country["PL"] = "Europe/Warsaw"
_country["PM"] = "America/Miquelon"
_country["PN"] = "Pacific/Pitcairn"
_country["PR"] = "America/Puerto_Rico"
_country["PS"] = "Asia/Gaza"
_country["PT"] = {}
_country["PT"]["02"] = "Europe/Lisbon"
_country["PT"]["03"] = "Europe/Lisbon"
_country["PT"]["04"] = "Europe/Lisbon"
_country["PT"]["05"] = "Europe/Lisbon"
_country["PT"]["06"] = "Europe/Lisbon"
_country["PT"]["07"] = "Europe/Lisbon"
_country["PT"]["08"] = "Europe/Lisbon"
_country["PT"]["09"] = "Europe/Lisbon"
_country["PT"]["10"] = "Atlantic/Madeira"
_country["PT"]["11"] = "Europe/Lisbon"
_country["PT"]["13"] = "Europe/Lisbon"
_country["PT"]["14"] = "Europe/Lisbon"
_country["PT"]["16"] = "Europe/Lisbon"
_country["PT"]["17"] = "Europe/Lisbon"
_country["PT"]["18"] = "Europe/Lisbon"
_country["PT"]["19"] = "Europe/Lisbon"
_country["PT"]["20"] = "Europe/Lisbon"
_country["PT"]["21"] = "Europe/Lisbon"
_country["PT"]["22"] = "Europe/Lisbon"
_country["PW"] = "Pacific/Palau"
_country["PY"] = "America/Asuncion"
_country["QA"] = "Asia/Qatar"
_country["RE"] = "Indian/Reunion"
_country["RO"] = "Europe/Bucharest"
_country["RS"] = "Europe/Belgrade"
_country["RU"] = {}
_country["RU"]["01"] = "Europe/Volgograd"
_country["RU"]["02"] = "Asia/Irkutsk"
_country["RU"]["03"] = "Asia/Novokuznetsk"
_country["RU"]["04"] = "Asia/Novosibirsk"
_country["RU"]["05"] = "Asia/Vladivostok"
_country["RU"]["06"] = "Europe/Moscow"
_country["RU"]["07"] = "Europe/Volgograd"
_country["RU"]["08"] = "Europe/Samara"
_country["RU"]["09"] = "Europe/Moscow"
_country["RU"]["10"] = "Europe/Moscow"
_country["RU"]["11"] = "Asia/Irkutsk"
_country["RU"]["13"] = "Asia/Yekaterinburg"
_country["RU"]["14"] = "Asia/Irkutsk"
_country["RU"]["15"] = "Asia/Anadyr"
_country["RU"]["16"] = "Europe/Samara"
_country["RU"]["17"] = "Europe/Volgograd"
_country["RU"]["18"] = "Asia/Krasnoyarsk"
_country["RU"]["20"] = "Asia/Irkutsk"
_country["RU"]["21"] = "Europe/Moscow"
_country["RU"]["22"] = "Europe/Volgograd"
_country["RU"]["23"] = "Europe/Kaliningrad"
_country["RU"]["24"] = "Europe/Volgograd"
_country["RU"]["25"] = "Europe/Moscow"
_country["RU"]["26"] = "Asia/Kamchatka"
_country["RU"]["27"] = "Europe/Volgograd"
_country["RU"]["28"] = "Europe/Moscow"
_country["RU"]["29"] = "Asia/Novokuznetsk"
_country["RU"]["30"] = "Asia/Vladivostok"
_country["RU"]["31"] = "Asia/Krasnoyarsk"
_country["RU"]["32"] = "Asia/Omsk"
_country["RU"]["33"] = "Asia/Yekaterinburg"
_country["RU"]["34"] = "Asia/Yekaterinburg"
_country["RU"]["35"] = "Asia/Yekaterinburg"
_country["RU"]["36"] = "Asia/Anadyr"
_country["RU"]["37"] = "Europe/Moscow"
_country["RU"]["38"] = "Europe/Volgograd"
_country["RU"]["39"] = "Asia/Krasnoyarsk"
_country["RU"]["40"] = "Asia/Yekaterinburg"
_country["RU"]["41"] = "Europe/Moscow"
_country["RU"]["42"] = "Europe/Moscow"
_country["RU"]["43"] = "Europe/Moscow"
_country["RU"]["44"] = "Asia/Magadan"
_country["RU"]["45"] = "Europe/Samara"
_country["RU"]["46"] = "Europe/Samara"
_country["RU"]["47"] = "Europe/Moscow"
_country["RU"]["48"] = "Europe/Moscow"
_country["RU"]["49"] = "Europe/Moscow"
_country["RU"]["50"] = "Asia/Yekaterinburg"
_country["RU"]["51"] = "Europe/Moscow"
_country["RU"]["52"] = "Europe/Moscow"
_country["RU"]["53"] = "Asia/Novosibirsk"
_country["RU"]["54"] = "Asia/Omsk"
_country["RU"]["55"] = "Europe/Samara"
_country["RU"]["56"] = "Europe/Moscow"
_country["RU"]["57"] = "Europe/Samara"
_country["RU"]["58"] = "Asia/Yekaterinburg"
_country["RU"]["59"] = "Asia/Vladivostok"
_country["RU"]["60"] = "Europe/Kaliningrad"
_country["RU"]["61"] = "Europe/Volgograd"
_country["RU"]["62"] = "Europe/Moscow"
_country["RU"]["63"] = "Asia/Yakutsk"
_country["RU"]["64"] = "Asia/Sakhalin"
_country["RU"]["65"] = "Europe/Samara"
_country["RU"]["66"] = "Europe/Moscow"
_country["RU"]["67"] = "Europe/Samara"
_country["RU"]["68"] = "Europe/Volgograd"
_country["RU"]["69"] = "Europe/Moscow"
_country["RU"]["70"] = "Europe/Volgograd"
_country["RU"]["71"] = "Asia/Yekaterinburg"
_country["RU"]["72"] = "Europe/Moscow"
_country["RU"]["73"] = "Europe/Samara"
_country["RU"]["74"] = "Asia/Krasnoyarsk"
_country["RU"]["75"] = "Asia/Novosibirsk"
_country["RU"]["76"] = "Europe/Moscow"
_country["RU"]["77"] = "Europe/Moscow"
_country["RU"]["78"] = "Asia/Yekaterinburg"
_country["RU"]["79"] = "Asia/Irkutsk"
_country["RU"]["80"] = "Asia/Yekaterinburg"
_country["RU"]["81"] = "Europe/Samara"
_country["RU"]["82"] = "Asia/Irkutsk"
_country["RU"]["83"] = "Europe/Moscow"
_country["RU"]["84"] = "Europe/Volgograd"
_country["RU"]["85"] = "Europe/Moscow"
_country["RU"]["86"] = "Europe/Moscow"
_country["RU"]["87"] = "Asia/Novosibirsk"
_country["RU"]["88"] = "Europe/Moscow"
_country["RU"]["89"] = "Asia/Vladivostok"
_country["RW"] = "Africa/Kigali"
_country["SA"] = "Asia/Riyadh"
_country["SB"] = "Pacific/Guadalcanal"
_country["SC"] = "Indian/Mahe"
_country["SD"] = "Africa/Khartoum"
_country["SE"] = "Europe/Stockholm"
_country["SG"] = "Asia/Singapore"
_country["SH"] = "Atlantic/St_Helena"
_country["SI"] = "Europe/Ljubljana"
_country["SJ"] = "Arctic/Longyearbyen"
_country["SK"] = "Europe/Bratislava"
_country["SL"] = "Africa/Freetown"
_country["SM"] = "Europe/San_Marino"
_country["SN"] = "Africa/Dakar"
_country["SO"] = "Africa/Mogadishu"
_country["SR"] = "America/Paramaribo"
_country["ST"] = "Africa/Sao_Tome"
_country["SV"] = "America/El_Salvador"
_country["SX"] = "America/Curacao"
_country["SY"] = "Asia/Damascus"
_country["SZ"] = "Africa/Mbabane"
_country["TC"] = "America/Grand_Turk"
_country["TD"] = "Africa/Ndjamena"
_country["TF"] = "Indian/Kerguelen"
_country["TG"] = "Africa/Lome"
_country["TH"] = "Asia/Bangkok"
_country["TJ"] = "Asia/Dushanbe"
_country["TK"] = "Pacific/Fakaofo"
_country["TL"] = "Asia/Dili"
_country["TM"] = "Asia/Ashgabat"
_country["TN"] = "Africa/Tunis"
_country["TO"] = "Pacific/Tongatapu"
_country["TR"] = "Asia/Istanbul"
_country["TT"] = "America/Port_of_Spain"
_country["TV"] = "Pacific/Funafuti"
_country["TW"] = "Asia/Taipei"
_country["TZ"] = "Africa/Dar_es_Salaam"
_country["UA"] = {}
_country["UA"]["01"] = "Europe/Kiev"
_country["UA"]["02"] = "Europe/Kiev"
_country["UA"]["03"] = "Europe/Uzhgorod"
_country["UA"]["04"] = "Europe/Zaporozhye"
_country["UA"]["05"] = "Europe/Zaporozhye"
_country["UA"]["06"] = "Europe/Uzhgorod"
_country["UA"]["07"] = "Europe/Zaporozhye"
_country["UA"]["08"] = "Europe/Simferopol"
_country["UA"]["09"] = "Europe/Kiev"
_country["UA"]["10"] = "Europe/Zaporozhye"
_country["UA"]["11"] = "Europe/Simferopol"
_country["UA"]["13"] = "Europe/Kiev"
_country["UA"]["14"] = "Europe/Zaporozhye"
_country["UA"]["15"] = "Europe/Uzhgorod"
_country["UA"]["16"] = "Europe/Zaporozhye"
_country["UA"]["17"] = "Europe/Simferopol"
_country["UA"]["18"] = "Europe/Zaporozhye"
_country["UA"]["19"] = "Europe/Kiev"
_country["UA"]["20"] = "Europe/Simferopol"
_country["UA"]["21"] = "Europe/Kiev"
_country["UA"]["22"] = "Europe/Uzhgorod"
_country["UA"]["23"] = "Europe/Kiev"
_country["UA"]["24"] = "Europe/Uzhgorod"
_country["UA"]["25"] = "Europe/Uzhgorod"
_country["UA"]["26"] = "Europe/Zaporozhye"
_country["UA"]["27"] = "Europe/Kiev"
_country["UG"] = "Africa/Kampala"
_country["US"] = {}
_country["US"]["AK"] = "America/Anchorage"
_country["US"]["AL"] = "America/Chicago"
_country["US"]["AR"] = "America/Chicago"
_country["US"]["AZ"] = "America/Phoenix"
_country["US"]["CA"] = "America/Los_Angeles"
_country["US"]["CO"] = "America/Denver"
_country["US"]["CT"] = "America/New_York"
_country["US"]["DC"] = "America/New_York"
_country["US"]["DE"] = "America/New_York"
_country["US"]["FL"] = "America/New_York"
_country["US"]["GA"] = "America/New_York"
_country["US"]["HI"] = "Pacific/Honolulu"
_country["US"]["IA"] = "America/Chicago"
_country["US"]["ID"] = "America/Denver"
_country["US"]["IL"] = "America/Chicago"
_country["US"]["IN"] = "America/Indianapolis"
_country["US"]["KS"] = "America/Chicago"
_country["US"]["KY"] = "America/New_York"
_country["US"]["LA"] = "America/Chicago"
_country["US"]["MA"] = "America/New_York"
_country["US"]["MD"] = "America/New_York"
_country["US"]["ME"] = "America/New_York"
_country["US"]["MI"] = "America/New_York"
_country["US"]["MN"] = "America/Chicago"
_country["US"]["MO"] = "America/Chicago"
_country["US"]["MS"] = "America/Chicago"
_country["US"]["MT"] = "America/Denver"
_country["US"]["NC"] = "America/New_York"
_country["US"]["ND"] = "America/Chicago"
_country["US"]["NE"] = "America/Chicago"
_country["US"]["NH"] = "America/New_York"
_country["US"]["NJ"] = "America/New_York"
_country["US"]["NM"] = "America/Denver"
_country["US"]["NV"] = "America/Los_Angeles"
_country["US"]["NY"] = "America/New_York"
_country["US"]["OH"] = "America/New_York"
_country["US"]["OK"] = "America/Chicago"
_country["US"]["OR"] = "America/Los_Angeles"
_country["US"]["PA"] = "America/New_York"
_country["US"]["RI"] = "America/New_York"
_country["US"]["SC"] = "America/New_York"
_country["US"]["SD"] = "America/Chicago"
_country["US"]["TN"] = "America/Chicago"
_country["US"]["TX"] = "America/Chicago"
_country["US"]["UT"] = "America/Denver"
_country["US"]["VA"] = "America/New_York"
_country["US"]["VT"] = "America/New_York"
_country["US"]["WA"] = "America/Los_Angeles"
_country["US"]["WI"] = "America/Chicago"
_country["US"]["WV"] = "America/New_York"
_country["US"]["WY"] = "America/Denver"
_country["UY"] = "America/Montevideo"
_country["UZ"] = {}
_country["UZ"]["01"] = "Asia/Tashkent"
_country["UZ"]["02"] = "Asia/Samarkand"
_country["UZ"]["03"] = "Asia/Tashkent"
_country["UZ"]["06"] = "Asia/Tashkent"
_country["UZ"]["07"] = "Asia/Samarkand"
_country["UZ"]["08"] = "Asia/Samarkand"
_country["UZ"]["09"] = "Asia/Samarkand"
_country["UZ"]["10"] = "Asia/Samarkand"
_country["UZ"]["12"] = "Asia/Samarkand"
_country["UZ"]["13"] = "Asia/Tashkent"
_country["UZ"]["14"] = "Asia/Tashkent"
_country["VA"] = "Europe/Vatican"
_country["VC"] = "America/St_Vincent"
_country["VE"] = "America/Caracas"
_country["VG"] = "America/Tortola"
_country["VI"] = "America/St_Thomas"
_country["VN"] = "Asia/Phnom_Penh"
_country["VU"] = "Pacific/Efate"
_country["WF"] = "Pacific/Wallis"
_country["WS"] = "Pacific/Samoa"
_country["YE"] = "Asia/Aden"
_country["YT"] = "Indian/Mayotte"
_country["YU"] = "Europe/Belgrade"
_country["ZA"] = "Africa/Johannesburg"
_country["ZM"] = "Africa/Lusaka"
_country["ZW"] = "Africa/Harare"
def time_zone_by_country_and_region(country_code, region_name=None):
if country_code not in _country:
return None
if not region_name or region_name == '00':
region_name = None
timezones = _country[country_code]
if isinstance(timezones, str):
return timezones
if region_name:
return timezones.get(region_name)

42
lib/pygeoip/util.py Normal file
View File

@ -0,0 +1,42 @@
"""
Misc. utility functions. It is part of the pygeoip package.
@author: Jennifer Ennis <zaylea at gmail dot com>
@license:
Copyright(C) 2004 MaxMind LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
"""
import six
def ip2long(ip):
"""
Convert a IPv4 address into a 32-bit integer.
@param ip: quad-dotted IPv4 address
@type ip: str
@return: network byte order 32-bit integer
@rtype: int
"""
ip_array = ip.split('.')
if six.PY3:
# int and long are unified in py3
ip_long = int(ip_array[0]) * 16777216 + int(ip_array[1]) * 65536 + int(ip_array[2]) * 256 + int(ip_array[3])
else:
ip_long = long(ip_array[0]) * 16777216 + long(ip_array[1]) * 65536 + long(ip_array[2]) * 256 + long(ip_array[3])
return ip_long

366
lib/six.py Normal file
View File

@ -0,0 +1,366 @@
"""Utilities for writing code that runs on Python 2 and 3"""
import operator
import sys
import types
__author__ = "Benjamin Peterson <benjamin@python.org>"
__version__ = "1.2.0"
# True if we are running on Python 3.
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str,
integer_types = int,
class_types = type,
text_type = str
binary_type = bytes
MAXSIZE = sys.maxsize
else:
string_types = basestring,
integer_types = (int, long)
class_types = (type, types.ClassType)
text_type = unicode
binary_type = str
if sys.platform == "java":
# Jython always uses 32 bits.
MAXSIZE = int((1 << 31) - 1)
else:
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
class X(object):
def __len__(self):
return 1 << 31
try:
len(X())
except OverflowError:
# 32-bit
MAXSIZE = int((1 << 31) - 1)
else:
# 64-bit
MAXSIZE = int((1 << 63) - 1)
del X
def _add_doc(func, doc):
"""Add documentation to a function."""
func.__doc__ = doc
def _import_module(name):
"""Import module, returning the module after the last dot."""
__import__(name)
return sys.modules[name]
class _LazyDescr(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, tp):
result = self._resolve()
setattr(obj, self.name, result)
# This is a bit ugly, but it avoids running this again.
delattr(tp, self.name)
return result
class MovedModule(_LazyDescr):
def __init__(self, name, old, new=None):
super(MovedModule, self).__init__(name)
if PY3:
if new is None:
new = name
self.mod = new
else:
self.mod = old
def _resolve(self):
return _import_module(self.mod)
class MovedAttribute(_LazyDescr):
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
super(MovedAttribute, self).__init__(name)
if PY3:
if new_mod is None:
new_mod = name
self.mod = new_mod
if new_attr is None:
if old_attr is None:
new_attr = name
else:
new_attr = old_attr
self.attr = new_attr
else:
self.mod = old_mod
if old_attr is None:
old_attr = name
self.attr = old_attr
def _resolve(self):
module = _import_module(self.mod)
return getattr(module, self.attr)
class _MovedItems(types.ModuleType):
"""Lazy loading of moved objects"""
_moved_attributes = [
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
MovedAttribute("reduce", "__builtin__", "functools"),
MovedAttribute("StringIO", "StringIO", "io"),
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
MovedModule("copyreg", "copy_reg"),
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
MovedModule("http_cookies", "Cookie", "http.cookies"),
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
MovedModule("html_parser", "HTMLParser", "html.parser"),
MovedModule("http_client", "httplib", "http.client"),
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
MovedModule("cPickle", "cPickle", "pickle"),
MovedModule("queue", "Queue"),
MovedModule("reprlib", "repr"),
MovedModule("socketserver", "SocketServer"),
MovedModule("tkinter", "Tkinter"),
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
MovedModule("tkinter_colorchooser", "tkColorChooser",
"tkinter.colorchooser"),
MovedModule("tkinter_commondialog", "tkCommonDialog",
"tkinter.commondialog"),
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
"tkinter.simpledialog"),
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
MovedModule("winreg", "_winreg"),
]
for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr)
del attr
moves = sys.modules["six.moves"] = _MovedItems("moves")
def add_move(move):
"""Add an item to six.moves."""
setattr(_MovedItems, move.name, move)
def remove_move(name):
"""Remove item from six.moves."""
try:
delattr(_MovedItems, name)
except AttributeError:
try:
del moves.__dict__[name]
except KeyError:
raise AttributeError("no such move, %r" % (name,))
if PY3:
_meth_func = "__func__"
_meth_self = "__self__"
_func_code = "__code__"
_func_defaults = "__defaults__"
_iterkeys = "keys"
_itervalues = "values"
_iteritems = "items"
else:
_meth_func = "im_func"
_meth_self = "im_self"
_func_code = "func_code"
_func_defaults = "func_defaults"
_iterkeys = "iterkeys"
_itervalues = "itervalues"
_iteritems = "iteritems"
try:
advance_iterator = next
except NameError:
def advance_iterator(it):
return it.next()
next = advance_iterator
if PY3:
def get_unbound_function(unbound):
return unbound
Iterator = object
def callable(obj):
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
else:
def get_unbound_function(unbound):
return unbound.im_func
class Iterator(object):
def next(self):
return type(self).__next__(self)
callable = callable
_add_doc(get_unbound_function,
"""Get the function out of a possibly unbound function""")
get_method_function = operator.attrgetter(_meth_func)
get_method_self = operator.attrgetter(_meth_self)
get_function_code = operator.attrgetter(_func_code)
get_function_defaults = operator.attrgetter(_func_defaults)
def iterkeys(d):
"""Return an iterator over the keys of a dictionary."""
return iter(getattr(d, _iterkeys)())
def itervalues(d):
"""Return an iterator over the values of a dictionary."""
return iter(getattr(d, _itervalues)())
def iteritems(d):
"""Return an iterator over the (key, value) pairs of a dictionary."""
return iter(getattr(d, _iteritems)())
if PY3:
def b(s):
return s.encode("latin-1")
def u(s):
return s
if sys.version_info[1] <= 1:
def int2byte(i):
return bytes((i,))
else:
# This is about 2x faster than the implementation above on 3.2+
int2byte = operator.methodcaller("to_bytes", 1, "big")
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
else:
def b(s):
return s
def u(s):
return unicode(s, "unicode_escape")
int2byte = chr
import StringIO
StringIO = BytesIO = StringIO.StringIO
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")
if PY3:
import builtins
exec_ = getattr(builtins, "exec")
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
print_ = getattr(builtins, "print")
del builtins
else:
def exec_(code, globs=None, locs=None):
"""Execute code in a namespace."""
if globs is None:
frame = sys._getframe(1)
globs = frame.f_globals
if locs is None:
locs = frame.f_locals
del frame
elif locs is None:
locs = globs
exec("""exec code in globs, locs""")
exec_("""def reraise(tp, value, tb=None):
raise tp, value, tb
""")
def print_(*args, **kwargs):
"""The new-style print function."""
fp = kwargs.pop("file", sys.stdout)
if fp is None:
return
def write(data):
if not isinstance(data, basestring):
data = str(data)
fp.write(data)
want_unicode = False
sep = kwargs.pop("sep", None)
if sep is not None:
if isinstance(sep, unicode):
want_unicode = True
elif not isinstance(sep, str):
raise TypeError("sep must be None or a string")
end = kwargs.pop("end", None)
if end is not None:
if isinstance(end, unicode):
want_unicode = True
elif not isinstance(end, str):
raise TypeError("end must be None or a string")
if kwargs:
raise TypeError("invalid keyword arguments to print()")
if not want_unicode:
for arg in args:
if isinstance(arg, unicode):
want_unicode = True
break
if want_unicode:
newline = unicode("\n")
space = unicode(" ")
else:
newline = "\n"
space = " "
if sep is None:
sep = space
if end is None:
end = newline
for i, arg in enumerate(args):
if i:
write(sep)
write(arg)
write(end)
_add_doc(reraise, """Reraise an exception.""")
def with_metaclass(meta, base=object):
"""Create a base class with a metaclass."""
return meta("NewBase", (base,), {})

BIN
plugins/data/geoip.dat Normal file

Binary file not shown.

View File

@ -1,43 +1,17 @@
from util import hook, http
from util import hook
import os.path
import pygeoip
def find_location(ip, api):
response = http.get("http://api.ipinfodb.com/v3/ip-city/", key=api, ip=ip)
response = response.split(";")
results = {}
results["country"] = response[4].title()
results["country_short"] = response[3].upper()
results["state"] = response[5].title()
results["city"] = response[6].title()
results["timezone"] = response[10].title()
return results
def timezone(ip):
time = find_location(ip)["timezone"]
time = time.replace(":", ".")
time = time.replace(".00", "")
return int(time)
# initalise geolocation database
geo = pygeoip.GeoIP(os.path.abspath("./plugins/data/geoip.dat"))
@hook.command
@hook.command("location")
def geoip(inp, say=None, bot=None):
"geoip <ip> - Performs a location check on <ip>."
api_key = bot.config.get("api_keys", {}).get("geoip", None)
if api_key is None:
return "error: no api key set"
def geoip(inp):
"geoip <host/ip> -- Gets the location of <host/ip>"
try:
record = geo.record_by_name(inp)
except:
return "Sorry, I can't locate that in my database."
give = find_location(inp, api_key)
if give["country"] not in ["", " ", "-", " - ", None]:
if give["state"] == give["city"]:
localstring = give["city"]
else:
localstring = give["city"] + ", " + give["state"]
say("That IP comes from " + give["country"] +
" (" + give["country_short"] + ")")
say("I think it's in " + localstring +
" with a timezone of " + give["timezone"] + "GMT")
else:
say("Either that wasn't an IP or I cannot locate it in my database.")
return
return "Country: %(country_name)s (%(country_code)s), City: %(city)s" % record