PK irGck tilecloud_chain/expiretiles.py# -*- coding: utf-8 -*-
from argparse import ArgumentParser
import sys
import psycopg2
from shapely.geometry import Polygon, MultiPolygon
from shapely.ops import cascaded_union
from tilecloud.grid.quad import QuadTileGrid
from tilecloud_chain import parse_tilecoord
def main():
parser = ArgumentParser(
description='Used to import the osm2pgsql expire-tiles file to Postgres',
prog=sys.argv[0]
)
parser.add_argument(
'--buffer',
type=float,
default=0.0,
help='Extent buffer to the tiles [m], default is 0',
)
parser.add_argument(
'--simplify',
type=float,
default=0.0,
help='Simplify the result geometry [m], default is 0',
)
parser.add_argument(
'--create',
default=False,
action="store_true",
help='create the table if not exists',
)
parser.add_argument(
'--delete',
default=False,
action="store_true",
help='empty the table',
)
parser.add_argument(
'file',
metavar='FILE',
help='The osm2pgsql expire-tiles file',
)
parser.add_argument(
'connection',
metavar='CONNECTION',
help='The PostgreSQL connection string e.g. "user=www-data password=www-data dbname=sig host=localhost"',
)
parser.add_argument(
'table',
metavar='TABLE',
help='The PostgreSQL table to fill',
)
parser.add_argument(
'--schema',
default='public',
help='The PostgreSQL schema to use (should already exists), default is public',
)
parser.add_argument(
'column',
metavar='COLUMN',
default='geom',
nargs='?',
help='The PostgreSQL column, default is "geom"',
)
parser.add_argument(
'--srid',
type=int,
default=3857,
nargs='?',
help='The stored geometry SRID, no conversion by default (3857)',
)
options = parser.parse_args()
connection = psycopg2.connect(options.connection)
cursor = connection.cursor()
if options.create:
cursor.execute(
"SELECT count(*) FROM pg_tables WHERE schemaname='%s' AND tablename='%s'" % (
options.schema, options.table,
)
)
if cursor.fetchone()[0] == 0:
cursor.execute('CREATE TABLE IF NOT EXISTS "%s"."%s" (id serial)' % (
options.schema, options.table,
))
cursor.execute("SELECT AddGeometryColumn('%s', '%s', '%s', %s, 'MULTIPOLYGON', 2)" % (
options.schema, options.table, options.column, options.srid,
))
if options.delete:
cursor.execute('DELETE FROM "%s"' % (options.table))
geoms = []
grid = QuadTileGrid(
max_extent=(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
)
with open(options.file, "r") as f:
for coord in f:
extent = grid.extent(parse_tilecoord(coord), options.buffer)
geoms.append(Polygon((
(extent[0], extent[1]),
(extent[0], extent[3]),
(extent[2], extent[3]),
(extent[2], extent[1])
)))
if len(geoms) == 0:
print("No coords found")
connection.commit()
cursor.close()
connection.close()
exit(0)
geom = cascaded_union(geoms)
if geom.geom_type == 'Polygon':
geom = MultiPolygon((geom,))
if options.simplify > 0:
geom.simplify(options.simplify)
sql_geom = "ST_GeomFromText('%s', 3857)" % geom.wkt
if options.srid <= 0:
sql_geom = "ST_GeomFromText('%s')" % geom.wkt # pragma: no cover
elif options.srid != 3857:
sql_geom = 'ST_Transform(%s, %i)' % (sql_geom, options.srid)
cursor.execute('INSERT INTO "%s" ("%s") VALUES (%s)' % (
options.table, options.column, sql_geom
))
connection.commit()
cursor.close()
connection.close()
print('Import successful')
PK 9CeE 1 tilecloud_chain/wmts_get_capabilities_template.pywmts_get_capabilities_template = """
REST
{%
if server %}
KVP
{%
endif %}
{%
for base_url in base_urls %}
REST{%
if server %}
KVP{%
endif %}
{%
endfor %}
{% for layername, layer in layers.items() %}
{{layername}}
{{layername}}
{{layer['mime_type']}} {%
if layer['query_layers'] %}{%
for info_format in layer['info_formats'] %}
{{infoformat}}{%
endfor %}{%
endif %}{%
for dimension in layer['dimensions'] %}
{{dimension['name']}}
{{dimension['default']}} {%
for value in dimension['values'] %}
{{value}} {%
endfor %}
{%
endfor %}{%
for base_url in base_urls %}
{%
endfor %}
{{layer["grid"]}}
{% endfor %}
{% for gridname, grid in grids.items() %}
{{gridname}}
urn:ogc:def:crs:{{
grid['srs'].replace(':', '::')
}}{%
for i, resolution in enumerate(grid['resolutions']) %}{%
set width = int(ceil(
(grid['bbox'][2]-grid['bbox'][0]) /
resolution / grid['tile_size'])) %}{%
set height = int(ceil(
(grid['bbox'][3]-grid['bbox'][1]) /
resolution / grid['tile_size'])) %}{%
set left = grid['bbox'][0] %}{%
set top = grid['bbox'][3] %}
{{ get_tile_matrix_identifier(grid, resolution=resolution, zoom=i) }}
{{resolution / 0.00028}}
{{left}} {{top}}
{{grid['tile_size']}}
{{grid['tile_size']}}
{{width}}
{{height}}
{% endfor %}
{% endfor %}
"""
PK vBߥ " tilecloud_chain/openlayers_html.pyopenlayers_html = """
OpenLayers test page
"""
PK wHR"^ tilecloud_chain/__init__.py# -*- coding: utf-8 -*-
import sys
import os
import re
import logging
import yaml
import sqlite3
import tempfile
import subprocess
from six.moves import cStringIO, map, filter
from math import ceil, sqrt
from hashlib import sha1
from fractions import Fraction
from datetime import datetime
from tilecloud import consume
try:
import bsddb3 as bsddb
except: # pragma: no cover
import bsddb
try:
from PIL import Image
Image # suppress pyflakes warning
except: # pragma: no cover
import Image
import psycopg2
from shapely.wkb import loads as loads_wkb
from shapely.geometry import Polygon
from shapely.ops import cascaded_union
import boto.sqs
from boto.sqs.jsonmessage import JSONMessage
from tilecloud import Tile, BoundingPyramid, TileCoord
from tilecloud.grid.free import FreeTileGrid
from tilecloud.store.metatile import MetaTileSplitterTileStore
from tilecloud.store.s3 import S3TileStore
from tilecloud.store.mbtiles import MBTilesTileStore
from tilecloud.store.bsddb import BSDDBTileStore
from tilecloud.store.filesystem import FilesystemTileStore
from tilecloud.layout.wmts import WMTSTileLayout
from tilecloud.filter.logger import Logger
from tilecloud.filter.error import LogErrors, MaximumConsecutiveErrors
logger = logging.getLogger('tilecloud_chain')
def add_comon_options(
parser, tile_pyramid=True, no_geom=True,
near=True, time=True, dimensions=False, cache=True):
parser.add_argument(
'-c', '--config', default='tilegeneration/config.yaml',
help='path to the configuration file', metavar="FILE"
)
parser.add_argument(
'-l', '--layer', metavar="NAME",
help='the layer to generate'
)
if tile_pyramid:
parser.add_argument(
'-b', '--bbox', nargs=4, type=float, metavar=('MINX', 'MINY', 'MAXX', 'MAXY'),
help='restrict to specified bounding box'
)
parser.add_argument(
'-z', '--zoom',
help='restrict to specified zoom level, or a zooms range (2-5), or a zooms list (2,4,5)'
)
parser.add_argument(
'-t', '--test', type=int,
help='test with generating N tiles, and add log messages', metavar="N"
)
if near:
parser.add_argument(
'--near', type=float, nargs=2, metavar=('X', 'Y'),
help='This option is a good replacement of --bbox, to used with '
'--time or --test and --zoom, implies --no-geom. '
'It automatically measure a bbox around the X Y position that corresponds to the metatiles.'
)
if time:
parser.add_argument(
'--time', '--measure-generation-time',
dest='time', metavar="N", type=int,
help='Measure the generation time by creating N tiles to warm-up, '
'N tile to do the measure and N tiles to slow-down'
)
if no_geom:
parser.add_argument(
'--no-geom', default=True, action="store_false", dest="geom",
help="Don't the geometry available in the SQL"
)
if dimensions:
parser.add_argument(
'--dimensions', nargs='+', metavar='DIMENSION=VALUE', default=[],
help='overwrite the dimensions values specified in the config file'
)
if cache:
parser.add_argument(
'--cache', '--destination-cache',
dest='cache', metavar="NAME",
help='The cache name to use'
)
parser.add_argument(
'-q', '--quiet', default=False, action="store_true",
help='Display only errors.'
)
parser.add_argument(
'-v', '--verbose', default=False, action="store_true",
help='Display info message.'
)
parser.add_argument(
'-d', '--debug', default=False, action="store_true",
help='Display debug message, and stop on first error.'
)
def get_tile_matrix_identifier(grid, resolution=None, zoom=None):
if grid is None or grid['matrix_identifier'] == 'zoom':
return str(zoom)
else:
if resolution is None:
resolution = grid['resolutions'][zoom]
if int(resolution) == resolution:
return str(int(resolution))
else:
return str(resolution).replace('.', '_')
class TileGeneration:
def __init__(self, config_file, options=None, layer_name=None):
self.close_actions = []
self.geom = None
self.error = 0
if options is not None:
if not hasattr(options, 'bbox'):
options.bbox = None
if not hasattr(options, 'zoom'):
options.zoom = None
if not hasattr(options, 'test'):
options.test = None
if not hasattr(options, 'near'):
options.near = None
if not hasattr(options, 'time'):
options.time = None
if not hasattr(options, 'geom'):
options.geom = True
level = logging.WARNING
if options and options.quiet:
level = logging.ERROR
elif options and options.verbose:
level = logging.INFO
elif options and options.debug:
level = logging.DEBUG
logging.basicConfig(
format='%(levelname)s:%(name)s:%(funcName)s:%(message)s',
level=level)
with open(config_file) as f:
self.config = yaml.load(f)
self.options = options
self.validate_exists(self.config, 'config', 'grids')
self.grids = self.config['grids']
error = False
for gname, grid in self.config['grids'].items():
if type(gname) != str:
gname = str(gname)
self.config['grids'][gname] = grid
name = "grid[%s]" % gname
error = self.validate(
grid, name, 'name', attribute_type=str, default=gname, regex="^[a-zA-Z0-9_\-~\.]+$"
) or error
error = self.validate(
grid, name, 'resolution_scale',
attribute_type=int
) or error
error = self.validate(
grid, name, 'resolutions',
attribute_type=float, is_array=True, required=True
) or error
if not error and 'resolution_scale' not in grid:
scale = self._resolution_scale(grid['resolutions'])
grid['resolution_scale'] = scale
elif not error:
scale = grid['resolution_scale']
for r in grid['resolutions']:
if r * scale % 1 != 0.0:
logger.error("The resolution %s * resolution_scale %i is not an integer." % (r, scale))
error = True
error = self.validate(grid, name, 'bbox', attribute_type=float, is_array=True, required=True) or error
error = self.validate(grid, name, 'srs', attribute_type=str, required=True) or error
if not error:
srs = grid['srs'].split(':')
if len(srs) == 2:
if srs[0].lower() == 'epsg':
try:
srs[1] = int(srs[1])
except ValueError:
logger.error("The grid '%s' srs should have an int ref_id but it is %s." % (gname, srs[1]))
else:
logger.error("The grid '%s' srs should have the authority 'EPSG' but it is %s." % (
gname, srs[0])
)
error = True
else:
logger.error("The grid '%s' srs should have the syntax : but is %s." % (
gname, grid['srs']
))
error = True
error = self.validate(grid, name, 'proj4_literal', attribute_type=str) or error
if not error and 'proj4_literal' not in grid:
if srs[1] == 3857: # pragma: no cover
grid['proj4_literal'] = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 ' \
'+x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'
elif srs[1] == 21781:
grid['proj4_literal'] = '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' \
'+x_0=600000 +y_0=200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m ' \
'+no_defs'
elif srs[1] == 2056: # pragma: no cover
grid['proj4_literal'] = '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' \
'+x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m ' \
'+no_defs'
else:
grid['proj4_literal'] = '+init=%s' % grid['srs']
elif not error and grid['proj4_literal'] == '': # pragma: no cover
grid['proj4_literal'] = None
error = self.validate(grid, name, 'unit', attribute_type=str, default='m') or error
error = self.validate(grid, name, 'tile_size', attribute_type=int, default=256) or error
error = self.validate(
grid, name, 'matrix_identifier', attribute_type=str, default='zoom',
enumeration=['zoom', 'resolution']
) or error
grid['obj'] = FreeTileGrid(
resolutions=[int(r * scale) for r in grid['resolutions']],
scale=scale,
max_extent=grid['bbox'],
tile_size=grid['tile_size']) if not error else None
default = self.config.get('layer_default', {})
self.layers = {}
self.validate_exists(self.config, 'config', 'layers')
for lname, layer in self.config['layers'].items():
name = "layer[%s]" % lname
for k, v in default.items():
if k not in layer:
layer[k] = v
error = self.validate(
layer, name, 'name', attribute_type=str, default=lname, regex="^[a-zA-Z0-9_\-~\.]+$"
) or error
error = self.validate(layer, name, 'grid', attribute_type=str, required=True) or error
error = self.validate(layer, name, 'min_resolution_seed', attribute_type=float) or error
error = self.validate(layer, name, 'px_buffer', attribute_type=float, default=False) or error
error = self.validate(
layer, name, 'type', attribute_type=str, required=True,
enumeration=['wms', 'mapnik']
) or error
error = self.validate(layer, name, 'meta', attribute_type=bool, default=False) or error
if not layer['meta']:
layer['meta_size'] = 1
else:
error = self.validate(layer, name, 'meta_size', attribute_type=int, default=8) or error
error = self.validate(
layer, name, 'meta_buffer', attribute_type=int,
default=0 if layer['type'] == 'mapnik' else 128
) or error
error = self.validate(
layer, name, 'query_layers', attribute_type=str, is_array=True
) or error
if not error and layer['type'] == 'wms':
error = self.validate(layer, name, 'url', attribute_type=str, required=True) or error
error = self.validate(layer, name, 'generate_salt', attribute_type=bool, default=False) or error
if 'query_layers' in layer:
error = self.validate(
layer, name, 'info_formats', attribute_type=str, is_array=True,
default=['application/vnd.ogc.gml']
) or error
if not error and layer['type'] == 'mapnik':
error = self.validate(layer, name, 'mapfile', attribute_type=str, required=True) or error
error = self.validate(
layer, name, 'output_format', attribute_type=str, default='png',
enumeration=['png', 'png256', 'jpeg', 'grid']
) or error
error = self.validate(layer, name, 'data_buffer', attribute_type=int, default=128) or error
if layer['output_format'] == 'grid':
error = self.validate(layer, name, 'resolution', attribute_type=int, default=4) or error
error = self.validate(layer, name, 'layers_fields', attribute_type=dict, default={}) or error
error = self.validate(
layer, name, 'drop_empty_utfgrid', attribute_type=bool, default=False
) or error
if layer['meta']:
logger.error(
"The layer '%s' is of type Mapnik/Grid, that can't support matatiles." %
(layer['name'])
)
error = True
if 'min_resolution_seed' in layer or 'info_formats' in layer or \
'wms_url' in layer or 'query_layers' in layer:
error = self.validate(layer, name, 'wms_url', attribute_type=str, required=True) or error
error = self.validate(
layer, name, 'layers', attribute_type=str, default=['__all__'], is_array=True
) or error
if 'info_formats' in layer or 'query_layers' in layer:
error = self.validate(
layer, name, 'query_layers', attribute_type=str, default=['__all__'], is_array=True
) or error
error = self.validate(
layer, name, 'info_formats', attribute_type=str, is_array=True,
required=True
) or error
if not error and (layer['type'] == 'wms' or 'wms_url' in layer):
error = self.validate(layer, name, 'params', attribute_type=dict, default={
}) or error
for key in layer['params']:
self.validate(layer['params'], name + '/params', key, attribute_type=str) or error
error = self.validate(layer, name, 'headers', attribute_type=dict, default={
'Cache-Control': 'no-cache, no-store',
'Pragma': 'no-cache',
}) or error
for key in layer['headers']:
self.validate(layer['headers'], name + '/headers', key, attribute_type=str) or error
error = self.validate(
layer, name, 'layers', attribute_type=str, required=True, is_array=True
) or error
error = self.validate(layer, name, 'extension', attribute_type=str, required=True) or error
error = self.validate(layer, name, 'mime_type', attribute_type=str, required=True) or error
error = self.validate(
layer, name, 'wmts_style', attribute_type=str, required=True, regex="^[a-zA-Z0-9_\-~\.]+$"
) or error
error = self.validate(layer, name, 'dimensions', is_array=True, default=[]) or error
for d in layer['dimensions']:
dname = name + ".dimensions[%s]" % d.get('name', '')
error = self.validate(
d, dname, 'name', attribute_type=str, required=True, regex="^[a-zA-Z0-9_\-~\.]+$"
) or error
error = self.validate(
d, dname, 'value', attribute_type=str, required=True, regex="^[a-zA-Z0-9_\-~\.]+$"
) or error
error = self.validate(
d, dname, 'values', attribute_type=str, is_array=True, default=[d['value']]
) or error
error = self.validate(
d, dname, 'default', attribute_type=str, default=d['value'],
regex="^[a-zA-Z0-9_\-~\.]+$"
) or error
error = self.validate(
layer, name, 'pre_hash_post_process', attribute_type=str, default=False
) or error
error = self.validate(
layer, name, 'post_process', attribute_type=str, default=False
) or error
error = self.validate(layer, name, 'geoms', is_array=True, default=[]) or error
for i, g in enumerate(layer['geoms']):
gname = name + ".geoms[%i]" % i
# => connection required on the layer.
error = self.validate(
layer, name, 'connection', attribute_type=str, required=True
) or error
error = self.validate(
g, gname, 'sql', attribute_type=str, required=True
) or error
error = self.validate(
g, gname, 'min_resolution', attribute_type=float
) or error
error = self.validate(
g, gname, 'max_resolution', attribute_type=float
) or error
if 'empty_tile_detection' in layer:
error = self.validate(
layer['empty_tile_detection'], name + '.empty_tile_detection',
'size', attribute_type=int, required=True
) or error
error = self.validate(
layer['empty_tile_detection'], name + '.empty_tile_detection',
'hash', attribute_type=str, required=True
) or error
if 'empty_metatile_detection' in layer:
error = self.validate(
layer['empty_metatile_detection'], name + '.empty_metatile_detection',
'size', attribute_type=int, required=True
) or error
error = self.validate(
layer['empty_metatile_detection'], name + '.empty_metatile_detection',
'hash', attribute_type=str, required=True
) or error
if 'sqs' in layer:
error = self.validate(
layer['sqs'], name + '.sqs', 'queue',
attribute_type=str, required=True
) or error
error = self.validate(
layer['sqs'], name + '.sqs', 'region',
attribute_type=str, default='eu-west-1'
) or error
layer['grid_ref'] = self.grids[layer['grid']] if not error else None
self.layers[lname] = layer
self.validate_exists(self.config, 'config', 'caches')
self.caches = self.config['caches']
for cname, cache in self.caches.items():
name = "caches[%s]" % cname
error = self.validate(cache, name, 'name', attribute_type=str, default=cname) or error
error = self.validate(
cache, name, 'type', attribute_type=str, required=True,
enumeration=['s3', 'filesystem', 'mbtiles', 'bsddb']
) or error
error = self.validate(
cache, 'cache[%s]' % cache['name'], 'wmtscapabilities_file', attribute_type=str,
default='1.0.0/WMTSCapabilities.xml'
) or error
if cache['type'] == 'filesystem' or cache['type'] == 'mbtiles' or cache['type'] == 'bsddb':
error = self.validate(cache, name, 'folder', attribute_type=str, required=True) or error
elif cache['type'] == 's3':
error = self.validate(cache, name, 'bucket', attribute_type=str, required=True) or error
error = self.validate(cache, name, 'region', attribute_type=str, default='eu-west-1') or error
error = self.validate(cache, name, 'folder', attribute_type=str, default='') or error
error = self.validate(self.config, 'config', 'generation', attribute_type=dict, default={}) or error
error = self.validate(
self.config['generation'], 'generation', 'default_cache',
attribute_type=str, default='default'
) or error
error = self.validate(
self.config['generation'], 'generation', 'default_layers',
is_array=True, attribute_type=str, default=self.layers.keys()
) or error
error = self.validate(
self.config['generation'], 'generation', 'log_format', attribute_type=str,
default='%(levelname)s:%(name)s:%(funcName)s:%(message)s',
) or error
error = self.validate(self.config['generation'], 'generation', 'authorised_user', attribute_type=str) or error
error = self.validate(
self.config['generation'], 'generation', 'maxconsecutive_errors',
attribute_type=int, default=10
) or error
error = self.validate(
self.config, 'config',
'process', attribute_type=dict, default={}
) or error
for cmd_name, cmds in self.config['process'].items():
for i, cmd in enumerate(cmds):
error = self.validate(
cmd, 'process[%s][%i]' % (cmd_name, i),
'cmd', attribute_type=str, required=True
) or error
error = self.validate(
cmd, 'process[%s][%i]' % (cmd_name, i),
'need_out', attribute_type=bool, default=False
) or error
error = self.validate(
cmd, 'process[%s][%i]' % (cmd_name, i),
'arg', attribute_type=dict, default={}
) or error
error = self.validate(
cmd['arg'], 'process[%s][%i].arg' % (cmd_name, i),
'default', attribute_type=str
) or error
error = self.validate(
cmd['arg'], 'process[%s][%i].arg' % (cmd_name, i),
'verbose', attribute_type=str
) or error
error = self.validate(
cmd['arg'], 'process[%s][%i].arg' % (cmd_name, i),
'debug', attribute_type=str
) or error
error = self.validate(
cmd['arg'], 'process[%s][%i].arg' % (cmd_name, i),
'quiet', attribute_type=str
) or error
error = self.validate(self.config, 'config', 'ec2', attribute_type=dict) or error
if 'ec2' in self.config:
error = self.validate(
self.config['ec2'], 'ec2', 'number_process',
attribute_type=int, default=1
) or error
error = self.validate(
self.config['ec2'], 'ec2', 'host_type', attribute_type=str,
default='m1.medium', enumeration=[
't1.micro', 'm1.small', 'm1.medium', 'm1.large', 'm1.xlarge',
'm2.xlarge', 'm2.2xlarge', 'm2.4xlarge', 'c1.medium', 'c1.xlarge', 'cc1.4xlarge', 'cc2.8xlarge',
'cg1.4xlarge', 'hi1.4xlarge'
]
) or error
error = self.validate(
self.config['ec2'], 'ec2', 'ssh_options',
attribute_type=str
) or error
error = self.validate(self.config['ec2'], 'ec2', 'geodata_folder', attribute_type=str) or error
if 'geodata_folder' in self.config['ec2'] and self.config['ec2']['geodata_folder'][-1] != '/':
self.config['ec2']['geodata_folder'] += '/'
error = self.validate(self.config['ec2'], 'ec2', 'code_folder', attribute_type=str) or error
if 'code_folder' in self.config['ec2'] and self.config['ec2']['code_folder'][-1] != '/':
self.config['ec2']['code_folder'] += '/'
error = self.validate(
self.config['ec2'], 'ec2', 'deploy_config',
attribute_type=str, default="tilegeneration/deploy.cfg") or error
error = self.validate(
self.config['ec2'], 'ec2', 'build_cmds',
attribute_type=str, is_array=True, default=[
"mkdir .build",
"virtualenv .build/venv",
".build/venv/bin/pip install ."
]
) or error
error = self.validate(self.config['ec2'], 'ec2', 'apache_config', attribute_type=str) or error
error = self.validate(self.config['ec2'], 'ec2', 'apache_content', attribute_type=str) or error
error = self.validate(
self.config['ec2'], 'ec2', 'disable_geodata',
attribute_type=bool, default=False
) or error
error = self.validate(
self.config['ec2'], 'ec2', 'disable_code',
attribute_type=bool, default=False
) or error
error = self.validate(
self.config['ec2'], 'ec2', 'disable_database',
attribute_type=bool, default=False
) or error
error = self.validate(
self.config['ec2'], 'ec2', 'disable_fillqueue',
attribute_type=bool, default=False
) or error
error = self.validate(
self.config['ec2'], 'ec2', 'disable_tilesgen',
attribute_type=bool, default=False
) or error
if 'sns' in self.config: # pragma: no cover
error = self.validate(self.config['sns'], 'sns', 'topic', attribute_type=str, required=True) or error
error = self.validate(self.config['sns'], 'sns', 'region', attribute_type=str, default='eu-west-1') or error
if error:
exit(1)
logging.basicConfig(
format=self.config['generation']['log_format'],
level=level)
if options and options.zoom is not None:
error_message = (
"The zoom argument '%s' has incorect format, "
"it can be a single value, a range (3-9), a list of values (2,5,7)."
) % options.zoom
if options.zoom.find('-') >= 0:
r = options.zoom.split('-')
if len(r) != 2: # pragma: no cover
logger.error(error_message)
error = True
try:
options.zoom = range(int(r[0]), int(r[1]) + 1)
except ValueError: # pragma: no cover
logger.error(error_message)
error = True
elif options.zoom.find(',') >= 0:
try:
options.zoom = [int(z) for z in options.zoom.split(',')]
except ValueError: # pragma: no cover
logger.error(error_message)
error = True
else:
try:
options.zoom = [int(options.zoom)]
except ValueError: # pragma: no cover
logger.error(error_message)
error = True
if error: # pragma: no cover
exit(1)
self.layer = None
if layer_name and not error:
self.set_layer(layer_name, options)
def _primefactors(self, x):
factorlist = []
loop = 2
while loop <= x:
if x % loop == 0:
x /= loop
factorlist.append(loop)
else:
loop += 1
return factorlist
def _resolution_scale(self, resolutions):
prime_fact = {}
for resolution in resolutions:
denominator = Fraction(str(resolution)).denominator
prime_factors = self._primefactors(denominator)
for factor in set(prime_factors):
if factor not in prime_fact:
prime_fact[factor] = 0
prime_fact[factor] = max(prime_fact[factor], len([f for f in prime_factors if f == factor]))
result = 1
for fact, nb in prime_fact.items():
result *= fact ** nb
return result
def get_store(self, cache, layer, dimensions=None, read_only=False):
# build layout
grid = layer['grid_ref'] if 'grid_ref' in layer else None
layout = WMTSTileLayout(
layer=layer['name'],
url=cache['folder'],
style=layer['wmts_style'],
format='.' + layer['extension'],
dimensions=dimensions if dimensions is not None else [
(dimension['name'], dimension['value'])
for dimension in layer['dimensions']
],
tile_matrix_set=layer['grid'],
tile_matrix=lambda z: get_tile_matrix_identifier(grid, zoom=z),
request_encoding='REST',
)
# store
if cache['type'] == 's3':
# on s3
cache_tilestore = S3TileStore(cache['bucket'], layout) # pragma: no cover
elif cache['type'] == 'mbtiles':
# on mbtiles file
filename = layout.filename(TileCoord(0, 0, 0)).replace(
'/0/0/0', ''
) + '.mbtiles'
if not os.path.exists(os.path.dirname(filename)):
os.makedirs(os.path.dirname(filename))
cache_tilestore = MBTilesTileStore(
sqlite3.connect(filename),
content_type=layer['mime_type'],
tilecoord_in_topleft=True,
)
elif cache['type'] == 'bsddb':
# on bsddb file
filename = layout.filename(TileCoord(0, 0, 0)).replace(
'/0/0/0', ''
) + '.bsddb'
if not os.path.exists(os.path.dirname(filename)):
os.makedirs(os.path.dirname(filename))
db = bsddb.hashopen(
filename,
# and os.path.exists(filename) to avoid error on non existing file
'r' if read_only and os.path.exists(filename) else 'c'
)
class Close:
def __call__(self):
self.db.close()
ca = Close()
ca.db = db
self.close_actions.append(ca)
cache_tilestore = BSDDBTileStore(
db, content_type=layer['mime_type'],
)
elif cache['type'] == 'filesystem':
# on filesystem
cache_tilestore = FilesystemTileStore(
layout,
content_type=layer['mime_type'],
)
else:
exit('unknown cache type: ' + cache['type']) # pragma: no cover
return cache_tilestore
def validate_exists(self, obj, obj_name, attribute):
if attribute not in obj:
logger.error("The attribute '%s' is required in the object %s." % (attribute, obj_name))
exit(1)
def _validate_type(self, value, attribute_type, enumeration, regex=None):
if attribute_type is not None:
if attribute_type == int and type(value) == str:
try:
value = int(round(eval(value)))
except:
return (True, None, 'right int expression: %s' % value)
if attribute_type == float:
if type(value) == int:
value = float(value)
if type(value) == str:
try:
value = float(eval(value))
except:
return (True, None, 'right float expression: %s' % value)
elif type(value) != attribute_type:
return (True, None, str(attribute_type))
elif attribute_type == str:
typ = type(value)
if typ == list or typ == dict:
return (True, None, str(attribute_type))
if typ != str:
value = str(value)
if regex is not None:
if re.search(regex, value) is None:
return (True, None, "value '%s' don't respect regex '%s'" % (value, regex))
else:
if type(value) != attribute_type:
return (True, None, str(attribute_type))
if enumeration:
return (value not in enumeration, value, str(enumeration))
return (False, value, None)
def validate(
self, obj, obj_name, attribute, attribute_type=None, is_array=False,
default=None, required=False, enumeration=None, **kargs):
if attribute not in obj:
if required:
logger.error("The attribute '%s' is required in the object %s." % (attribute, obj_name))
return True
elif default is False:
# no value
obj[attribute] = False
# no test
return False
elif default is not None:
obj[attribute] = default
else:
# no value to test
return False
if is_array:
if type(obj[attribute]) == str:
obj[attribute] = [v.strip() for v in obj[attribute].split(',')]
if type(obj[attribute]) == list:
for n, v in enumerate(obj[attribute]):
result, value, type_error = self._validate_type(v, attribute_type, enumeration, **kargs)
if result:
logger.error(
"The attribute '%s' of the object %s has an element who is not a %s." %
(attribute, obj_name, type_error)
)
return True
obj[attribute][n] = value
else:
logger.error("The attribute '%s' of the object %s is not an array." % (attribute, obj_name))
return True
else:
result, value, type_error = self._validate_type(obj[attribute], attribute_type, enumeration, **kargs)
if result:
logger.error(
"The attribute '%s' of the object %s is not a %s." %
(attribute, obj_name, type_error)
)
return True
obj[attribute] = value
return False
def validate_apache_config(self):
error = False
error = self.validate(self.config, 'config', 'apache', attribute_type=dict, default={}) or error
error = self.validate(
self.config['apache'], 'apache', 'location', attribute_type=str,
default='/tiles'
) or error
error = self.validate(
self.config['apache'], 'apache', 'config_file', attribute_type=str,
default='apache/tiles.conf'
) or error
error = self.validate(
self.config['apache'], 'apache', 'expires', attribute_type=int,
default=8
) or error
return not error
def validate_mapcache_config(self):
error = False
error = self.validate(self.config, 'config', 'mapcache', attribute_type=dict, default={}) or error
error = self.validate(
self.config['mapcache'], 'mapcache', 'config_file', attribute_type=str,
default='apache/mapcache.xml'
) or error
error = self.validate(
self.config['mapcache'], 'mapcache', 'memcache_host', attribute_type=str,
default='localhost'
) or error
error = self.validate(
self.config['mapcache'], 'mapcache', 'memcache_port', attribute_type=int,
default='11211'
) or error
error = self.validate(
self.config['mapcache'], 'mapcache', 'location', attribute_type=str,
default='/mapcache'
) or error
return not error
def set_layer(self, layer, options):
self.create_log_tiles_error(layer)
self.layer = self.layers[layer]
if options.near is not None or (
options.time is not None and 'bbox' in self.layer and options.zoom is not None
):
if options.zoom is None or len(options.zoom) != 1: # pragma: no cover
exit('Option --near needs the option --zoom with one value.')
if not (options.time is not None or options.test is not None): # pragma: no cover
exit('Option --near needs the option --time or --test.')
position = options.near if options.near is not None else [
(self.layer['bbox'][0] + self.layer['bbox'][2]) / 2,
(self.layer['bbox'][1] + self.layer['bbox'][3]) / 2,
]
bbox = self.layer['grid_ref']['bbox']
diff = [position[0] - bbox[0], position[1] - bbox[1]]
resolution = self.layer['grid_ref']['resolutions'][options.zoom[0]]
mt_to_m = self.layer['meta_size'] * self.layer['grid_ref']['tile_size'] * resolution
mt = [float(d) / mt_to_m for d in diff]
nb_tile = options.time * 3 if options.time is not None else options.test
nb_mt = nb_tile / (self.layer['meta_size'] ** 2)
nb_sqrt_mt = ceil(sqrt(nb_mt))
mt_origin = [round(m - nb_sqrt_mt / 2) for m in mt]
self.init_geom([
bbox[0] + mt_origin[0] * mt_to_m,
bbox[1] + mt_origin[1] * mt_to_m,
bbox[0] + (mt_origin[0] + nb_sqrt_mt) * mt_to_m,
bbox[1] + (mt_origin[1] + nb_sqrt_mt) * mt_to_m,
])
elif options.bbox is not None:
self.init_geom(options.bbox)
elif 'bbox' in self.layer:
self.init_geom(self.layer['bbox'])
else:
self.init_geom(self.layer['grid_ref']['bbox'])
def get_grid(self, name=None):
if not name:
name = self.layer['grid']
return self.grids[name]
def get_tilesstore(self, cache_name):
cache = self.caches[cache_name]
dimensions_args = {}
for dim in self.options.dimensions:
dim = dim.split('=')
if len(dim) != 2: # pragma: no cover
exit(
'the DIMENTIONS option should be like this '
'DATE=2013 VERSION=13.'
)
dimensions_args[dim[0]] = dim[1]
dimensions = []
for dim in self.layer['dimensions']:
dimensions.append((
dim['name'],
dimensions_args[dim['name']] if
dim['name'] in dimensions_args else dim['value']
))
cache_tilestore = self.get_store(cache, self.layer, dimensions=dimensions)
if cache_tilestore is None:
exit('Unknown cache type: ' + cache['type']) # pragma: no cover
return cache_tilestore
def get_sqs_queue(self): # pragma: no cover
if self.layer is None:
exit("A layer must be specified.")
if 'sqs' not in self.layer:
exit("The layer '%s' hasn't any configured queue" % self.layer['name'])
connection = boto.sqs.connect_to_region(self.layer['sqs']['region'])
queue = connection.get_queue(self.layer['sqs']['queue'])
queue.set_message_class(JSONMessage)
return queue
def init_geom(self, extent=None):
self.geoms = self.get_geoms(self.layer, extent)
def get_geoms(self, layer, extent=None):
if not hasattr(self, 'layers_geoms'):
layers_geoms = {}
if layer['name'] in layers_geoms: # pragma: no cover
# already build
return layers_geoms[layer['name']]
layer_geoms = {}
layers_geoms[layer['name']] = layer_geoms
if extent:
geom = Polygon((
(extent[0], extent[1]),
(extent[0], extent[3]),
(extent[2], extent[3]),
(extent[2], extent[1]),
))
for z, r in enumerate(layer['grid_ref']['resolutions']):
layer_geoms[z] = geom
if self.options is None or (
self.options.near is None and self.options.geom
):
if 'connection' in layer:
connection = psycopg2.connect(layer['connection'])
cursor = connection.cursor()
for g in layer['geoms']:
sql = 'SELECT ST_AsBinary(geom) FROM (SELECT %s) AS g' % g['sql']
logger.info('Execute SQL: %s.' % sql)
cursor.execute(sql)
geoms = [loads_wkb(str(r[0])) for r in cursor.fetchall()]
geom = cascaded_union(geoms)
if extent:
geom = geom.intersection(Polygon((
(extent[0], extent[1]),
(extent[0], extent[3]),
(extent[2], extent[3]),
(extent[2], extent[1]),
)))
for z, r in enumerate(layer['grid_ref']['resolutions']):
if ('min_resolution' not in g or g['min_resolution'] <= r) and \
('max_resolution' not in g or g['max_resolution'] >= r):
layer_geoms[z] = geom
cursor.close()
connection.close()
return layer_geoms
def add_local_process_filter(self): # pragma: no cover
self.ifilter(LocalProcessFilter(
self.config["ec2"]["number_process"],
self.options.local_process_number
))
def get_geoms_filter(self, layer, grid, geoms, queue_store=None):
return IntersectGeometryFilter(
grid=grid,
geoms=geoms,
queue_store=queue_store,
px_buffer=(
layer['px_buffer'] +
layer['meta_buffer'] if layer['meta'] else 0
)
)
def add_geom_filter(self, queue_store=None):
self.ifilter(self.get_geoms_filter(
layer=self.layer,
grid=self.get_grid(),
geoms=self.geoms,
queue_store=queue_store,
), "Intersect with geom")
def add_logger(self):
if not self.options.quiet and \
not self.options.verbose and \
not self.options.debug:
def log_tiles(tile):
variables = dict()
variables.update(tile.__dict__)
variables.update(tile.tilecoord.__dict__)
sys.stdout.write("%(tilecoord)s \r" % variables)
sys.stdout.flush()
return tile
self.imap(log_tiles)
elif self.options.verbose:
self.imap(Logger(logger, logging.INFO, '%(tilecoord)s'))
def add_metatile_splitter(self):
store = MetaTileSplitterTileStore(
self.layer['mime_type'],
self.layer['grid_ref']['tile_size'],
self.layer['meta_buffer'])
if self.options.debug:
def meta_get(tilestream): # pragma: no cover
for metatile in tilestream:
substream = store.get((metatile,))
for tile in substream:
tile.metatile = metatile
yield tile
self.tilestream = meta_get(self.tilestream) # pragma: no cover
else:
def safe_get(tilestream):
for metatile in tilestream:
try:
substream = store.get((metatile,))
for tile in substream:
tile.metatile = metatile
yield tile
except GeneratorExit as e:
raise e
except: # pragma: no cover
data = repr(metatile.data)
if len(data) < 2000:
metatile.error = str(sys.exc_info()[1]) + " - " + metatile.data
else:
class NoRepr:
def __init__(self, value):
self.value = value
def __repr__(self):
return self.value
metatile.error = NoRepr(
repr(str(sys.exc_info()[1])) + " - " + data[0:2000] + '...'
)
yield metatile
self.tilestream = safe_get(self.tilestream)
error_file = None
def create_log_tiles_error(self, layer):
if 'error_file' in self.config['generation']:
now = datetime.now()
time = now.strftime('%d-%m-%Y %H:%M:%S')
self.error_file = open(
self.config['generation']['error_file'].format(
layer=layer, datetime=now
),
'a'
)
self.error_file.write("# [%s] Start the layer '%s' generation\n" % (time, layer))
def log_tiles_error(self, tilecoord=None, message=None):
if 'error_file' in self.config['generation']:
time = datetime.now().strftime('%d-%m-%Y %H:%M:%S')
if self.error_file is None: # pragma: no cover
raise "Missing error file"
tilecoord = "" if tilecoord is None else "%s " % tilecoord
message = "" if message is None else " %s" % message
self.error_file.write('%s# [%s]%s\n' % (tilecoord, time, message.replace('\n', ' ')))
def add_error_filters(self):
self.imap(LogErrors(
logger, logging.ERROR,
"Error in tile: %(tilecoord)s, %(error)r"
))
if 'error_file' in self.config['generation']:
def do(tile):
if tile and tile.error:
self.log_tiles_error(tilecoord=tile.tilecoord, message=repr(tile.error))
return tile
self.imap(do)
if 'maxconsecutive_errors' in self.config['generation']:
self.tilestream = map(MaximumConsecutiveErrors(
self.config['generation']['maxconsecutive_errors']), self.tilestream)
def drop_count(tile):
if tile and tile.error:
self.error += 1
return None
return tile
self.ifilter(drop_count)
def init_tilecoords(self):
resolutions = self.layer['grid_ref']['resolutions']
if self.options.time is not None and self.options.zoom is None:
if 'min_resolution_seed' in self.layer: # pragma: no cover
self.options.zoom = [resolutions.index(
self.layer['min_resolution_seed']
)]
else:
self.options.zoom = [len(resolutions) - 1]
if self.options.zoom is not None:
zoom_max = len(resolutions) - 1
for zoom in self.options.zoom:
if zoom > zoom_max:
logger.warn(
"zoom %i is greater than the maximum zoom %i"
" of grid %s of layer %s, ignored." % (
zoom, zoom_max, self.layer['grid'], self.layer['name']
)
)
self.options.zoom = [z for z in self.options.zoom if z <= zoom_max]
if 'min_resolution_seed' in self.layer:
if self.options.zoom is None:
self.options.zoom = []
for z, resolution in enumerate(resolutions):
if resolution >= self.layer['min_resolution_seed']:
self.options.zoom.append(z)
else:
for zoom in self.options.zoom:
resolution = resolutions[zoom]
if resolution < self.layer['min_resolution_seed']:
logger.warn(
"zoom %i corresponds to resolution %s is smaller"
" than the 'min_resolution_seed' %s of layer %s, ignored." %
(
zoom, resolution, self.layer['min_resolution_seed'], self.layer['name']
)
)
self.options.zoom = [
z for z in self.options.zoom if
resolutions[z] >= self.layer['min_resolution_seed']
]
if self.options.zoom is None:
self.options.zoom = [z for z, r in enumerate(resolutions)]
# fill the bounding pyramid
tilegrid = self.layer['grid_ref']['obj']
bounding_pyramid = BoundingPyramid(tilegrid=tilegrid)
for zoom in self.options.zoom:
if zoom in self.geoms:
extent = self.geoms[zoom].bounds
if len(extent) == 0:
logger.warn("bounds empty for zoom %i" % zoom)
else:
minx, miny, maxx, maxy = extent
px_buffer = self.layer['px_buffer']
m_buffer = px_buffer * resolutions[zoom]
minx -= m_buffer
miny -= m_buffer
maxx += m_buffer
maxy += m_buffer
bounding_pyramid.add(tilegrid.tilecoord(
zoom,
max(minx, tilegrid.max_extent[0]),
max(miny, tilegrid.max_extent[1]),
))
bounding_pyramid.add(tilegrid.tilecoord(
zoom,
min(maxx, tilegrid.max_extent[2]),
min(maxy, tilegrid.max_extent[3]),
))
meta = self.layer['meta']
if meta:
self.set_tilecoords(bounding_pyramid.metatilecoords(self.layer['meta_size']))
else:
self.set_tilecoords(bounding_pyramid)
def set_tilecoords(self, tilecoords):
self.tilestream = (
Tile(tilecoord) for tilecoord in tilecoords
)
def set_store(self, store): # pragma: no cover
self.tilestream = store.list()
def counter(self, size=False):
count = CountSize() if size else Count()
self.imap(count)
return count
def process(self, name=None):
if name is None:
name = self.layer['post_process']
if name:
self.imap(Process(self.config['process'][name], self.options))
def get(self, store, time_message=None):
if self.options.debug:
self.tilestream = store.get(self.tilestream) # pragma: no cover
else:
def safe_get(tile):
try:
n = datetime.now()
t = store.get_one(tile)
if time_message:
logger.info("%s in %s" % (time_message, str(datetime.now() - n)))
return t
except GeneratorExit as e: # pragma: no cover
raise e
except SystemExit as e: # pragma: no cover
raise e
except KeyboardInterrupt: # pragma: no cover
exit("User interrupt")
except: # pragma: no cover
tile.error = sys.exc_info()[1]
return tile
self.tilestream = map(safe_get, filter(None, self.tilestream))
def put(self, store, time_message=None):
if self.options.debug:
self.tilestream = store.put(self.tilestream) # pragma: no cover
else:
def safe_put(tile):
try:
n = datetime.now()
t = store.put_one(tile)
if time_message:
logger.info("%s in %s" % (time_message, str(datetime.now() - n)))
return t
except GeneratorExit as e: # pragma: no cover
raise e
except SystemExit as e: # pragma: no cover
raise e
except KeyboardInterrupt: # pragma: no cover
exit("User interrupt")
except: # pragma: no cover
tile.error = sys.exc_info()[1]
return tile
self.tilestream = map(safe_put, filter(None, self.tilestream))
def delete(self, store, time_message=None): # pragma: no cover
if self.options.debug:
self.tilestream = store.delete(self.tilestream)
else:
def safe_delete(tile):
try:
n = datetime.now()
t = store.delete_one(tile)
if time_message:
logger.info("%s in %s" % (time_message, str(datetime.now() - n)))
return t
except GeneratorExit as e: # pragma: no cover
raise e
except SystemExit as e: # pragma: no cover
raise e
except KeyboardInterrupt: # pragma: no cover
exit("User interrupt")
except: # pragma: no cover
tile.error = sys.exc_info()[1]
return tile
self.tilestream = map(safe_delete, filter(None, self.tilestream))
def imap(self, tile_filter, time_message=None):
if self.options.debug:
self.tilestream = map(tile_filter, self.tilestream) # pragma: no cover
else:
def safe_imap(tile):
try:
n = datetime.now()
t = tile_filter(tile)
if time_message: # pragma: no cover
logger.info("%s in %s" % (time_message, str(datetime.now() - n)))
return t
except GeneratorExit as e: # pragma: no cover
raise e
except SystemExit as e: # pragma: no cover
raise e
except KeyboardInterrupt: # pragma: no cover
exit("User interrupt")
except: # pragma: no cover
tile.error = sys.exc_info()[1]
return tile
self.tilestream = map(safe_imap, filter(None, self.tilestream))
def ifilter(self, tile_filter, time_message=None):
if self.options.debug:
self.tilestream = filter(tile_filter, self.tilestream) # pragma: no cover
else:
def safe_filter(tile):
if tile:
try:
n = datetime.now()
t = tile_filter(tile)
if time_message:
logger.debug("%s in %s" % (time_message, str(datetime.now() - n)))
return t
except GeneratorExit as e: # pragma: no cover
raise e
except SystemExit as e: # pragma: no cover
raise e
except KeyboardInterrupt: # pragma: no cover
exit("User interrupt")
except: # pragma: no cover
tile.error = sys.exc_info()[1]
return tile
self.tilestream = filter(safe_filter, self.tilestream)
def consume(self, test=None):
if test is None:
test = self.options.test
start = datetime.now()
consume(self.tilestream, test)
self.duration = datetime.now() - start
for ca in self.close_actions:
ca()
class Count:
def __init__(self):
self.nb = 0
def __call__(self, tile=None):
self.nb += 1
return tile
class CountSize:
def __init__(self):
self.nb = 0
self.size = 0
def __call__(self, tile=None):
if tile and tile.data:
self.nb += 1
self.size += len(tile.data)
return tile
class HashDropper:
"""
Create a filter to remove the tiles data where they have
the specified size and hash.
Used to drop the empty tiles.
The ``store`` is used to delete the empty tiles.
"""
def __init__(self, size, sha1code, store=None, queue_store=None, count=None):
self.size = size
self.sha1code = sha1code
self.store = store
self.queue_store = queue_store
self.count = count
def __call__(self, tile):
if len(tile.data) != self.size or \
sha1(tile.data).hexdigest() != self.sha1code:
return tile
else:
if self.store is not None:
if tile.tilecoord.n != 1:
for tilecoord in tile.tilecoord:
self.store.delete_one(Tile(tilecoord))
else:
self.store.delete_one(tile)
logger.info("The tile %s is dropped" % str(tile.tilecoord))
if hasattr(tile, 'metatile'):
tile.metatile.elapsed_togenerate -= 1
if tile.metatile.elapsed_togenerate == 0 and self.queue_store is not None:
self.queue_store.delete_one(tile.metatile) # pragma: no cover
elif self.queue_store is not None: # pragma: no cover
self.queue_store.delete_one(tile)
if self.count:
self.count()
return None
class HashLogger:
"""
Log the tile size and hash.
"""
def __init__(self, block):
self.block = block
def __call__(self, tile):
ref = None
try:
image = Image.open(cStringIO(tile.data))
except IOError as e: # pragma: no cover
logger.error(tile.data)
raise e
for px in image.getdata():
if ref is None:
ref = px
elif px != ref:
exit("Error: image is not uniform.")
print("""Tile: %s
%s:
size: %i
hash: %s""" % (str(tile.tilecoord), self.block, len(tile.data), sha1(tile.data).hexdigest()))
return tile
class LocalProcessFilter: # pragma: no cover
def __init__(self, nb_process, process_nb):
self.nb_process = nb_process
self.process_nb = int(process_nb)
def filter(self, tilecoord):
nb = tilecoord.z + tilecoord.x / tilecoord.n + tilecoord.y / tilecoord.n
return nb % self.nb_process == self.process_nb
def __call__(self, tile):
return tile if self.filter(tile.tilecoord) else None
class IntersectGeometryFilter:
def __init__(self, grid, geoms=None, queue_store=None, px_buffer=0):
self.grid = grid
self.geoms = geoms
self.queue_store = queue_store
self.px_buffer = px_buffer
def filter_tilecoord(self, tilecoord):
return self.bbox_polygon(
self.grid['obj'].extent(
tilecoord,
self.grid['resolutions'][tilecoord.z] * self.px_buffer
)
).intersects(self.geoms[tilecoord.z])
def __call__(self, tile):
return tile if self.filter_tilecoord(tile.tilecoord) else None
def bbox_polygon(self, bbox):
return Polygon((
(bbox[0], bbox[1]),
(bbox[0], bbox[3]),
(bbox[2], bbox[3]),
(bbox[2], bbox[1])
))
class DropEmpty:
"""
Create a filter for dropping all tiles with errors.
"""
def __init__(self, gene):
self.gene = gene
def __call__(self, tile):
if not tile or not tile.data: # pragma: no cover
logger.error("The tile: %(tilecoord)s is empty" % {
'tilecoord': tile.tilecoord if tile else 'not defined'
})
if 'error_file' in self.gene.config['generation'] and tile:
self.gene.log_tiles_error(tilecoord=tile.tilecoord, message='The tile is empty')
return None
else:
return tile
def quote(arg):
if ' ' in arg:
if "'" in arg:
if '"' in arg:
return "'%s'" % arg.replace("'", "\\'")
else:
return '"%s"' % arg
else:
return "'%s'" % arg
elif arg == '':
return "''"
else:
return arg
def parse_tilecoord(string_representation):
parts = string_representation.split(':')
coords = [int(v) for v in parts[0].split('/')]
if len(coords) != 3: # pragma: no cover
raise ValueError("Wrong number of coordinates")
z, x, y = coords
if len(parts) == 1:
tilecoord = TileCoord(z, x, y)
elif len(parts) == 2:
meta = parts[1].split('/')
if len(meta) != 2: # pragma: no cover
raise ValueError("No one '/' in meta coordinates")
tilecoord = TileCoord(z, x, y, int(meta[0]))
else: # pragma: no cover
raise ValueError("More than on ':' in the tilecoord")
return tilecoord
class Process:
def __init__(self, config, options):
self.config = config
self.options = options
def __call__(self, tile):
if tile and tile.data:
fd_in, name_in = tempfile.mkstemp()
file_in = open(name_in, 'wb')
file_in.write(tile.data)
file_in.close()
for cmd in self.config:
args = []
if not self.options.verbose and \
not self.options.debug and \
not self.options.quiet and \
'default' in cmd['arg']:
args.append(cmd['arg']['default'])
if self.options.verbose and 'verbose' in cmd['arg']:
args.append(cmd['arg']['verbose'])
if self.options.debug and 'debug' in cmd['arg']:
args.append(cmd['arg']['debug'])
if self.options.quiet and 'quiet' in cmd['arg']:
args.append(cmd['arg']['quiet'])
if cmd['need_out']:
fd_out, name_out = tempfile.mkstemp()
os.unlink(name_out)
else: # pragma: no cover
name_out = name_in
command = cmd['cmd'] % {
'in': name_in,
'out': name_out,
'args': ' '.join(args),
'x': tile.tilecoord.x,
'y': tile.tilecoord.y,
'z': tile.tilecoord.z
}
logger.info('process: %s' % command)
code = subprocess.call(command, shell=True)
if code != 0: # pragma: no cover
tile.error = "Command '%s' on tile %s " \
"return error code %i" % \
(command, tile.tilecoord, code)
tile.data = None
return tile
if cmd['need_out']:
os.close(fd_in)
name_in = name_out
fd_in = fd_out
file_out = open(name_in, 'rb')
tile.data = file_out.read()
file_out.close()
os.close(fd_in)
return tile
class TilesFileStore:
def __init__(self, tiles_file):
self.tiles_file = open(tiles_file)
def list(self):
while True:
line = self.tiles_file.readline()
if not line:
return
line = line.split('#')[0].strip()
if line != '':
try:
yield Tile(parse_tilecoord(line))
except ValueError as e: # pragma: no cover
logger.error("A tile '%s' is not in the format 'z/x/y' or z/x/y:+n/+n\n%r" % (line, e))
PK :KD4ĉ tilecloud_chain/openlayers_js.pyopenlayers_js = """var callback = function(infoLookup) {
var msg = "";
if (infoLookup) {
var info;
for (var idx in infoLookup) {
// idx can be used to retrieve layer from map.layers[idx]
info = infoLookup[idx];
if (info && info.data) {
msg += "[" + info.id + "]"
for (k in info.data) {
msg += '
' + k + ': ' + info.data[k];
}
}
}
}
document.getElementById("attrs").innerHTML = msg;
};
map = new OpenLayers.Map({
div: "map",
projection: "{{srs}}",
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.Zoom(),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.LayerSwitcher(),
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.UTFGrid({
callback: callback,
handlerMode: "hover",
handlerOptions: {
'delay': 0,
'pixelTolerance': 0
},
reset: function() {}
})
],
center: [{{center_x}}, {{center_y}}],
zoom: 0
});
var format = new OpenLayers.Format.WMTSCapabilities();
OpenLayers.Request.GET({
url: "{{http_url}}1.0.0/WMTSCapabilities.xml",
success: function(request) {
var doc = request.responseXML;
if (!doc || !doc.documentElement) {
doc = request.responseText;
}
var capabilities = format.read(doc);
{% for layer in layers %}
map.addLayer(format.createLayer(capabilities, {
layer: "{{layer.name}}",
maxExtent: {{layer.maxExtent}},{%
if layer.grid %}
isBaseLayer: false,
utfgridResolution: {{layer.resolution}}{%
else %}
isBaseLayer: true{%
endif %}
}));{%
endfor %}
},
failure: function() {
alert("Trouble getting capabilities doc");
OpenLayers.Console.error.apply(OpenLayers.Console, arguments);
}
});"""
PK zkGht ht tilecloud_chain/OpenLayers.jsvar OpenLayers={VERSION_NUMBER:"Release 2.13 dev",singleFile:true,_getScriptLocation:(function(){var r=new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),s=document.getElementsByTagName('script'),src,m,l="";for(var i=0,len=s.length;i0){fig=parseFloat(num.toPrecision(sig));}
return fig;},format:function(num,dec,tsep,dsep){dec=(typeof dec!="undefined")?dec:0;tsep=(typeof tsep!="undefined")?tsep:OpenLayers.Number.thousandsSeparator;dsep=(typeof dsep!="undefined")?dsep:OpenLayers.Number.decimalSeparator;if(dec!=null){num=parseFloat(num.toFixed(dec));}
var parts=num.toString().split(".");if(parts.length==1&&dec==null){dec=0;}
var integer=parts[0];if(tsep){var thousands=/(-?[0-9]+)([0-9]{3})/;while(thousands.test(integer)){integer=integer.replace(thousands,"$1"+tsep+"$2");}}
var str;if(dec==0){str=integer;}else{var rem=parts.length>1?parts[1]:"0";if(dec!=null){rem=rem+new Array(dec-rem.length+1).join("0");}
str=integer+dsep+rem;}
return str;},zeroPad:function(num,len,radix){var str=num.toString(radix||10);while(str.length1){var newArgs=[C,P].concat(Array.prototype.slice.call(arguments).slice(1,len-1),F);OpenLayers.inherit.apply(null,newArgs);}else{C.prototype=F;}
return C;};OpenLayers.inherit=function(C,P){var F=function(){};F.prototype=P.prototype;C.prototype=new F;var i,l,o;for(i=2,l=arguments.length;ithis.right)){this.right=object.right;}
if((this.top==null)||(object.top>this.top)){this.top=object.top;}
break;}}},extendXY:function(x,y){this.centerLonLat=null;if((this.left==null)||(xthis.right)){this.right=x;}
if((this.top==null)||(y>this.top)){this.top=y;}},containsLonLat:function(ll,options){if(typeof options==="boolean"){options={inclusive:options};}
options=options||{};var contains=this.contains(ll.lon,ll.lat,options.inclusive),worldBounds=options.worldBounds;if(worldBounds&&!contains){var worldWidth=worldBounds.getWidth();var worldCenterX=(worldBounds.left+worldBounds.right)/2;var worldsAway=Math.round((ll.lon-worldCenterX)/worldWidth);contains=this.containsLonLat({lon:ll.lon-worldsAway*worldWidth,lat:ll.lat},{inclusive:options.inclusive});}
return contains;},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
if(x==null||y==null){return false;}
x=OpenLayers.Util.toFloat(x);y=OpenLayers.Util.toFloat(y);var contains=false;if(inclusive){contains=((x>=this.left)&&(x<=this.right)&&(y>=this.bottom)&&(y<=this.top));}else{contains=((x>this.left)&&(xthis.bottom)&&(y=self.bottom)&&(bounds.bottom<=self.top))||((self.bottom>=bounds.bottom)&&(self.bottom<=bounds.top)));var inTop=(((bounds.top>=self.bottom)&&(bounds.top<=self.top))||((self.top>bounds.bottom)&&(self.top=self.left)&&(bounds.left<=self.right))||((self.left>=bounds.left)&&(self.left<=bounds.right)));var inRight=(((bounds.right>=self.left)&&(bounds.right<=self.right))||((self.right>=bounds.left)&&(self.right<=bounds.right)));intersects=((inBottom||inTop)&&(inLeft||inRight));}
if(options.worldBounds&&!intersects){var world=options.worldBounds;var width=world.getWidth();var selfCrosses=!world.containsBounds(self);var boundsCrosses=!world.containsBounds(bounds);if(selfCrosses&&!boundsCrosses){bounds=bounds.add(-width,0);intersects=self.intersectsBounds(bounds,{inclusive:options.inclusive});}else if(boundsCrosses&&!selfCrosses){self=self.add(-width,0);intersects=bounds.intersectsBounds(self,{inclusive:options.inclusive});}}
return intersects;},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
if(inclusive==null){inclusive=true;}
var bottomLeft=this.contains(bounds.left,bounds.bottom,inclusive);var bottomRight=this.contains(bounds.right,bounds.bottom,inclusive);var topLeft=this.contains(bounds.left,bounds.top,inclusive);var topRight=this.contains(bounds.right,bounds.top,inclusive);return(partial)?(bottomLeft||bottomRight||topLeft||topRight):(bottomLeft&&bottomRight&&topLeft&&topRight);},determineQuadrant:function(lonlat){var quadrant="";var center=this.getCenterLonLat();quadrant+=(lonlat.lat=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-width,0);}
var newLeft=newBounds.left+leftTolerance;if(newLeftmaxExtent.left&&newBounds.right-rightTolerance>maxExtent.right){newBounds=newBounds.add(-width,0);}}
return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str,reverseAxisOrder){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds,reverseAxisOrder);};OpenLayers.Bounds.fromArray=function(bbox,reverseAxisOrder){return reverseAxisOrder===true?new OpenLayers.Bounds(bbox[1],bbox[0],bbox[3],bbox[2]):new OpenLayers.Bounds(bbox[0],bbox[1],bbox[2],bbox[3]);};OpenLayers.Bounds.fromSize=function(size){return new OpenLayers.Bounds(0,size.h,size.w,0);};OpenLayers.Bounds.oppositeQuadrant=function(quadrant){var opp="";opp+=(quadrant.charAt(0)=='t')?'b':'t';opp+=(quadrant.charAt(1)=='l')?'r':'l';return opp;};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){if(OpenLayers.Util.isArray(lon)){lat=lon[1];lon=lon[0];}
this.lon=OpenLayers.Util.toFloat(lon);this.lat=OpenLayers.Util.toFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){throw new TypeError('LonLat.add cannot receive null values');}
return new OpenLayers.LonLat(this.lon+OpenLayers.Util.toFloat(lon),this.lat+OpenLayers.Util.toFloat(lat));},equals:function(ll){var equals=false;if(ll!=null){equals=((this.lon==ll.lon&&this.lat==ll.lat)||(isNaN(this.lon)&&isNaN(this.lat)&&isNaN(ll.lon)&&isNaN(ll.lat)));}
return equals;},transform:function(source,dest){var point=OpenLayers.Projection.transform({'x':this.lon,'y':this.lat},source,dest);this.lon=point.x;this.lat=point.y;return this;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lonmaxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(pair[0],pair[1]);};OpenLayers.LonLat.fromArray=function(arr){var gotArr=OpenLayers.Util.isArray(arr),lon=gotArr&&arr[0],lat=gotArr&&arr[1];return new OpenLayers.LonLat(lon,lat);};OpenLayers.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0,len=arguments.length;i=0;i--){if(array[i]==item){array.splice(i,1);}}
return array;};OpenLayers.Util.indexOf=function(array,obj){if(typeof array.indexOf=="function"){return array.indexOf(obj);}else{for(var i=0,len=array.length;i=0.0&&parseFloat(opacity)<1.0){element.style.filter='alpha(opacity='+(opacity*100)+')';element.style.opacity=opacity;}else if(parseFloat(opacity)==1.0){element.style.filter='';element.style.opacity='';}};OpenLayers.Util.createDiv=function(id,px,sz,imgURL,position,border,overflow,opacity){var dom=document.createElement('div');if(imgURL){dom.style.backgroundImage='url('+imgURL+')';}
if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
if(!position){position="absolute";}
OpenLayers.Util.modifyDOMElement(dom,id,px,sz,position,border,overflow,opacity);return dom;};OpenLayers.Util.createImage=function(id,px,sz,imgURL,position,border,opacity,delayDisplay){var image=document.createElement("img");if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
if(!position){position="relative";}
OpenLayers.Util.modifyDOMElement(image,id,px,sz,position,border,null,opacity);if(delayDisplay){image.style.display="none";function display(){image.style.display="";OpenLayers.Event.stopObservingElement(image);}
OpenLayers.Event.observe(image,"load",display);OpenLayers.Event.observe(image,"error",display);}
image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
return image;};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=!!(document.body.filters);}catch(e){}
OpenLayers.Util.alphaHackNeeded=(filter&&(version>=5.5)&&(version<7));}
return OpenLayers.Util.alphaHackNeeded;};OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz,position,null,null,opacity);var img=div.childNodes[0];if(imgURL){img.src=imgURL;}
OpenLayers.Util.modifyDOMElement(img,div.id+"_innerImage",null,sz,"relative",border);if(OpenLayers.Util.alphaHack()){if(div.style.display!="none"){div.style.display="inline-block";}
if(sizing==null){sizing="scale";}
div.style.filter="progid:DXImageTransform.Microsoft"+".AlphaImageLoader(src='"+img.src+"', "+"sizingMethod='"+sizing+"')";if(parseFloat(div.style.opacity)>=0.0&&parseFloat(div.style.opacity)<1.0){div.style.filter+=" alpha(opacity="+div.style.opacity*100+")";}
img.style.filter="alpha(opacity=0)";}};OpenLayers.Util.createAlphaImageDiv=function(id,px,sz,imgURL,position,border,sizing,opacity,delayDisplay){var div=OpenLayers.Util.createDiv();var img=OpenLayers.Util.createImage(null,null,null,null,null,null,null,delayDisplay);img.className="olAlphaImg";div.appendChild(img);OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};OpenLayers.Util.upperCaseObject=function(object){var uObject={};for(var key in object){uObject[key.toUpperCase()]=object[key];}
return uObject;};OpenLayers.Util.applyDefaults=function(to,from){to=to||{};var fromIsEvt=typeof window.Event=="function"&&from instanceof window.Event;for(var key in from){if(to[key]===undefined||(!fromIsEvt&&from.hasOwnProperty&&from.hasOwnProperty(key)&&!to.hasOwnProperty(key))){to[key]=from[key];}}
if(!fromIsEvt&&from&&from.hasOwnProperty&&from.hasOwnProperty('toString')&&!to.hasOwnProperty('toString')){to.toString=from.toString;}
return to;};OpenLayers.Util.getParameterString=function(params){var paramsArray=[];for(var key in params){var value=params[key];if((value!=null)&&(typeof value!='function')){var encodedValue;if(typeof value=='object'&&value.constructor==Array){var encodedItemArray=[];var item;for(var itemIndex=0,len=value.length;itemIndex1e-12&&--iterLimit>0){var sinLambda=Math.sin(lambda),cosLambda=Math.cos(lambda);var sinSigma=Math.sqrt((cosU2*sinLambda)*(cosU2*sinLambda)+
(cosU1*sinU2-sinU1*cosU2*cosLambda)*(cosU1*sinU2-sinU1*cosU2*cosLambda));if(sinSigma==0){return 0;}
var cosSigma=sinU1*sinU2+cosU1*cosU2*cosLambda;var sigma=Math.atan2(sinSigma,cosSigma);var alpha=Math.asin(cosU1*cosU2*sinLambda/sinSigma);var cosSqAlpha=Math.cos(alpha)*Math.cos(alpha);var cos2SigmaM=cosSigma-2*sinU1*sinU2/cosSqAlpha;var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));lambdaP=lambda;lambda=L+(1-C)*f*Math.sin(alpha)*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));}
if(iterLimit==0){return NaN;}
var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));var s=b*A*(sigma-deltaSigma);var d=s.toFixed(3)/1000;return d;};OpenLayers.Util.destinationVincenty=function(lonlat,brng,dist){var u=OpenLayers.Util;var ct=u.VincentyConstants;var a=ct.a,b=ct.b,f=ct.f;var lon1=lonlat.lon;var lat1=lonlat.lat;var s=dist;var alpha1=u.rad(brng);var sinAlpha1=Math.sin(alpha1);var cosAlpha1=Math.cos(alpha1);var tanU1=(1-f)*Math.tan(u.rad(lat1));var cosU1=1/Math.sqrt((1+tanU1*tanU1)),sinU1=tanU1*cosU1;var sigma1=Math.atan2(tanU1,cosAlpha1);var sinAlpha=cosU1*sinAlpha1;var cosSqAlpha=1-sinAlpha*sinAlpha;var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var sigma=s/(b*A),sigmaP=2*Math.PI;while(Math.abs(sigma-sigmaP)>1e-12){var cos2SigmaM=Math.cos(2*sigma1+sigma);var sinSigma=Math.sin(sigma);var cosSigma=Math.cos(sigma);var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));sigmaP=sigma;sigma=s/(b*A)+deltaSigma;}
var tmp=sinU1*sinSigma-cosU1*cosSigma*cosAlpha1;var lat2=Math.atan2(sinU1*cosSigma+cosU1*sinSigma*cosAlpha1,(1-f)*Math.sqrt(sinAlpha*sinAlpha+tmp*tmp));var lambda=Math.atan2(sinSigma*sinAlpha1,cosU1*cosSigma-sinU1*sinSigma*cosAlpha1);var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));var L=lambda-(1-C)*f*sinAlpha*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));var revAz=Math.atan2(sinAlpha,-tmp);return new OpenLayers.LonLat(lon1+u.deg(L),u.deg(lat2));};OpenLayers.Util.getParameters=function(url,options){options=options||{};url=(url===null||url===undefined)?window.location.href:url;var paramsString="";if(OpenLayers.String.contains(url,'?')){var start=url.indexOf('?')+1;var end=OpenLayers.String.contains(url,"#")?url.indexOf('#'):url.length;paramsString=url.substring(start,end);}
var parameters={};var pairs=paramsString.split(/[&;]/);for(var i=0,len=pairs.length;i1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){var resolution;if(scale){if(units==null){units="degrees";}
var normScale=OpenLayers.Util.normalizeScale(scale);resolution=1/(normScale*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH);}
return resolution;};OpenLayers.Util.getScaleFromResolution=function(resolution,units){if(units==null){units="degrees";}
var scale=resolution*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH;return scale;};OpenLayers.Util.pagePosition=function(forElement){var pos=[0,0];var viewportElement=OpenLayers.Util.getViewportElement();if(!forElement||forElement==window||forElement==viewportElement){return pos;}
var BUGGY_GECKO_BOX_OBJECT=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(forElement,'position')=='absolute'&&(forElement.style.top==''||forElement.style.left=='');var parent=null;var box;if(forElement.getBoundingClientRect){box=forElement.getBoundingClientRect();var scrollTop=window.pageYOffset||viewportElement.scrollTop;var scrollLeft=window.pageXOffset||viewportElement.scrollLeft;pos[0]=box.left+scrollLeft;pos[1]=box.top+scrollTop;}else if(document.getBoxObjectFor&&!BUGGY_GECKO_BOX_OBJECT){box=document.getBoxObjectFor(forElement);var vpBox=document.getBoxObjectFor(viewportElement);pos[0]=box.screenX-vpBox.screenX;pos[1]=box.screenY-vpBox.screenY;}else{pos[0]=forElement.offsetLeft;pos[1]=forElement.offsetTop;parent=forElement.offsetParent;if(parent!=forElement){while(parent){pos[0]+=parent.offsetLeft;pos[1]+=parent.offsetTop;parent=parent.offsetParent;}}
var browser=OpenLayers.BROWSER_NAME;if(browser=="opera"||(browser=="safari"&&OpenLayers.Element.getStyle(forElement,'position')=='absolute')){pos[1]-=document.body.offsetTop;}
parent=forElement.offsetParent;while(parent&&parent!=document.body){pos[0]-=parent.scrollLeft;if(browser!="opera"||parent.tagName!='TR'){pos[1]-=parent.scrollTop;}
parent=parent.offsetParent;}}
return pos;};OpenLayers.Util.getViewportElement=function(){var viewportElement=arguments.callee.viewportElement;if(viewportElement==undefined){viewportElement=(OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!='CSS1Compat')?document.body:document.documentElement;arguments.callee.viewportElement=viewportElement;}
return viewportElement;};OpenLayers.Util.isEquivalentUrl=function(url1,url2,options){options=options||{};OpenLayers.Util.applyDefaults(options,{ignoreCase:true,ignorePort80:true,ignoreHash:true,splitArgs:false});var urlObj1=OpenLayers.Util.createUrlObject(url1,options);var urlObj2=OpenLayers.Util.createUrlObject(url2,options);for(var key in urlObj1){if(key!=="args"){if(urlObj1[key]!=urlObj2[key]){return false;}}}
for(var key in urlObj1.args){if(urlObj1.args[key]!=urlObj2.args[key]){return false;}
delete urlObj2.args[key];}
for(var key in urlObj2.args){return false;}
return true;};OpenLayers.Util.createUrlObject=function(url,options){options=options||{};if(!(/^\w+:\/\//).test(url)){var loc=window.location;var port=loc.port?":"+loc.port:"";var fullUrl=loc.protocol+"//"+loc.host.split(":").shift()+port;if(url.indexOf("/")===0){url=fullUrl+url;}else{var parts=loc.pathname.split("/");parts.pop();url=fullUrl+parts.join("/")+"/"+url;}}
if(options.ignoreCase){url=url.toLowerCase();}
var a=document.createElement('a');a.href=url;var urlObject={};urlObject.host=a.host.split(":").shift();urlObject.protocol=a.protocol;if(options.ignorePort80){urlObject.port=(a.port=="80"||a.port=="0")?"":a.port;}else{urlObject.port=(a.port==""||a.port=="0")?"80":a.port;}
urlObject.hash=(options.ignoreHash||a.hash==="#")?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
urlObject.args=OpenLayers.Util.getParameters(queryString,{splitArgs:options.splitArgs});urlObject.pathname=(a.pathname.charAt(0)=="/")?a.pathname:"/"+a.pathname;return urlObject;};OpenLayers.Util.removeTail=function(url){var head=null;var qMark=url.indexOf("?");var hashMark=url.indexOf("#");if(qMark==-1){head=(hashMark!=-1)?url.substr(0,hashMark):url;}else{head=(hashMark!=-1)?url.substr(0,Math.min(qMark,hashMark)):url.substr(0,qMark);}
return head;};OpenLayers.IS_GECKO=(function(){var ua=navigator.userAgent.toLowerCase();return ua.indexOf("webkit")==-1&&ua.indexOf("gecko")!=-1;})();OpenLayers.CANVAS_SUPPORTED=(function(){var elem=document.createElement('canvas');return!!(elem.getContext&&elem.getContext('2d'));})();OpenLayers.BROWSER_NAME=(function(){var name="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){name="opera";}else if(ua.indexOf("msie")!=-1){name="msie";}else if(ua.indexOf("safari")!=-1){name="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){name="firefox";}else{name="mozilla";}}
return name;})();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME;};OpenLayers.Util.getRenderedDimensions=function(contentHTML,size,options){var w,h;var container=document.createElement("div");container.style.visibility="hidden";var containerElement=(options&&options.containerElement)?options.containerElement:document.body;var parentHasPositionAbsolute=false;var superContainer=null;var parent=containerElement;while(parent&&parent.tagName.toLowerCase()!="body"){var parentPosition=OpenLayers.Element.getStyle(parent,"position");if(parentPosition=="absolute"){parentHasPositionAbsolute=true;break;}else if(parentPosition&&parentPosition!="static"){break;}
parent=parent.parentNode;}
if(parentHasPositionAbsolute&&(containerElement.clientHeight===0||containerElement.clientWidth===0)){superContainer=document.createElement("div");superContainer.style.visibility="hidden";superContainer.style.position="absolute";superContainer.style.overflow="visible";superContainer.style.width=document.body.clientWidth+"px";superContainer.style.height=document.body.clientHeight+"px";superContainer.appendChild(container);}
container.style.position="absolute";if(size){if(size.w){w=size.w;container.style.width=w+"px";}else if(size.h){h=size.h;container.style.height=h+"px";}}
if(options&&options.displayClass){container.className=options.displayClass;}
var content=document.createElement("div");content.innerHTML=contentHTML;content.style.overflow="visible";if(content.childNodes){for(var i=0,l=content.childNodes.length;i=60){coordinateseconds-=60;coordinateminutes+=1;if(coordinateminutes>=60){coordinateminutes-=60;coordinatedegrees+=1;}}
if(coordinatedegrees<10){coordinatedegrees="0"+coordinatedegrees;}
var str=coordinatedegrees+"\u00B0";if(dmsOption.indexOf('dm')>=0){if(coordinateminutes<10){coordinateminutes="0"+coordinateminutes;}
str+=coordinateminutes+"'";if(dmsOption.indexOf('dms')>=0){if(coordinateseconds<10){coordinateseconds="0"+coordinateseconds;}
str+=coordinateseconds+'"';}}
if(axis=="lon"){str+=coordinate<0?OpenLayers.i18n("W"):OpenLayers.i18n("E");}else{str+=coordinate<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");}
return str;};OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){if(!OpenLayers.Lang.code){OpenLayers.Lang.setCode();}
return OpenLayers.Lang.code;},setCode:function(code){var lang;if(!code){code=(OpenLayers.BROWSER_NAME=="msie")?navigator.userLanguage:navigator.language;}
var parts=code.split('-');parts[0]=parts[0].toLowerCase();if(typeof OpenLayers.Lang[parts[0]]=="object"){lang=parts[0];}
if(parts[1]){var testLang=parts[0]+'-'+parts[1].toUpperCase();if(typeof OpenLayers.Lang[testLang]=="object"){lang=testLang;}}
if(!lang){OpenLayers.Console.warn('Failed to find OpenLayers.Lang.'+parts.join("-")+' dictionary, falling back to default language');lang=OpenLayers.Lang.defaultCode;}
OpenLayers.Lang.code=lang;},translate:function(key,context){var dictionary=OpenLayers.Lang[OpenLayers.Lang.getCode()];var message=dictionary&&dictionary[key];if(!message){message=key;}
if(context){message=OpenLayers.String.format(message,context);}
return message;}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:false,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;},destroy:function(){},read:function(data){throw new Error('Read not implemented.');},write:function(object){throw new Error('Write not implemented.');},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(options){if(window.ActiveXObject){this.xmldom=new ActiveXObject("Microsoft.XMLDOM");}
OpenLayers.Format.prototype.initialize.apply(this,[options]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var alias in this.namespaces){this.namespaceAlias[this.namespaces[alias]]=alias;}},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,arguments);},setNamespace:function(alias,uri){this.namespaces[alias]=uri;this.namespaceAlias[uri]=alias;},read:function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
var node=OpenLayers.Util.Try(OpenLayers.Function.bind((function(){var xmldom;if(window.ActiveXObject&&!this.xmldom){xmldom=new ActiveXObject("Microsoft.XMLDOM");}else{xmldom=this.xmldom;}
xmldom.loadXML(text);return xmldom;}),this),function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
req.send(null);return req.responseXML;});if(this.keepData){this.data=node;}
return node;},write:function(node){var data;if(this.xmldom){data=node.xml;}else{var serializer=new XMLSerializer();if(node.nodeType==1){var doc=document.implementation.createDocument("","",null);if(doc.importNode){node=doc.importNode(node,true);}
doc.appendChild(node);data=serializer.serializeToString(doc);}else{data=serializer.serializeToString(node);}}
return data;},createElementNS:function(uri,name){var element;if(this.xmldom){if(typeof uri=="string"){element=this.xmldom.createNode(1,name,uri);}else{element=this.xmldom.createNode(1,name,"");}}else{element=document.createElementNS(uri,name);}
return element;},createDocumentFragment:function(){var element;if(this.xmldom){element=this.xmldom.createDocumentFragment();}else{element=document.createDocumentFragment();}
return element;},createTextNode:function(text){var node;if(typeof text!=="string"){text=String(text);}
if(this.xmldom){node=this.xmldom.createTextNode(text);}else{node=document.createTextNode(text);}
return node;},getElementsByTagNameNS:function(node,uri,name){var elements=[];if(node.getElementsByTagNameNS){elements=node.getElementsByTagNameNS(uri,name);}else{var allNodes=node.getElementsByTagName("*");var potentialNode,fullName;for(var i=0,len=allNodes.length;i0){prefix=name.substring(0,split);local=name.substring(split+1);}else{if(parent){prefix=this.namespaceAlias[parent.namespaceURI];}else{prefix=this.defaultPrefix;}
local=name;}
var child=this.writers[prefix][local].apply(this,[obj]);if(parent){parent.appendChild(child);}
return child;},getChildEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.firstChild,name,uri);},getNextEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.nextSibling,name,uri);},getThisOrNextEl:function(node,name,uri){outer:for(var sibling=node;sibling;sibling=sibling.nextSibling){switch(sibling.nodeType){case 1:if((!name||name===(sibling.localName||sibling.nodeName.split(":").pop()))&&(!uri||uri===sibling.namespaceURI)){break outer;}
sibling=null;break outer;case 3:if(/^\s*$/.test(sibling.nodeValue)){break;}
case 4:case 6:case 12:case 10:case 11:sibling=null;break outer;}}
return sibling||null;},lookupNamespaceURI:function(node,prefix){var uri=null;if(node){if(node.lookupNamespaceURI){uri=node.lookupNamespaceURI(prefix);}else{outer:switch(node.nodeType){case 1:if(node.namespaceURI!==null&&node.prefix===prefix){uri=node.namespaceURI;break outer;}
var len=node.attributes.length;if(len){var attr;for(var i=0;i=1){matrixSet=contents.tileMatrixSets[layerDef.tileMatrixSetLinks[0].tileMatrixSet];}
if(!matrixSet){throw new Error("matrixSet not found");}
var style;for(var i=0,ii=layerDef.styles.length;i0?duration:Number.POSITIVE_INFINITY;var id=++counter;var start=+new Date;loops[id]=function(){if(loops[id]&&+new Date-start<=duration){callback();if(loops[id]){requestFrame(loops[id],element);}}else{delete loops[id];}};requestFrame(loops[id],element);return id;}
function stop(id){delete loops[id];}
return{isNative:isNative,requestFrame:requestFrame,start:start,stop:stop};})(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,minFrameRate:null,startTime:null,animationId:null,playing:false,initialize:function(easing){this.easing=(easing)?easing:OpenLayers.Easing.Expo.easeOut;},start:function(begin,finish,duration,options){this.playing=true;this.begin=begin;this.finish=finish;this.duration=duration;this.callbacks=options.callbacks;this.minFrameRate=options.minFrameRate||30;this.time=0;this.startTime=new Date().getTime();OpenLayers.Animation.stop(this.animationId);this.animationId=null;if(this.callbacks&&this.callbacks.start){this.callbacks.start.call(this,this.begin);}
this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play,this));},stop:function(){if(!this.playing){return;}
if(this.callbacks&&this.callbacks.done){this.callbacks.done.call(this,this.finish);}
OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.playing=false;},play:function(){var value={};for(var i in this.begin){var b=this.begin[i];var f=this.finish[i];if(b==null||f==null||isNaN(b)||isNaN(f)){throw new TypeError('invalid value for Tween');}
var c=f-b;value[i]=this.easing.apply(this,[this.time,b,c,this.duration]);}
this.time++;if(this.callbacks&&this.callbacks.eachStep){if((new Date().getTime()-this.startTime)/this.time<=1000/this.minFrameRate){this.callbacks.eachStep.call(this,value);}}
if(this.time>this.duration){this.stop();}},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(t,b,c,d){return c*t/d+b;},easeOut:function(t,b,c,d){return c*t/d+b;},easeInOut:function(t,b,c,d){return c*t/d+b;},CLASS_NAME:"OpenLayers.Easing.Linear"};OpenLayers.Easing.Expo={easeIn:function(t,b,c,d){return(t==0)?b:c*Math.pow(2,10*(t/d-1))+b;},easeOut:function(t,b,c,d){return(t==d)?b+c:c*(-Math.pow(2,-10*t/d)+1)+b;},easeInOut:function(t,b,c,d){if(t==0)return b;if(t==d)return b+c;if((t/=d/2)<1)return c/2*Math.pow(2,10*(t-1))+b;return c/2*(-Math.pow(2,-10*--t)+2)+b;},CLASS_NAME:"OpenLayers.Easing.Expo"};OpenLayers.Easing.Quad={easeIn:function(t,b,c,d){return c*(t/=d)*t+b;},easeOut:function(t,b,c,d){return-c*(t/=d)*(t-2)+b;},easeInOut:function(t,b,c,d){if((t/=d/2)<1)return c/2*t*t+b;return-c/2*((--t)*(t-2)-1)+b;},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:false,displayClass:"",title:"",autoActivate:false,active:null,handlerOptions:null,handler:null,eventListeners:null,events:null,initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}},destroy:function(){if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
this.events.destroy();this.events=null;}
this.eventListeners=null;if(this.handler){this.handler.destroy();this.handler=null;}
if(this.handlers){for(var key in this.handlers){if(this.handlers.hasOwnProperty(key)&&typeof this.handlers[key].destroy=="function"){this.handlers[key].destroy();}}
this.handlers=null;}
if(this.map){this.map.removeControl(this);this.map=null;}
this.div=null;},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv(this.id);this.div.className=this.displayClass;if(!this.allowSelection){this.div.className+=" olControlNoSelect";this.div.setAttribute("unselectable","on",0);this.div.onselectstart=OpenLayers.Function.False;}
if(this.title!=""){this.div.title=this.title;}}
if(px!=null){this.position=px.clone();}
this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
if(this.handler){this.handler.activate();}
this.active=true;if(this.map){OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");}
this.events.triggerEvent("activate");return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
this.active=false;if(this.map){OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");}
this.events.triggerEvent("deactivate");return true;}
return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Event={observers:false,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isSingleTouch:function(event){return event.touches&&event.touches.length==1;},isMultiTouch:function(event){return event.touches&&event.touches.length>1;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},isRightClick:function(event){return(((event.which)&&(event.which==3))||((event.button)&&(event.button==2)));},stop:function(event,allowDefault){if(!allowDefault){OpenLayers.Event.preventDefault(event);}
if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},preventDefault:function(event){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}},findElement:function(event,tagName){var element=OpenLayers.Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase()))){element=element.parentNode;}
return element;},observe:function(elementParam,name,observer,useCapture){var element=OpenLayers.Util.getElement(elementParam);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent)){name='keydown';}
if(!this.observers){this.observers={};}
if(!element._eventCacheID){var idPrefix="eventCacheID_";if(element.id){idPrefix=element.id+"_"+idPrefix;}
element._eventCacheID=OpenLayers.Util.createUniqueID(idPrefix);}
var cacheID=element._eventCacheID;if(!this.observers[cacheID]){this.observers[cacheID]=[];}
this.observers[cacheID].push({'element':element,'name':name,'observer':observer,'useCapture':useCapture});if(element.addEventListener){element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){element.attachEvent('on'+name,observer);}},stopObservingElement:function(elementParam){var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[cacheID]);},_removeElementObservers:function(elementObservers){if(elementObservers){for(var i=elementObservers.length-1;i>=0;i--){var entry=elementObservers[i];OpenLayers.Event.stopObserving.apply(this,[entry.element,entry.name,entry.observer,entry.useCapture]);}}},stopObserving:function(elementParam,name,observer,useCapture){useCapture=useCapture||false;var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;if(name=='keypress'){if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent){name='keydown';}}
var foundEntry=false;var elementObservers=OpenLayers.Event.observers[cacheID];if(elementObservers){var i=0;while(!foundEntry&&iMath.floor(evt.pageY)||evt.pageX===0&&Math.floor(x)>Math.floor(evt.pageX)){x=x-winPageX;y=y-winPageY;}else if(y<(evt.pageY-winPageY)||x<(evt.pageX-winPageX)){x=evt.pageX-winPageX;y=evt.pageY-winPageY;}
evt.olClientX=x;evt.olClientY=y;return{clientX:x,clientY:y};},clearMouseCache:function(){this.element.scrolls=null;this.element.lefttop=null;this.element.offsets=null;},getMousePosition:function(evt){if(!this.includeXY){this.clearMouseCache();}else if(!this.element.hasScrollEvent){OpenLayers.Event.observe(window,"scroll",this.clearMouseListener);this.element.hasScrollEvent=true;}
if(!this.element.scrolls){var viewportElement=OpenLayers.Util.getViewportElement();this.element.scrolls=[window.pageXOffset||viewportElement.scrollLeft,window.pageYOffset||viewportElement.scrollTop];}
if(!this.element.lefttop){this.element.lefttop=[(document.documentElement.clientLeft||0),(document.documentElement.clientTop||0)];}
if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);}
return new OpenLayers.Pixel((evt.clientX+this.element.scrolls[0])-this.element.offsets[0]
-this.element.lefttop[0],(evt.clientY+this.element.scrolls[1])-this.element.offsets[1]
-this.element.lefttop[1]);},addMsTouchListener:function(element,type,handler){var eventHandler=this.eventHandler;var touches=this._msTouches;function msHandler(evt){handler(OpenLayers.Util.applyDefaults({stopPropagation:function(){for(var i=touches.length-1;i>=0;--i){touches[i].stopPropagation();}},preventDefault:function(){for(var i=touches.length-1;i>=0;--i){touches[i].preventDefault();}},type:type},evt));}
switch(type){case'touchstart':return this.addMsTouchListenerStart(element,type,msHandler);case'touchend':return this.addMsTouchListenerEnd(element,type,msHandler);case'touchmove':return this.addMsTouchListenerMove(element,type,msHandler);default:throw'Unknown touch event type';}},addMsTouchListenerStart:function(element,type,handler){var touches=this._msTouches;var cb=function(e){var alreadyInArray=false;for(var i=0,ii=touches.length;i=this.down.xy.distanceTo(evt.xy);if(passes&&this.touch&&this.down.touches.length===this.last.touches.length){for(var i=0,ii=this.down.touches.length;ithis.pixelTolerance){passes=false;break;}}}}
return passes;},getTouchDistance:function(from,to){return Math.sqrt(Math.pow(from.clientX-to.clientX,2)+
Math.pow(from.clientY-to.clientY,2));},passesDblclickTolerance:function(evt){var passes=true;if(this.down&&this.first){passes=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance;}
return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}
if(this.rightclickTimerId!=null){window.clearTimeout(this.rightclickTimerId);this.rightclickTimerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback("click",[evt]);}},getEventInfo:function(evt){var touches;if(evt.touches){var len=evt.touches.length;touches=new Array(len);var touch;for(var i=0;i0){var infoLookup={};var layer,idx;for(var i=0,len=layers.length;i=0;--i){layer=candidates[i];if(OpenLayers.Layer.UTFGrid&&layer instanceof OpenLayers.Layer.UTFGrid||OpenLayers.Layer.WMTSUTFGrid&&layer instanceof OpenLayers.Layer.WMTSUTFGrid){layers.push(layer);}}
return layers;},CLASS_NAME:"OpenLayers.Control.UTFGrid"});OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(typeof Proj4js=="object"){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},toString:function(){return this.getCode();},equals:function(projection){var p=projection,equals=false;if(p){if(!(p instanceof OpenLayers.Projection)){p=new OpenLayers.Projection(p);}
if((typeof Proj4js=="object")&&this.proj.defData&&p.proj.defData){equals=this.proj.defData.replace(this.titleRegEx,"")==p.proj.defData.replace(this.titleRegEx,"");}else if(p.getCode){var source=this.getCode(),target=p.getCode();equals=source==target||!!OpenLayers.Projection.transforms[source]&&OpenLayers.Projection.transforms[source][target]===OpenLayers.Projection.nullTransform;}}
return equals;},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:true},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-20037508.34,-20037508.34,20037508.34,20037508.34]}};OpenLayers.Projection.addTransform=function(from,to,method){if(method===OpenLayers.Projection.nullTransform){var defaults=OpenLayers.Projection.defaults[from];if(defaults&&!OpenLayers.Projection.defaults[to]){OpenLayers.Projection.defaults[to]=defaults;}}
if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};}
OpenLayers.Projection.transforms[from][to]=method;};OpenLayers.Projection.transform=function(point,source,dest){if(source&&dest){if(!(source instanceof OpenLayers.Projection)){source=new OpenLayers.Projection(source);}
if(!(dest instanceof OpenLayers.Projection)){dest=new OpenLayers.Projection(dest);}
if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}else{var sourceCode=source.getCode();var destCode=dest.getCode();var transforms=OpenLayers.Projection.transforms;if(transforms[sourceCode]&&transforms[sourceCode][destCode]){transforms[sourceCode][destCode](point);}}}
return point;};OpenLayers.Projection.nullTransform=function(point){return point;};(function(){var pole=20037508.34;function inverseMercator(xy){xy.x=180*xy.x/pole;xy.y=180/Math.PI*(2*Math.atan(Math.exp((xy.y/pole)*Math.PI))-Math.PI/2);return xy;}
function forwardMercator(xy){xy.x=xy.x*pole/180;var y=Math.log(Math.tan((90+xy.y)*Math.PI/360))/Math.PI*pole;xy.y=Math.max(-20037508.34,Math.min(y,20037508.34));return xy;}
function map(base,codes){var add=OpenLayers.Projection.addTransform;var same=OpenLayers.Projection.nullTransform;var i,len,code,other,j;for(i=0,len=codes.length;i=0;--i){map(mercator[i],geographic);}
for(i=geographic.length-1;i>=0;--i){map(geographic[i],mercator);}})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1000},id:null,fractionalZoom:false,events:null,allOverlays:false,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,tileManager:null,fallThrough:false,autoUpdateSize:true,eventListeners:null,panTween:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,zoomTween:null,zoomMethod:OpenLayers.Easing.Quad.easeOut,zoomDuration:20,paddingForPopups:null,layerContainerOriginPx:null,minPx:null,maxPx:null,initialize:function(div,options){if(arguments.length===1&&typeof div==="object"){options=div;div=options&&options.div;}
this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';this.options=OpenLayers.Util.extend({},options);OpenLayers.Util.extend(this,options);var projCode=this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection;OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[projCode]);if(this.maxExtent&&!(this.maxExtent instanceof OpenLayers.Bounds)){this.maxExtent=new OpenLayers.Bounds(this.maxExtent);}
if(this.minExtent&&!(this.minExtent instanceof OpenLayers.Bounds)){this.minExtent=new OpenLayers.Bounds(this.minExtent);}
if(this.restrictedExtent&&!(this.restrictedExtent instanceof OpenLayers.Bounds)){this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent);}
if(this.center&&!(this.center instanceof OpenLayers.LonLat)){this.center=new OpenLayers.LonLat(this.center);}
this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);if(!this.div){this.div=document.createElement("div");this.div.style.height="1px";this.div.style.width="1px";}
OpenLayers.Element.addClass(this.div,'olMap');var id=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:true});if(this.tileManager){this.tileManager.addMap(this);}
id=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.layerContainerOriginPx={x:0,y:0};this.applyTransform();this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
if(this.autoUpdateSize===true){this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,'resize',this.updateSizeDestroy);}
if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0,len=nodes.length;i=0;--i){this.controls[i].destroy();}
this.controls=null;}
if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);}
this.layers=null;}
if(this.viewPortDiv&&this.viewPortDiv.parentNode){this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);}
this.viewPortDiv=null;if(this.tileManager){this.tileManager.removeMap(this);this.tileManager=null;}
if(this.eventListeners){this.events.un(this.eventListeners);this.eventListeners=null;}
this.events.destroy();this.events=null;this.options=null;},setOptions:function(options){var updatePxExtent=this.minPx&&options.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,options);updatePxExtent&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:true});},getTileSize:function(){return this.tileSize;},getBy:function(array,property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this[array],function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getLayersBy:function(property,match){return this.getBy("layers",property,match);},getLayersByName:function(match){return this.getLayersBy("name",match);},getLayersByClass:function(match){return this.getLayersBy("CLASS_NAME",match);},getControlsBy:function(property,match){return this.getBy("controls",property,match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},getLayer:function(id){var foundLayer=null;for(var i=0,len=this.layers.length;ithis.layers.length){idx=this.layers.length;}
if(base!=idx){this.layers.splice(base,1);this.layers.splice(idx,0,layer);for(var i=0,len=this.layers.length;i=0;--i){this.removePopup(this.popups[i]);}}
popup.map=this;this.popups.push(popup);var popupDiv=popup.draw();if(popupDiv){popupDiv.style.zIndex=this.Z_INDEX_BASE['Popup']+
this.popups.length;this.layerContainerDiv.appendChild(popupDiv);}},removePopup:function(popup){OpenLayers.Util.removeItem(this.popups,popup);if(popup.div){try{this.layerContainerDiv.removeChild(popup.div);}
catch(e){}}
popup.map=null;},getSize:function(){var size=null;if(this.size!=null){size=this.size.clone();}
return size;},updateSize:function(){var newSize=this.getCurrentSize();if(newSize&&!isNaN(newSize.h)&&!isNaN(newSize.w)){this.events.clearMouseCache();var oldSize=this.getSize();if(oldSize==null){this.size=oldSize=newSize;}
if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0,len=this.layers.length;i=this.minPx.x+xRestriction?Math.round(dx):0;dy=y<=this.maxPx.y-yRestriction&&y>=this.minPx.y+yRestriction?Math.round(dy):0;if(dx||dy){if(!this.dragging){this.dragging=true;this.events.triggerEvent("movestart");}
this.center=null;if(dx){this.layerContainerOriginPx.x-=dx;this.minPx.x-=dx;this.maxPx.x-=dx;}
if(dy){this.layerContainerOriginPx.y-=dy;this.minPx.y-=dy;this.maxPx.y-=dy;}
this.applyTransform();var layer,i,len;for(i=0,len=this.layers.length;imaxResolution){if(this.fractionalZoom){zoom=this.getZoomForResolution(maxResolution);}else{for(var i=zoom|0,ii=resolutions.length;ithis.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.leftthis.restrictedExtent.right){lonlat=lonlat.add(this.restrictedExtent.right-
extent.right,0);}
if(extent.getHeight()>this.restrictedExtent.getHeight()){lonlat=new OpenLayers.LonLat(lonlat.lon,maxCenter.lat);}else if(extent.bottomthis.restrictedExtent.top){lonlat=lonlat.add(0,this.restrictedExtent.top-
extent.top);}}}
var zoomChanged=forceZoomChange||((this.isValidZoomLevel(zoom))&&(zoom!=this.getZoom()));var centerChanged=(this.isValidLonLat(lonlat))&&(!lonlat.equals(this.center));if(zoomChanged||centerChanged||dragging){dragging||this.events.triggerEvent("movestart",{zoomChanged:zoomChanged});if(centerChanged){if(!zoomChanged&&this.center){this.centerLayerContainer(lonlat);}
this.center=lonlat.clone();}
var res=zoomChanged?this.getResolutionForZoom(zoom):this.getResolution();if(zoomChanged||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;this.applyTransform();var maxExtent=this.getMaxExtent({restricted:true});var maxExtentCenter=maxExtent.getCenterLonLat();var lonDelta=this.center.lon-maxExtentCenter.lon;var latDelta=maxExtentCenter.lat-this.center.lat;var extentWidth=Math.round(maxExtent.getWidth()/res);var extentHeight=Math.round(maxExtent.getHeight()/res);this.minPx={x:(this.size.w-extentWidth)/2-lonDelta/res,y:(this.size.h-extentHeight)/2-latDelta/res};this.maxPx={x:this.minPx.x+Math.round(maxExtent.getWidth()/res),y:this.minPx.y+Math.round(maxExtent.getHeight()/res)};}
if(zoomChanged){this.zoom=zoom;this.resolution=res;}
var bounds=this.getExtent();if(this.baseLayer.visibility){this.baseLayer.moveTo(bounds,zoomChanged,options.dragging);options.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:zoomChanged});}
bounds=this.baseLayer.getExtent();for(var i=this.layers.length-1;i>=0;--i){var layer=this.layers[i];if(layer!==this.baseLayer&&!layer.isBaseLayer){var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;if(!inRange){layer.display(false);}}
if(inRange&&layer.visibility){layer.moveTo(bounds,zoomChanged,options.dragging);options.dragging||layer.events.triggerEvent("moveend",{zoomChanged:zoomChanged});}}}
this.events.triggerEvent("move");dragging||this.events.triggerEvent("moveend");if(zoomChanged){for(var i=0,len=this.popups.length;i=0)&&(zoomLevel0){resolution=this.layers[0].getResolution();}
return resolution;},getUnits:function(){var units=null;if(this.baseLayer!=null){units=this.baseLayer.units;}
return units;},getScale:function(){var scale=null;if(this.baseLayer!=null){var res=this.getResolution();var units=this.baseLayer.units;scale=OpenLayers.Util.getScaleFromResolution(res,units);}
return scale;},getZoomForExtent:function(bounds,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds,closest);}
return zoom;},getResolutionForZoom:function(zoom){var resolution=null;if(this.baseLayer){resolution=this.baseLayer.getResolutionForZoom(zoom);}
return resolution;},getZoomForResolution:function(resolution,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution,closest);}
return zoom;},zoomTo:function(zoom,xy){var map=this;if(map.isValidZoomLevel(zoom)){if(map.baseLayer.wrapDateLine){zoom=map.adjustZoom(zoom);}
if(map.zoomTween){var currentRes=map.getResolution(),targetRes=map.getResolutionForZoom(zoom),start={scale:1},end={scale:currentRes/targetRes};if(map.zoomTween.playing&&map.zoomTween.duration<3*map.zoomDuration){map.zoomTween.finish={scale:map.zoomTween.finish.scale*end.scale};}else{if(!xy){var size=map.getSize();xy={x:size.w/2,y:size.h/2};}
map.zoomTween.start(start,end,map.zoomDuration,{minFrameRate:50,callbacks:{eachStep:function(data){var containerOrigin=map.layerContainerOriginPx,scale=data.scale,dx=((scale-1)*(containerOrigin.x-xy.x))|0,dy=((scale-1)*(containerOrigin.y-xy.y))|0;map.applyTransform(containerOrigin.x+dx,containerOrigin.y+dy,scale);},done:function(data){map.applyTransform();var resolution=map.getResolution()/data.scale,zoom=map.getZoomForResolution(resolution,true)
map.moveTo(map.getZoomTargetCenter(xy,resolution),zoom,true);}}});}}else{var center=xy?map.getZoomTargetCenter(xy,map.getResolutionForZoom(zoom)):null;map.setCenter(center,zoom);}}},zoomIn:function(){this.zoomTo(this.getZoom()+1);},zoomOut:function(){this.zoomTo(this.getZoom()-1);},zoomToExtent:function(bounds,closest){if(!(bounds instanceof OpenLayers.Bounds)){bounds=new OpenLayers.Bounds(bounds);}
var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right=0){this.initResolutions();if(reinitialize&&this.map.baseLayer===this){this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(resolution),false,true);this.map.events.triggerEvent("changebaselayer",{layer:this});}
break;}}}},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){var zoomChanged=true;this.moveTo(extent,zoomChanged,false);this.events.triggerEvent("moveend",{"zoomChanged":zoomChanged});redrawn=true;}}
return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
this.display(display);},moveByPx:function(dx,dy){},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent=this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);}
this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer){this.inRange=this.calculateInRange();var show=((this.visibility)&&(this.inRange));this.div.style.display=show?"":"none";}
this.setTileSize();}},afterAdd:function(){},removeMap:function(map){},getImageSize:function(bounds){return(this.imageSize||this.tileSize);},setTileSize:function(size){var tileSize=(size)?size:((this.tileSize)?this.tileSize:this.map.getTileSize());this.tileSize=tileSize;if(this.gutter){this.imageSize=new OpenLayers.Size(tileSize.w+(2*this.gutter),tileSize.h+(2*this.gutter));}},getVisibility:function(){return this.visibility;},setVisibility:function(visibility){if(visibility!=this.visibility){this.visibility=visibility;this.display(visibility);this.redraw();this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display&&this.calculateInRange())?"block":"none";if(this.map){this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});}}},calculateInRange:function(){var inRange=false;if(this.alwaysInRange){inRange=true;}else{if(this.map){var resolution=this.map.getResolution();inRange=((resolution>=this.minResolution)&&(resolution<=this.maxResolution));}}
return inRange;},setIsBaseLayer:function(isBaseLayer){if(isBaseLayer!=this.isBaseLayer){this.isBaseLayer=isBaseLayer;if(this.map!=null){this.map.events.triggerEvent("changebaselayer",{layer:this});}}},initResolutions:function(){var i,len,p;var props={},alwaysInRange=true;for(i=0,len=this.RESOLUTION_PROPERTIES.length;i=resolution){highRes=res;lowZoom=i;}
if(res<=resolution){lowRes=res;highZoom=i;break;}}
var dRes=highRes-lowRes;if(dRes>0){zoom=lowZoom+((highRes-resolution)/dRes);}else{zoom=lowZoom;}}else{var diff;var minDiff=Number.POSITIVE_INFINITY;for(i=0,len=this.resolutions.length;iminDiff){break;}
minDiff=diff;}else{if(this.resolutions[i]=0&&row=0;i--){newResolution=this.serverResolutions[i];newDistance=Math.abs(newResolution-resolution);if(newDistance>distance){break;}
distance=newDistance;serverResolution=newResolution;}
resolution=serverResolution;}
return resolution;},getServerZoom:function(){var resolution=this.getServerResolution();return this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,resolution):this.map.getZoomForResolution(resolution)+(this.zoomOffset||0);},applyBackBuffer:function(resolution){if(this.backBufferTimerId!==null){this.removeBackBuffer();}
var backBuffer=this.backBuffer;if(!backBuffer){backBuffer=this.createBackBuffer();if(!backBuffer){return;}
if(resolution===this.gridResolution){this.div.insertBefore(backBuffer,this.div.firstChild);}else{this.map.baseLayer.div.parentNode.insertBefore(backBuffer,this.map.baseLayer.div);}
this.backBuffer=backBuffer;var topLeftTileBounds=this.grid[0][0].bounds;this.backBufferLonLat={lon:topLeftTileBounds.left,lat:topLeftTileBounds.top};this.backBufferResolution=this.gridResolution;}
var ratio=this.backBufferResolution/resolution;var tiles=backBuffer.childNodes,tile;for(var i=tiles.length-1;i>=0;--i){tile=tiles[i];tile.style.top=((ratio*tile._i*tile._h)|0)+'px';tile.style.left=((ratio*tile._j*tile._w)|0)+'px';tile.style.width=Math.round(ratio*tile._w)+'px';tile.style.height=Math.round(ratio*tile._h)+'px';}
var position=this.getViewPortPxFromLonLat(this.backBufferLonLat,resolution);var leftOffset=this.map.layerContainerOriginPx.x;var topOffset=this.map.layerContainerOriginPx.y;backBuffer.style.left=Math.round(position.x-leftOffset)+'px';backBuffer.style.top=Math.round(position.y-topOffset)+'px';},createBackBuffer:function(){var backBuffer;if(this.grid.length>0){backBuffer=document.createElement('div');backBuffer.id=this.div.id+'_bb';backBuffer.className='olBackBuffer';backBuffer.style.position='absolute';var map=this.map;backBuffer.style.zIndex=this.transitionEffect==='resize'?this.getZIndex()-1:map.Z_INDEX_BASE.BaseLayer-
(map.getNumLayers()-map.getLayerIndex(this));for(var i=0,lenI=this.grid.length;i=0;--i){OpenLayers.Event.stopObserving(this._transitionElement,this.transitionendEvents[i],this._removeBackBuffer);}
delete this._transitionElement;}
if(this.backBuffer){if(this.backBuffer.parentNode){this.backBuffer.parentNode.removeChild(this.backBuffer);}
this.backBuffer=null;this.backBufferResolution=null;if(this.backBufferTimerId!==null){window.clearTimeout(this.backBufferTimerId);this.backBufferTimerId=null;}}},moveByPx:function(dx,dy){if(!this.singleTile){this.moveGriddedTiles();}},setTileSize:function(size){if(this.singleTile){size=this.map.getSize();size.h=parseInt(size.h*this.ratio,10);size.w=parseInt(size.w*this.ratio,10);}
OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getTilesBounds:function(){var bounds=null;var length=this.grid.length;if(length){var bottomLeftTileBounds=this.grid[length-1][0].bounds,width=this.grid[0].length*bottomLeftTileBounds.getWidth(),height=this.grid.length*bottomLeftTileBounds.getHeight();bounds=new OpenLayers.Bounds(bottomLeftTileBounds.left,bottomLeftTileBounds.bottom,bottomLeftTileBounds.left+width,bottomLeftTileBounds.bottom+height);}
return bounds;},initSingleTile:function(bounds){this.events.triggerEvent("retile");var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var px=this.map.getLayerPxFromLonLat({lon:tileBounds.left,lat:tileBounds.top});if(!this.grid.length){this.grid[0]=[];}
var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
this.removeExcessTiles(1,1);this.gridResolution=this.getServerResolution();},calculateGridLayout:function(bounds,origin,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-origin.lon;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var rowSign=this.rowSign;var offsetlat=rowSign*(origin.lat-bounds.top+tilelat);var tilerow=Math[~rowSign?'floor':'ceil'](offsetlat/tilelat)-this.buffer*rowSign;return{tilelon:tilelon,tilelat:tilelat,startcol:tilecol,startrow:tilerow};},getTileOrigin:function(){var origin=this.tileOrigin;if(!origin){var extent=this.getMaxExtent();var edges=({"tl":["left","top"],"tr":["right","top"],"bl":["left","bottom"],"br":["right","bottom"]})[this.tileOriginCorner];origin=new OpenLayers.LonLat(extent[edges[0]],extent[edges[1]]);}
return origin;},getTileBoundsForGridIndex:function(row,col){var origin=this.getTileOrigin();var tileLayout=this.gridLayout;var tilelon=tileLayout.tilelon;var tilelat=tileLayout.tilelat;var startcol=tileLayout.startcol;var startrow=tileLayout.startrow;var rowSign=this.rowSign;return new OpenLayers.Bounds(origin.lon+(startcol+col)*tilelon,origin.lat-(startrow+row*rowSign)*tilelat*rowSign,origin.lon+(startcol+col+1)*tilelon,origin.lat-(startrow+(row-1)*rowSign)*tilelat*rowSign);},initGriddedTiles:function(bounds){this.events.triggerEvent("retile");var viewSize=this.map.getSize();var origin=this.getTileOrigin();var resolution=this.map.getResolution(),serverResolution=this.getServerResolution(),ratio=resolution/serverResolution,tileSize={w:this.tileSize.w/ratio,h:this.tileSize.h/ratio};var minRows=Math.ceil(viewSize.h/tileSize.h)+
2*this.buffer+1;var minCols=Math.ceil(viewSize.w/tileSize.w)+
2*this.buffer+1;var tileLayout=this.calculateGridLayout(bounds,origin,serverResolution);this.gridLayout=tileLayout;var tilelon=tileLayout.tilelon;var tilelat=tileLayout.tilelat;var layerContainerDivLeft=this.map.layerContainerOriginPx.x;var layerContainerDivTop=this.map.layerContainerOriginPx.y;var tileBounds=this.getTileBoundsForGridIndex(0,0);var startPx=this.map.getViewPortPxFromLonLat(new OpenLayers.LonLat(tileBounds.left,tileBounds.top));startPx.x=Math.round(startPx.x)-layerContainerDivLeft;startPx.y=Math.round(startPx.y)-layerContainerDivTop;var tileData=[],center=this.map.getCenter();var rowidx=0;do{var row=this.grid[rowidx];if(!row){row=[];this.grid.push(row);}
var colidx=0;do{tileBounds=this.getTileBoundsForGridIndex(rowidx,colidx);var px=startPx.clone();px.x=px.x+colidx*Math.round(tileSize.w);px.y=px.y+rowidx*Math.round(tileSize.h);var tile=row[colidx];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
var tileCenter=tileBounds.getCenterLonLat();tileData.push({tile:tile,distance:Math.pow(tileCenter.lon-center.lon,2)+
Math.pow(tileCenter.lat-center.lat,2)});colidx+=1;}while((tileBounds.right<=bounds.right+tilelon*this.buffer)||colidx=bounds.bottom-tilelat*this.buffer)||rowidx=0;--i){OpenLayers.Event.observe(this._transitionElement,transitionendEvents[i],this._removeBackBuffer);}
this.backBufferTimerId=window.setTimeout(this._removeBackBuffer,this.removeBackBufferDelay);}}
this.loading=false;this.events.triggerEvent("loadend");}};tile.onLoadError=function(){this.events.triggerEvent("tileerror",{tile:tile});};tile.events.on({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,"loaderror":tile.onLoadError,scope:this});},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,"loaderror":tile.onLoadError,scope:this});},moveGriddedTiles:function(){var buffer=this.buffer+1;while(true){var tlTile=this.grid[0][0];var tlViewPort={x:tlTile.position.x+
this.map.layerContainerOriginPx.x,y:tlTile.position.y+
this.map.layerContainerOriginPx.y};var ratio=this.getServerResolution()/this.map.getResolution();var tileSize={w:Math.round(this.tileSize.w*ratio),h:Math.round(this.tileSize.h*ratio)};if(tlViewPort.x>-tileSize.w*(buffer-1)){this.shiftColumn(true,tileSize);}else if(tlViewPort.x<-tileSize.w*buffer){this.shiftColumn(false,tileSize);}else if(tlViewPort.y>-tileSize.h*(buffer-1)){this.shiftRow(true,tileSize);}else if(tlViewPort.y<-tileSize.h*buffer){this.shiftRow(false,tileSize);}else{break;}}},shiftRow:function(prepend,tileSize){var grid=this.grid;var rowIndex=prepend?0:(grid.length-1);var sign=prepend?-1:1;var rowSign=this.rowSign;var tileLayout=this.gridLayout;tileLayout.startrow+=sign*rowSign;var modelRow=grid[rowIndex];var row=grid[prepend?'pop':'shift']();for(var i=0,len=row.length;irows){var row=this.grid.pop();for(i=0,l=row.length;icolumns){var row=this.grid[i];var tile=row.pop();this.destroyTile(tile);}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();}},getTileBounds:function(viewPortPx){var maxExtent=this.maxExtent;var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=maxExtent.left+(tileMapWidth*Math.floor((mapPoint.lon-
maxExtent.left)/tileMapWidth));var tileBottom=maxExtent.bottom+(tileMapHeight*Math.floor((mapPoint.lat-
maxExtent.bottom)/tileMapHeight));return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:" ",space:" ",newline:"\n",level:0,pretty:false,nativeJSON:(function(){return!!(window.JSON&&typeof JSON.parse=="function"&&typeof JSON.stringify=="function");})(),read:function(json,filter){var object;if(this.nativeJSON){object=JSON.parse(json,filter);}else try{if(/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){object=eval('('+json+')');if(typeof filter==='function'){function walk(k,v){if(v&&typeof v==='object'){for(var i in v){if(v.hasOwnProperty(i)){v[i]=walk(i,v[i]);}}}
return filter(k,v);}
object=walk('',object);}}}catch(e){}
if(this.keepData){this.data=object;}
return object;},write:function(value,pretty){this.pretty=!!pretty;var json=null;var type=typeof value;if(this.serialize[type]){try{json=(!this.pretty&&this.nativeJSON)?JSON.stringify(value):this.serialize[type].apply(this,[value]);}catch(err){OpenLayers.Console.error("Trouble serializing: "+err);}}
return json;},writeIndent:function(){var pieces=[];if(this.pretty){for(var i=0;i0){pieces.push(',');}
pieces.push(this.writeNewline(),this.writeIndent(),json);}}
this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),']');return pieces.join('');},'string':function(string){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};if(/["\\\x00-\x1f]/.test(string)){return'"'+string.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}
c=b.charCodeAt();return'\\u00'+
Math.floor(c/16).toString(16)+
(c%16).toString(16);})+'"';}
return'"'+string+'"';},'number':function(number){return isFinite(number)?String(number):"null";},'boolean':function(bool){return String(bool);},'date':function(date){function format(number){return(number<10)?'0'+number:number;}
return'"'+date.getFullYear()+'-'+
format(date.getMonth()+1)+'-'+
format(date.getDate())+'T'+
format(date.getHours())+':'+
format(date.getMinutes())+':'+
format(date.getSeconds())+'"';}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,stopDown:true,dragging:false,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:false,documentEvents:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(this.documentDrag===true){var me=this;this._docMove=function(evt){me.mousemove({xy:{x:evt.clientX,y:evt.clientY},element:document});};this._docUp=function(evt){me.mouseup({xy:{x:evt.clientX,y:evt.clientY}});};}},dragstart:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&(OpenLayers.Event.isLeftClick(evt)||OpenLayers.Event.isSingleTouch(evt))){this.started=true;this.start=evt.xy;this.last=evt.xy;OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown");this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.preventDefault(evt);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True;}
document.onselectstart=OpenLayers.Function.False;propagate=!this.stopDown;}else{this.started=false;this.start=null;this.last=null;}
return propagate;},dragmove:function(evt){this.lastMoveEvt=evt;if(this.started&&!this.timeoutId&&(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y)){if(this.documentDrag===true&&this.documentEvents){if(evt.element===document){this.adjustXY(evt);this.setEvent(evt);}else{this.removeDocumentEvents();}}
if(this.interval>0){this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);}
this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=OpenLayers.Function.False;}
this.last=evt.xy;}
return true;},dragend:function(evt){if(this.started){if(this.documentDrag===true&&this.documentEvents){this.adjustXY(evt);this.removeDocumentEvents();}
var dragged=(this.start!=this.last);this.started=false;this.dragging=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(evt);this.callback("up",[evt.xy]);if(dragged){this.callback("done",[evt.xy]);}
document.onselectstart=this.oldOnselectstart;}
return true;},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){return this.dragstart(evt);},touchstart:function(evt){this.startTouch();return this.dragstart(evt);},mousemove:function(evt){return this.dragmove(evt);},touchmove:function(evt){return this.dragmove(evt);},removeTimeout:function(){this.timeoutId=null;if(this.dragging){this.mousemove(this.lastMoveEvt);}},mouseup:function(evt){return this.dragend(evt);},touchend:function(evt){evt.xy=this.last;return this.dragend(evt);},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.viewPortDiv)){if(this.documentDrag===true){this.addDocumentEvents();}else{var dragged=(this.start!=this.last);this.started=false;this.dragging=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(evt);this.callback("out",[]);if(dragged){this.callback("done",[evt.xy]);}
if(document.onselectstart){document.onselectstart=this.oldOnselectstart;}}}
return true;},click:function(evt){return(this.start==this.last);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;activated=true;}
return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");}
return deactivated;},adjustXY:function(evt){var pos=OpenLayers.Util.pagePosition(this.map.viewPortDiv);evt.xy.x-=pos[0];evt.xy.y-=pos[1];},addDocumentEvents:function(){OpenLayers.Element.addClass(document.body,"olDragDown");this.documentEvents=true;OpenLayers.Event.observe(document,"mousemove",this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp);},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=false;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp);},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',boxOffsets:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.dragHandler=new OpenLayers.Handler.Drag(this,{down:this.startBox,move:this.moveBox,out:this.removeBox,up:this.endBox},{keyMask:this.keyMask});},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler=null;}},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv('zoomBox',{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox");},moveBox:function(xy){var startX=this.dragHandler.start.x;var startY=this.dragHandler.start.y;var deltaX=Math.abs(startX-xy.x);var deltaY=Math.abs(startY-xy.y);var offset=this.getBoxOffsets();this.zoomBox.style.width=(deltaX+offset.width+1)+"px";this.zoomBox.style.height=(deltaY+offset.height+1)+"px";this.zoomBox.style.left=(xy.x5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
this.removeBox();this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;this.boxOffsets=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox");},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){if(this.dragHandler.deactivate()){if(this.zoomBox){this.removeBox();}}
return true;}else{return false;}},getBoxOffsets:function(){if(!this.boxOffsets){var testDiv=document.createElement("div");testDiv.style.position="absolute";testDiv.style.border="1px solid black";testDiv.style.width="3px";document.body.appendChild(testDiv);var w3cBoxModel=testDiv.clientWidth==3;document.body.removeChild(testDiv);var left=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"));var right=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width"));var top=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width"));var bottom=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:left,right:right,top:top,bottom:bottom,width:w3cBoxModel===false?left+right:0,height:w3cBoxModel===false?top+bottom:0};}
return this.boxOffsets;},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,keyMask:null,alwaysZoom:false,zoomOnClick:true,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var bounds,targetCenterPx=position.getCenterPixel();if(!this.out){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);}else{var pixWidth=position.right-position.left;var pixHeight=position.bottom-position.top;var zoomFactor=Math.min((this.map.size.h/pixHeight),(this.map.size.w/pixWidth));var extent=this.map.getExtent();var center=this.map.getLonLatFromPixel(targetCenterPx);var xmin=center.lon-(extent.getWidth()/2)*zoomFactor;var xmax=center.lon+(extent.getWidth()/2)*zoomFactor;var ymin=center.lat-(extent.getHeight()/2)*zoomFactor;var ymax=center.lat+(extent.getHeight()/2)*zoomFactor;bounds=new OpenLayers.Bounds(xmin,ymin,xmax,ymax);}
var lastZoom=this.map.getZoom(),size=this.map.getSize(),centerPx={x:size.w/2,y:size.h/2},zoom=this.map.getZoomForExtent(bounds),oldRes=this.map.getResolution(),newRes=this.map.getResolutionForZoom(zoom),zoomOriginPx={x:(oldRes*targetCenterPx.x-newRes*centerPx.x)/(oldRes-newRes),y:(oldRes*targetCenterPx.y-newRes*centerPx.y)/(oldRes-newRes)};this.map.zoomTo(zoom,zoomOriginPx);if(lastZoom==this.map.getZoom()&&this.alwaysZoom==true){this.map.zoomTo(lastZoom+(this.out?-1:1));}}else if(this.zoomOnClick){if(!this.out){this.map.zoomTo(this.map.getZoom()+1,position);}else{this.map.zoomTo(this.map.getZoom()-1,position);}}},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:1,documentDrag:false,kinetic:null,enableKinetic:true,kineticInterval:10,draw:function(){if(this.enableKinetic&&OpenLayers.Kinetic){var config={interval:this.kineticInterval};if(typeof this.enableKinetic==="object"){config=OpenLayers.Util.extend(config,this.enableKinetic);}
this.kinetic=new OpenLayers.Kinetic(config);}
this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone,"down":this.panMapStart},{interval:this.interval,documentDrag:this.documentDrag});},panMapStart:function(){if(this.kinetic){this.kinetic.begin();}},panMap:function(xy){if(this.kinetic){this.kinetic.update(xy);}
this.panned=true;this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:true,animate:false});},panMapDone:function(xy){if(this.panned){var res=null;if(this.kinetic){res=this.kinetic.end(xy);}
this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:!!res,animate:false});if(res){var self=this;this.kinetic.move(res,function(x,y,end){self.map.pan(x,y,{dragging:!end,animate:false});});}
this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,interval:0,maxDelta:Number.POSITIVE_INFINITY,delta:0,cumulative:true,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this);},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null;},onWheelEvent:function(e){if(!this.map||!this.checkModifiers(e)){return;}
var overScrollableDiv=false;var allowScroll=false;var overMapDiv=false;var elem=OpenLayers.Event.element(e);while((elem!=null)&&!overMapDiv&&!overScrollableDiv){if(!overScrollableDiv){try{var overflow;if(elem.currentStyle){overflow=elem.currentStyle["overflow"];}else{var style=document.defaultView.getComputedStyle(elem,null);overflow=style.getPropertyValue("overflow");}
overScrollableDiv=(overflow&&(overflow=="auto")||(overflow=="scroll"));}catch(err){}}
if(!allowScroll){allowScroll=OpenLayers.Element.hasClass(elem,'olScrollable');if(!allowScroll){for(var i=0,len=this.map.layers.length;i=0;--i){this.target.register(this.events[i],this,this.buttonClick,{extension:true});}},destroy:function(){for(var i=this.events.length-1;i>=0;--i){this.target.unregister(this.events[i],this,this.buttonClick);}
delete this.target;},getPressedButton:function(element){var depth=3,button;do{if(OpenLayers.Element.hasClass(element,"olButton")){button=element;break;}
element=element.parentNode;}while(--depth>0&&element);return button;},ignore:function(element){var depth=3,ignore=false;do{if(element.nodeName.toLowerCase()==='a'){ignore=true;break;}
element=element.parentNode;}while(--depth>0&&element);return ignore;},buttonClick:function(evt){var propagate=true,element=OpenLayers.Event.element(evt);if(element&&(OpenLayers.Event.isLeftClick(evt)||!~evt.type.indexOf("mouse"))){var button=this.getPressedButton(element);if(button){if(evt.type==="keydown"){switch(evt.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",{buttonElement:button});OpenLayers.Event.stop(evt);propagate=false;break;}}else if(this.startEvt){if(this.completeRegEx.test(evt.type)){var pos=OpenLayers.Util.pagePosition(button);var viewportElement=OpenLayers.Util.getViewportElement();var scrollTop=window.pageYOffset||viewportElement.scrollTop;var scrollLeft=window.pageXOffset||viewportElement.scrollLeft;pos[0]=pos[0]-scrollLeft;pos[1]=pos[1]-scrollTop;this.target.triggerEvent("buttonclick",{buttonElement:button,buttonXY:{x:this.startEvt.clientX-pos[0],y:this.startEvt.clientY-pos[1]}});}
if(this.cancelRegEx.test(evt.type)){delete this.startEvt;}
OpenLayers.Event.stop(evt);propagate=false;}
if(this.startRegEx.test(evt.type)){this.startEvt=evt;OpenLayers.Event.stop(evt);propagate=false;}}else{propagate=!this.ignore(OpenLayers.Event.element(evt));delete this.startEvt;}}
return propagate;}});OpenLayers.Layer.WMTS=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,version:"1.0.0",requestEncoding:"KVP",url:null,layer:null,matrixSet:null,style:null,format:"image/jpeg",tileOrigin:null,tileFullExtent:null,formatSuffix:null,matrixIds:null,dimensions:null,params:null,zoomOffset:0,serverResolutions:null,formatSuffixMap:{"image/png":"png","image/png8":"png","image/png24":"png","image/png32":"png","png":"png","image/jpeg":"jpg","image/jpg":"jpg","jpeg":"jpg","jpg":"jpg"},matrix:null,initialize:function(config){var required={url:true,layer:true,style:true,matrixSet:true};for(var prop in required){if(!(prop in config)){throw new Error("Missing property '"+prop+"' in layer configuration.");}}
config.params=OpenLayers.Util.upperCaseObject(config.params);var args=[config.name,config.url,config.params,config];OpenLayers.Layer.Grid.prototype.initialize.apply(this,args);if(!this.formatSuffix){this.formatSuffix=this.formatSuffixMap[this.format]||this.format.split("/").pop();}
if(this.matrixIds){var len=this.matrixIds.length;if(len&&typeof this.matrixIds[0]==="string"){var ids=this.matrixIds;this.matrixIds=new Array(len);for(var i=0;i=0;--i){dimension=dimensions[i];context[dimension]=params[dimension.toUpperCase()];}}
url=OpenLayers.String.format(template,context);}else{var path=this.version+"/"+this.layer+"/"+this.style+"/";if(dimensions){for(var i=0;i4)
this._object.open(sMethod,sUrl,bAsync,sUser,sPassword);else
if(arguments.length>3)
this._object.open(sMethod,sUrl,bAsync,sUser);else
this._object.open(sMethod,sUrl,bAsync);this.readyState=cXMLHttpRequest.OPENED;fReadyStateChange(this);this._object.onreadystatechange=function(){if(bGecko&&!bAsync)
return;oRequest.readyState=oRequest._object.readyState;fSynchronizeValues(oRequest);if(oRequest._aborted){oRequest.readyState=cXMLHttpRequest.UNSENT;return;}
if(oRequest.readyState==cXMLHttpRequest.DONE){delete oRequest._data;fCleanTransport(oRequest);if(bIE&&bAsync)
window.detachEvent("onunload",fOnUnload);}
if(nState!=oRequest.readyState)
fReadyStateChange(oRequest);nState=oRequest.readyState;}};function fXMLHttpRequest_send(oRequest){oRequest._object.send(oRequest._data);if(bGecko&&!oRequest._async){oRequest.readyState=cXMLHttpRequest.OPENED;fSynchronizeValues(oRequest);while(oRequest.readyStatecXMLHttpRequest.UNSENT)
this._aborted=true;this._object.abort();fCleanTransport(this);this.readyState=cXMLHttpRequest.UNSENT;delete this._data;};cXMLHttpRequest.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders();};cXMLHttpRequest.prototype.getResponseHeader=function(sName){return this._object.getResponseHeader(sName);};cXMLHttpRequest.prototype.setRequestHeader=function(sName,sValue){if(!this._headers)
this._headers={};this._headers[sName]=sValue;return this._object.setRequestHeader(sName,sValue);};cXMLHttpRequest.prototype.addEventListener=function(sName,fHandler,bUseCapture){for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
if(oListener[0]==sName&&oListener[1]==fHandler&&oListener[2]==bUseCapture)
return;this._listeners.push([sName,fHandler,bUseCapture]);};cXMLHttpRequest.prototype.removeEventListener=function(sName,fHandler,bUseCapture){for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
if(oListener[0]==sName&&oListener[1]==fHandler&&oListener[2]==bUseCapture)
break;if(oListener)
this._listeners.splice(nIndex,1);};cXMLHttpRequest.prototype.dispatchEvent=function(oEvent){var oEventPseudo={'type':oEvent.type,'target':this,'currentTarget':this,'eventPhase':2,'bubbles':oEvent.bubbles,'cancelable':oEvent.cancelable,'timeStamp':oEvent.timeStamp,'stopPropagation':function(){},'preventDefault':function(){},'initEvent':function(){}};if(oEventPseudo.type=="readystatechange"&&this.onreadystatechange)
(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[oEventPseudo]);for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
if(oListener[0]==oEventPseudo.type&&!oListener[2])
(oListener[1].handleEvent||oListener[1]).apply(this,[oEventPseudo]);};cXMLHttpRequest.prototype.toString=function(){return'['+"object"+' '+"XMLHttpRequest"+']';};cXMLHttpRequest.toString=function(){return'['+"XMLHttpRequest"+']';};function fReadyStateChange(oRequest){if(cXMLHttpRequest.onreadystatechange)
cXMLHttpRequest.onreadystatechange.apply(oRequest);oRequest.dispatchEvent({'type':"readystatechange",'bubbles':false,'cancelable':false,'timeStamp':new Date+0});};function fGetDocument(oRequest){var oDocument=oRequest.responseXML,sResponse=oRequest.responseText;if(bIE&&sResponse&&oDocument&&!oDocument.documentElement&&oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)){oDocument=new window.ActiveXObject("Microsoft.XMLDOM");oDocument.async=false;oDocument.validateOnParse=false;oDocument.loadXML(sResponse);}
if(oDocument)
if((bIE&&oDocument.parseError!=0)||!oDocument.documentElement||(oDocument.documentElement&&oDocument.documentElement.tagName=="parsererror"))
return null;return oDocument;};function fSynchronizeValues(oRequest){try{oRequest.responseText=oRequest._object.responseText;}catch(e){}
try{oRequest.responseXML=fGetDocument(oRequest._object);}catch(e){}
try{oRequest.status=oRequest._object.status;}catch(e){}
try{oRequest.statusText=oRequest._object.statusText;}catch(e){}};function fCleanTransport(oRequest){oRequest._object.onreadystatechange=new window.Function;};if(!window.Function.prototype.apply){window.Function.prototype.apply=function(oRequest,oArguments){if(!oArguments)
oArguments=[];oRequest.__func=this;oRequest.__func(oArguments[0],oArguments[1],oArguments[2],oArguments[3],oArguments[4]);delete oRequest.__func;};};if(!OpenLayers.Request){OpenLayers.Request={};}
OpenLayers.Request.XMLHttpRequest=cXMLHttpRequest;})();OpenLayers.ProxyHost="";if(!OpenLayers.Request){OpenLayers.Request={};}
OpenLayers.Util.extend(OpenLayers.Request,{DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:true,user:undefined,password:undefined,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(url,proxy){var sameOrigin=url.indexOf("http")!==0;var urlParts=!sameOrigin&&url.match(this.URL_SPLIT_REGEX);if(urlParts){var location=window.location;sameOrigin=urlParts[1]==location.protocol&&urlParts[3]==location.hostname;var uPort=urlParts[4],lPort=location.port;if(uPort!=80&&uPort!=""||lPort!="80"&&lPort!=""){sameOrigin=sameOrigin&&uPort==lPort;}}
if(!sameOrigin){if(proxy){if(typeof proxy=="function"){url=proxy(url);}else{url=proxy+encodeURIComponent(url);}}}
return url;},issue:function(config){var defaultConfig=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});config=config||{};config.headers=config.headers||{};config=OpenLayers.Util.applyDefaults(config,defaultConfig);config.headers=OpenLayers.Util.applyDefaults(config.headers,defaultConfig.headers);var customRequestedWithHeader=false,headerKey;for(headerKey in config.headers){if(config.headers.hasOwnProperty(headerKey)){if(headerKey.toLowerCase()==='x-requested-with'){customRequestedWithHeader=true;}}}
if(customRequestedWithHeader===false){config.headers['X-Requested-With']='XMLHttpRequest';}
var request=new OpenLayers.Request.XMLHttpRequest();var url=OpenLayers.Util.urlAppend(config.url,OpenLayers.Util.getParameterString(config.params||{}));url=OpenLayers.Request.makeSameOrigin(url,config.proxy);request.open(config.method,url,config.async,config.user,config.password);for(var header in config.headers){request.setRequestHeader(header,config.headers[header]);}
var events=this.events;var self=this;request.onreadystatechange=function(){if(request.readyState==OpenLayers.Request.XMLHttpRequest.DONE){var proceed=events.triggerEvent("complete",{request:request,config:config,requestUrl:url});if(proceed!==false){self.runCallbacks({request:request,config:config,requestUrl:url});}}};if(config.async===false){request.send(config.data);}else{window.setTimeout(function(){if(request.readyState!==0){request.send(config.data);}},0);}
return request;},runCallbacks:function(options){var request=options.request;var config=options.config;var complete=(config.scope)?OpenLayers.Function.bind(config.callback,config.scope):config.callback;var success;if(config.success){success=(config.scope)?OpenLayers.Function.bind(config.success,config.scope):config.success;}
var failure;if(config.failure){failure=(config.scope)?OpenLayers.Function.bind(config.failure,config.scope):config.failure;}
if(OpenLayers.Util.createUrlObject(config.url).protocol=="file:"&&request.responseText){request.status=200;}
complete(request);if(!request.status||(request.status>=200&&request.status<300)){this.events.triggerEvent("success",options);if(success){success(request);}}
if(request.status&&(request.status<200||request.status>=300)){this.events.triggerEvent("failure",options);if(failure){failure(request);}}},GET:function(config){config=OpenLayers.Util.extend(config,{method:"GET"});return OpenLayers.Request.issue(config);},POST:function(config){config=OpenLayers.Util.extend(config,{method:"POST"});config.headers=config.headers?config.headers:{};if(!("CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(config.headers))){config.headers["Content-Type"]="application/xml";}
return OpenLayers.Request.issue(config);},PUT:function(config){config=OpenLayers.Util.extend(config,{method:"PUT"});config.headers=config.headers?config.headers:{};if(!("CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(config.headers))){config.headers["Content-Type"]="application/xml";}
return OpenLayers.Request.issue(config);},DELETE:function(config){config=OpenLayers.Util.extend(config,{method:"DELETE"});return OpenLayers.Request.issue(config);},HEAD:function(config){config=OpenLayers.Util.extend(config,{method:"HEAD"});return OpenLayers.Request.issue(config);},OPTIONS:function(config){config=OpenLayers.Util.extend(config,{method:"OPTIONS"});return OpenLayers.Request.issue(config);}});OpenLayers.Tile.UTFGrid=OpenLayers.Class(OpenLayers.Tile,{url:null,utfgridResolution:2,json:null,format:null,destroy:function(){this.clear();OpenLayers.Tile.prototype.destroy.apply(this,arguments);},draw:function(){var drawn=OpenLayers.Tile.prototype.draw.apply(this,arguments);if(drawn){if(this.isLoading){this.abortLoading();this.events.triggerEvent("reload");}else{this.isLoading=true;this.events.triggerEvent("loadstart");}
this.url=this.layer.getURL(this.bounds);if(this.layer.useJSONP){var ols=new OpenLayers.Protocol.Script({url:this.url,callback:function(response){this.isLoading=false;this.events.triggerEvent("loadend");this.json=response.data;},scope:this});ols.read();this.request=ols;}else{this.request=OpenLayers.Request.GET({url:this.url,callback:function(response){this.isLoading=false;this.events.triggerEvent("loadend");if(response.status===200){this.parseData(response.responseText);}},scope:this});}}else{this.unload();}
return drawn;},abortLoading:function(){if(this.request){this.request.abort();delete this.request;}
this.isLoading=false;},getFeatureInfo:function(i,j){var info=null;if(this.json){var id=this.getFeatureId(i,j);if(id!==null){info={id:id,data:this.json.data[id]};}}
return info;},getFeatureId:function(i,j){var id=null;if(this.json){var resolution=this.utfgridResolution;var row=Math.floor(j/resolution);var col=Math.floor(i/resolution);var charCode=this.json.grid[row].charCodeAt(col);var index=this.indexFromCharCode(charCode);var keys=this.json.keys;if(!isNaN(index)&&(index in keys)){id=keys[index];}}
return id;},indexFromCharCode:function(charCode){if(charCode>=93){charCode--;}
if(charCode>=35){charCode--;}
return charCode-32;},parseData:function(str){if(!this.format){this.format=new OpenLayers.Format.JSON();}
this.json=this.format.read(str);},clear:function(){this.json=null;},CLASS_NAME:"OpenLayers.Tile.UTFGrid"});OpenLayers.Layer.WMTSUTFGrid=OpenLayers.Class(OpenLayers.Layer.WMTS,{isBaseLayer:false,useJSONP:false,tileClass:OpenLayers.Tile.UTFGrid,initialize:function(options){OpenLayers.Layer.WMTS.prototype.initialize.apply(this,[options]);this.tileOptions=OpenLayers.Util.extend({utfgridResolution:this.utfgridResolution},this.tileOptions);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMTSUTFGrid(this.getOptions());}
obj=OpenLayers.Layer.WMTS.prototype.clone.apply(this,[obj]);return obj;},getFeatureInfo:function(location){var info=null;var tileInfo=this.getTileData(location);if(tileInfo.tile){info=tileInfo.tile.getFeatureInfo(tileInfo.i,tileInfo.j);}
return info;},getFeatureId:function(location){var id=null;var info=this.getTileData(location);if(info.tile){id=info.tile.getFeatureId(info.i,info.j);}
return id;},CLASS_NAME:"OpenLayers.Layer.WMTSUTFGrid"});OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{autoActivate:true,element:null,prefix:'',separator:', ',suffix:'',numDigits:5,granularity:10,emptyString:null,lastXy:null,displayProjection:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){this.map.events.register('mousemove',this,this.redraw);this.map.events.register('mouseout',this,this.reset);this.redraw();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.map.events.unregister('mousemove',this,this.redraw);this.map.events.unregister('mouseout',this,this.reset);this.element.innerHTML="";return true;}else{return false;}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element){this.div.left="";this.div.top="";this.element=this.div;}
return this.div;},redraw:function(evt){var lonLat;if(evt==null){this.reset();return;}else{if(this.lastXy==null||Math.abs(evt.xy.x-this.lastXy.x)>this.granularity||Math.abs(evt.xy.y-this.lastXy.y)>this.granularity)
{this.lastXy=evt.xy;return;}
lonLat=this.map.getLonLatFromPixel(evt.xy);if(!lonLat){return;}
if(this.displayProjection){lonLat.transform(this.map.getProjectionObject(),this.displayProjection);}
this.lastXy=evt.xy;}
var newHtml=this.formatOutput(lonLat);if(newHtml!=this.element.innerHTML){this.element.innerHTML=newHtml;}},reset:function(evt){if(this.emptyString!=null){this.element.innerHTML=this.emptyString;}},formatOutput:function(lonLat){var digits=parseInt(this.numDigits);var newHtml=this.prefix+
lonLat.lon.toFixed(digits)+
this.separator+
lonLat.lat.toFixed(digits)+
this.suffix;return newHtml;},CLASS_NAME:"OpenLayers.Control.MousePosition"});OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,getParameters:function(url){url=url||window.location.href;var parameters=OpenLayers.Util.getParameters(url);var index=url.indexOf('#');if(index>0){url='?'+url.substring(index+1,url.length);OpenLayers.Util.extend(parameters,OpenLayers.Util.getParameters(url));}
return parameters;},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0,len=this.map.controls.length;i