summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml18
-rw-r--r--Makefile.example3
-rw-r--r--chimere/actions.py61
-rw-r--r--chimere/admin.py219
-rw-r--r--chimere/feeds.py46
-rw-r--r--chimere/fixtures/initial_data.json26
-rw-r--r--chimere/forms.py189
-rw-r--r--chimere/locale/fr/LC_MESSAGES/django.po757
-rw-r--r--chimere/managers.py22
-rw-r--r--chimere/migrations/0015_auto__add_field_icon_offset_x__add_field_icon_offset_y.py302
-rw-r--r--chimere/migrations/0016_auto__add_field_icon_popup_offset_x__add_field_icon_popup_offset_y.py304
-rw-r--r--chimere/migrations/0017_auto__add_subcategoryuserlimit.py (renamed from chimere/migrations/0015_auto__add_subcategoryuserlimit.py)12
-rw-r--r--chimere/migrations/0018_auto__add_polygon.py397
-rw-r--r--chimere/migrations/0019_auto__chg_field_marker_name__chg_field_polygon_name__chg_field_route_n.py (renamed from chimere/migrations/0016_auto__chg_field_marker_name__chg_field_route_name.py)40
-rw-r--r--chimere/migrations/0020_auto__add_unique_tinyurl_parameters.py (renamed from chimere/migrations/0017_auto__add_unique_tinyurl_parameters.py)34
-rw-r--r--chimere/migrations/0021_auto__add_field_polygon_color__add_field_polygon_inner_color__add_fiel.py389
-rw-r--r--chimere/migrations/0022_auto__chg_field_polygon_color__chg_field_polygon_inner_color__chg_fiel.py383
-rw-r--r--chimere/migrations/0023_auto__add_field_area_allow_point_edition__add_field_area_allow_route_e.py386
-rw-r--r--chimere/migrations/0024_auto__add_field_picturefile_polygon__chg_field_picturefile_marker__add.py392
-rw-r--r--chimere/migrations/0025_auto__add_field_area_display_category_menu.py373
-rw-r--r--chimere/migrations/0026_auto__add_field_propertymodel_slug.py378
-rw-r--r--chimere/migrations/0027_auto__add_field_property_polygon__chg_field_property_marker.py381
-rw-r--r--chimere/migrations/0028_auto__add_field_area_extra_map_def.py376
-rw-r--r--chimere/migrations/0029_auto__add_field_layer_extra_js_code__chg_field_layer_layer_code.py383
-rw-r--r--chimere/migrations/0030_auto.py381
-rw-r--r--chimere/migrations/0031_auto__add_field_marker_weight__add_field_marker_normalised_weight__add.py433
-rw-r--r--chimere/migrations/0032_create_aggregate_polygon_view.py404
-rw-r--r--chimere/migrations/0033_auto__add_field_color_inner_code.py393
-rw-r--r--chimere/migrations/0034_auto__add_field_subcategory_min_zoom.py394
-rw-r--r--chimere/migrations/0035_auto__add_field_subcategory_simplify_tolerance.py395
-rw-r--r--chimere/models.py1178
-rw-r--r--chimere/route.py24
-rw-r--r--chimere/static/bsmSelect/MIT-LICENSE.txt4
-rw-r--r--chimere/static/bsmSelect/README.md22
-rw-r--r--chimere/static/bsmSelect/css/jquery.bsmselect.css8
-rw-r--r--chimere/static/bsmSelect/js/jquery.bsmselect.compatibility.js10
-rw-r--r--chimere/static/bsmSelect/js/jquery.bsmselect.js43
-rw-r--r--chimere/static/bsmSelect/js/jquery.bsmselect.sortable.js18
-rw-r--r--chimere/static/chimere/css/forms.css47
-rw-r--r--chimere/static/chimere/css/styles.css118
-rw-r--r--chimere/static/chimere/js/edit_area.js180
-rw-r--r--chimere/static/chimere/js/importer_interface.js2
-rw-r--r--chimere/static/chimere/js/jquery.chimere.js853
-rw-r--r--chimere/static/ol3/ol-debug.js107541
-rw-r--r--chimere/static/ol3/ol.css1
-rw-r--r--chimere/static/ol3/ol.js998
-rw-r--r--chimere/static/openlayers/OpenLayers.js1443
-rw-r--r--chimere/static/openlayers/OpenLayers.mobile.js1654
-rw-r--r--chimere/static/openlayers/SimplePanZoom.js366
-rw-r--r--chimere/templates/chimere/blocks/JQueryAutoComplete.html57
-rw-r--r--chimere/templates/chimere/blocks/head_chimere.html33
-rw-r--r--chimere/templates/chimere/blocks/head_form.html2
-rw-r--r--chimere/templates/chimere/blocks/head_jme.html3
-rw-r--r--chimere/templates/chimere/blocks/live_coordinates.html53
-rw-r--r--chimere/templates/chimere/blocks/map.html43
-rw-r--r--chimere/templates/chimere/blocks/ol_map.html7
-rw-r--r--chimere/templates/chimere/blocks/polygon_edit.html36
-rw-r--r--chimere/templates/chimere/category_item_detail.html2
-rw-r--r--chimere/templates/chimere/detail.html7
-rw-r--r--chimere/templates/chimere/edit.html36
-rw-r--r--chimere/templates/chimere/edit_polygon.html12
-rw-r--r--chimere/templates/chimere/main_map.html2
-rw-r--r--chimere/templatetags/chimere_tags.py210
-rw-r--r--chimere/templatetags/unescape.py26
-rw-r--r--chimere/urls.py102
-rw-r--r--chimere/utils.py116
-rw-r--r--chimere/views.py782
-rw-r--r--chimere/widgets.py551
-rw-r--r--chimere_example_project/.gitignore10
-rw-r--r--chimere_example_project/__init__.py0
-rw-r--r--chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.css9
-rw-r--r--chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.js6
-rw-r--r--chimere_example_project/chimere_example_static/chimere/css/extra-styles.css474
-rw-r--r--chimere_example_project/chimere_example_static/chimere/css/form-compat.css69
-rw-r--r--chimere_example_project/chimere_example_static/chimere/img/layer-switcher-maximize.pngbin0 -> 1433 bytes
-rw-r--r--chimere_example_project/chimere_example_static/chimere/img/logo.jpgbin0 -> 25981 bytes
-rwxr-xr-xchimere_example_project/chimere_example_static/chimere/img/minus.pngbin0 -> 236 bytes
-rwxr-xr-xchimere_example_project/chimere_example_static/chimere/img/plus.pngbin0 -> 528 bytes
-rw-r--r--chimere_example_project/chimere_example_static/chimere/js/interface.js73
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/LICENSE1
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.css1801
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.min.css4
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/fonts/FontAwesome.otfbin0 -> 93888 bytes
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.eotbin0 -> 60767 bytes
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.svg565
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.ttfbin0 -> 122092 bytes
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woffbin0 -> 71508 bytes
-rw-r--r--chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff2bin0 -> 56780 bytes
-rw-r--r--chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rw-r--r--chimere_example_project/fixtures/first_data.json853
-rw-r--r--chimere_example_project/local_settings.py.pip.sample42
-rw-r--r--chimere_example_project/local_settings.py.sample36
-rw-r--r--chimere_example_project/locale/fr/LC_MESSAGES/django.po165
-rwxr-xr-xchimere_example_project/manage.py17
-rw-r--r--chimere_example_project/project_static/.project_static0
-rw-r--r--chimere_example_project/settings.py352
-rw-r--r--chimere_example_project/templates/chimere/base.html41
-rw-r--r--chimere_example_project/templates/chimere/blocks/actions.html61
-rw-r--r--chimere_example_project/templates/chimere/blocks/categories.html32
-rw-r--r--chimere_example_project/templates/chimere/blocks/map.html122
-rw-r--r--chimere_example_project/templates/chimere/blocks/news.html62
-rw-r--r--chimere_example_project/templates/chimere/blocks/overload_templates_here0
-rw-r--r--chimere_example_project/templates/chimere/blocks/share_bar.html39
-rw-r--r--chimere_example_project/templates/chimere/blocks/welcome.html62
-rw-r--r--chimere_example_project/templates/chimere/detail.html150
-rw-r--r--chimere_example_project/templates/chimere/main_map.html54
-rw-r--r--chimere_example_project/templates/chimere/overload_templates_here0
-rw-r--r--chimere_example_project/templates/overload_templates_here0
-rw-r--r--chimere_example_project/urls.py44
-rw-r--r--chimere_example_project/wsgi.py11
113 files changed, 124993 insertions, 5252 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..a4d3a85
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,18 @@
+before_script:
+ - apt-get update
+ - apt-get install -q -y python-pip libpq-dev python-dev
+ - pip install -q -r requirements.txt
+ - cp Makefile.example Makefile
+
+variables:
+ POSTGRES_DB: morrigan
+ POSTGRES_USER: morrigan
+ POSTGRES_PASSWORD: "morrigan"
+
+services:
+ - postgres:9.1
+
+master:
+ script: "make test_gitlab"
+ only:
+ - master
diff --git a/Makefile.example b/Makefile.example
index e50bace..4ac65cb 100644
--- a/Makefile.example
+++ b/Makefile.example
@@ -16,6 +16,9 @@ clean:
test: clean
cd $(project); $(PYTHON) manage.py test chimere
+test_gitlab:
+ cd $(project); $(PYTHON) manage.py test chimere
+
pep8:
pep8 --filename=*.py --ignore=W --exclude="manage.py,settings.py,migrations" --statistics --repeat .
diff --git a/chimere/actions.py b/chimere/actions.py
index 8ce3e2a..ecbd07a 100644
--- a/chimere/actions.py
+++ b/chimere/actions.py
@@ -21,11 +21,11 @@
Actions available in the main interface
"""
from django.conf import settings
-from django.contrib.auth import models
from django.core.urlresolvers import reverse, NoReverseMatch
from django.utils.translation import ugettext_lazy as _
-from models import Page
+from models import Page, Area
+
class Action:
def __init__(self, id, path, label, extra_url_args=[]):
@@ -34,18 +34,24 @@ class Action:
def update_url(self, area_name):
try:
- self.url = reverse(self.path,
- args=[area_name if area_name else ''] + self.extra_url_args)
+ self.url = reverse(
+ self.path,
+ args=[area_name + '/' if area_name else '']
+ + self.extra_url_args)
except NoReverseMatch:
# backward url management
- self.url = reverse(self.path,
- args=[area_name + '/' if area_name else ''] + self.extra_url_args)
+ self.url = reverse(
+ self.path,
+ args=[area_name if area_name else ''] + self.extra_url_args)
-default_actions = [(Action('view', 'chimere:index', _('View')), []),
- (Action('contribute', 'chimere:edit', _('Contribute')),
- (Action('edit', 'chimere:edit', _('Add a new point of interest')),
- Action('edit-route', 'chimere:editroute', _('Add a new route'))),
- ),]
+default_actions = [
+ (Action('view', 'chimere:index', _('View')), []),
+ (Action('contribute', 'chimere:edit', _('Contribute')),
+ (Action('edit-marker', 'chimere:editmarker',
+ _('Add a new point of interest')),
+ Action('edit-route', 'chimere:editroute', _('Add a new route')),
+ Action('edit-polygon', 'chimere:editpolygon', _('Add a new polygon'))),
+ )]
if hasattr(settings, 'CHIMERE_DIRECTORY') and settings.CHIMERE_DIRECTORY:
default_actions.append((Action('categories', 'chimere:category-directory',
@@ -62,13 +68,38 @@ if settings.EMAIL_HOST:
def actions(area_name=''):
acts = default_actions[:]
- for act, childs in default_actions:
- act.update_url(area_name)
+ area, q = None, None
+ if area_name:
+ q = Area.objects.filter(urn=area_name)
+ if not q.count():
+ q = Area.objects.filter(name=area_name)
+ if not q or not q.count():
+ q = Area.objects.filter(default=True)
+ if q.count():
+ area = q.all()[0]
+
+ real_acts = []
+ for act, childs in acts:
+ real_childs = []
for child_act in childs:
+ if area:
+ if (child_act.id == 'edit-marker'
+ and not area.allow_point_edition) \
+ or (child_act.id == 'edit-route'
+ and not area.allow_route_edition) \
+ or (child_act.id == 'edit-polygon'
+ and not area.allow_polygon_edition):
+ continue
+ real_childs.append(child_act)
+ if childs and not real_childs:
+ continue
+ act.update_url(area_name)
+ for child_act in real_childs:
child_act.update_url(area_name)
+ real_acts.append((act, real_childs))
for page in Page.objects.filter(available=True).order_by('order'):
act = Action(page.mnemonic, 'chimere:extra_page', page.title,
[page.mnemonic])
act.update_url(area_name)
- acts.append((act, []))
- return acts
+ real_acts.append((act, []))
+ return real_acts
diff --git a/chimere/admin.py b/chimere/admin.py
index 66816bc..a30f0df 100644
--- a/chimere/admin.py
+++ b/chimere/admin.py
@@ -20,9 +20,13 @@
"""
Settings for administration pages
"""
+
+from copy import deepcopy
+
from django.conf import settings
from django.contrib import admin, messages
from django.contrib.admin import SimpleListFilter
+from django.contrib.admin.util import flatten_fieldsets
from django.contrib.auth.admin import UserAdmin as VanillaUserAdmin
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
@@ -37,17 +41,17 @@ except ImportError:
pass
from chimere.forms import MarkerAdminForm, RouteAdminForm, AreaAdminForm,\
- NewsAdminForm, CategoryAdminForm, ImporterAdminForm, OSMForm, \
- PageAdminForm, PictureFileAdminForm, MultimediaFileAdminForm
+ NewsAdminForm, CategoryAdminForm, ImporterAdminForm, OSMForm, \
+ PageAdminForm, PictureFileAdminForm, MultimediaFileAdminForm, \
+ PolygonAdminForm
from chimere import models
from chimere.models import Category, Icon, SubCategory, Marker, \
- PropertyModel, News, Route, Area, ColorTheme, Color, \
- MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\
- PropertyModelChoice, MultimediaExtension, Page,\
- get_areas_for_user, get_users_by_area, ImporterKeyCategories,\
- SubCategoryUserLimit
-from chimere.utils import unicode_normalize, ShapefileManager, KMLManager,\
- CSVManager
+ PropertyModel, News, Route, Area, ColorTheme, Color, \
+ MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\
+ PropertyModelChoice, Page, get_areas_for_user, \
+ ImporterKeyCategories, SubCategoryUserLimit
+from chimere.utils import ShapefileManager, KMLManager, CSVManager
+
def disable(modeladmin, request, queryset):
for item in queryset:
@@ -55,23 +59,26 @@ def disable(modeladmin, request, queryset):
item.save()
disable.short_description = _(u"Disable")
+
def validate(modeladmin, request, queryset):
for item in queryset:
item.status = 'A'
item.save()
validate.short_description = _(u"Validate")
+
def export_to_kml(modeladmin, request, queryset):
u"""
Export data to KML
"""
filename, result = KMLManager.export(queryset)
response = HttpResponse(result,
- mimetype='application/vnd.google-earth.kml+xml')
+ mimetype='application/vnd.google-earth.kml+xml')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
export_to_kml.short_description = _(u"Export to KML")
+
def export_to_shapefile(modeladmin, request, queryset):
u"""
Export data to Shapefile
@@ -86,6 +93,7 @@ def export_to_shapefile(modeladmin, request, queryset):
return response
export_to_shapefile.short_description = _(u"Export to Shapefile")
+
def export_to_csv(modeladmin, request, queryset):
u"""
Export data to CSV
@@ -96,6 +104,7 @@ def export_to_csv(modeladmin, request, queryset):
return response
export_to_csv.short_description = _(u"Export to CSV")
+
def managed_modified(modeladmin, request, queryset):
# not very clean... There is must be a better way to do that
redirect_url = request.get_full_path().split('admin_modification')[0]
@@ -108,8 +117,8 @@ def managed_modified(modeladmin, request, queryset):
item = queryset.all()[0]
if not item.ref_item or item.ref_item == item:
try:
- item = modeladmin.model.objects.filter(ref_item=item
- ).exclude(pk=item.pk).all()[0]
+ item = modeladmin.model.objects.filter(ref_item=item)\
+ .exclude(pk=item.pk).all()[0]
except IndexError:
messages.error(request, _(u"No modified item associated "
u"to the selected item."))
@@ -160,7 +169,7 @@ def managed_modified(modeladmin, request, queryset):
messages.success(request, _(u"Modified item traited."))
return HttpResponseRedirect(redirect_url)
return render_to_response('admin/chimere/managed_modified.html',
- {'item':item, 'item_ref':item_ref},
+ {'item': item, 'item_ref': item_ref},
context_instance=RequestContext(request))
managed_modified.short_description = _(u"Managed modified items")
@@ -218,6 +227,15 @@ class AreaRouteListFilter(AreaMarkerListFilter):
return queryset.filter(area.getIncludeRoute())
+class AreaPolygonListFilter(AreaMarkerListFilter):
+ def queryset(self, request, queryset):
+ try:
+ area = models.Area.objects.get(urn=self.value())
+ except models.Area.DoesNotExist:
+ return queryset
+ return queryset.filter(area.getIncludePolygon())
+
+
class HasCategoriesListFilter(SimpleListFilter):
title = _('Has categories')
parameter_name = 'has_category'
@@ -271,6 +289,38 @@ def moderator_right(user, qs, geo_type='marker'):
limited_for_user__user=user).all())
return qs
+MARKER_FIELDSETS = [
+ [None, {
+ 'fields': ['point', 'name', 'status', 'categories', 'description',
+ 'keywords', 'start_date', 'end_date']
+ }],
+ [_(u"Submitter"), {
+ 'classes': ('collapse',),
+ 'fields': ('submiter_name', 'submiter_email', 'submiter_comment')
+ }],
+ [_(u"Import"), {
+ 'classes': ('collapse',),
+ 'fields': ('not_for_osm', 'modified_since_import', 'import_source',
+ 'origin', 'license')
+ }],
+ [_(u"Associated items"), {
+ 'classes': ('collapse',),
+ 'fields': ['ref_item', 'route']
+ }]
+]
+
+ROUTE_FIELDSETS = deepcopy(MARKER_FIELDSETS)
+ROUTE_FIELDSETS[0][1]['fields'][0] = 'route'
+ROUTE_FIELDSETS[0][1]['fields'].pop(ROUTE_FIELDSETS[0][1]['fields'].index(
+ 'description'))
+ROUTE_FIELDSETS[3][1]['fields'] = ('ref_item', 'associated_file',
+ 'has_associated_marker')
+POLYGON_FIELDSETS = deepcopy(MARKER_FIELDSETS)
+POLYGON_FIELDSETS[0][1]['fields'][0] = 'polygon'
+POLYGON_FIELDSETS[0][1]['fields'].pop(POLYGON_FIELDSETS[0][1]['fields'].index(
+ 'description'))
+POLYGON_FIELDSETS.pop(3)
+
class MarkerAdmin(admin.ModelAdmin):
"""
@@ -284,43 +334,28 @@ class MarkerAdmin(admin.ModelAdmin):
export_to_shapefile, export_to_csv]
exclude = ['submiter_session_key', 'import_key', 'import_version',
'available_date', 'ref_item']
- readonly_fields = ['submiter_email', 'submiter_comment', 'import_source',
- 'submiter_name', 'ref_item', 'modified_since_import', 'route']
+ readonly_fields = [
+ 'submiter_email', 'submiter_comment', 'import_source',
+ 'submiter_name', 'ref_item', 'modified_since_import', 'route']
form = MarkerAdminForm
- fieldsets = ((None, {
- 'fields': ['point', 'name', 'status', 'categories',
- 'description', 'keywords', 'start_date', 'end_date']
- }),
- (_(u"Submitter"), {
- 'classes':('collapse',),
- 'fields': ('submiter_name', 'submiter_email',
- 'submiter_comment')
- }),
- (_(u"Import"), {
- 'classes':('collapse',),
- 'fields': ('not_for_osm', 'modified_since_import',
- 'import_source', 'origin', 'license')
- }),
- (_(u"Associated items"), {
- 'classes':('collapse',),
- 'fields': ('ref_item', 'route',)
- }),
- )
+ fieldsets = MARKER_FIELDSETS
inlines = [MultimediaInline, PictureInline]
has_properties = True
- def __init__(self, *args, **kwargs):
+ def get_fieldsets(self, request, obj=None):
"""
Manage properties in fieldsets.
"""
+ fieldsets = super(MarkerAdmin, self).get_fieldsets(request, obj)
+ newfieldsets = list(fieldsets)
if self.has_properties:
- main_fields = self.fieldsets[0][1]['fields']
- for pm in PropertyModel.objects.filter(available=True).order_by('order'
- ).all():
+ main_fields = newfieldsets[0][1]['fields']
+ for pm in PropertyModel.objects.filter(available=True)\
+ .order_by('order').all():
pm_name = pm.getNamedId()
if pm_name not in main_fields:
main_fields.append(pm_name)
- super(MarkerAdmin, self).__init__(*args, **kwargs)
+ return newfieldsets
def queryset(self, request):
qs = self.model._default_manager.get_query_set()
@@ -334,13 +369,14 @@ class MarkerAdmin(admin.ModelAdmin):
'''
Redirect to the marker modification form
'''
- return managed_modified(self, request,
- Marker.objects.filter(pk=item_id))
+ return managed_modified(
+ self, request, Marker.objects.filter(pk=item_id))
def get_urls(self):
from django.conf.urls.defaults import patterns, url
urls = super(MarkerAdmin, self).get_urls()
- my_urls = patterns('',
+ my_urls = patterns(
+ '',
url(r'^admin_modification/(?P<item_id>\d+)/$',
self.admin_site.admin_view(self.admin_modification),
name='admin-modification'),
@@ -348,6 +384,8 @@ class MarkerAdmin(admin.ModelAdmin):
return my_urls + urls
def get_form(self, request, obj=None, **kwargs):
+ # remove dynamic field to prevent admin check
+ kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets)
form = super(MarkerAdmin, self).get_form(request, obj, **kwargs)
q = request.user.subcategory_limit_to
if not q.count():
@@ -371,26 +409,7 @@ class RouteAdmin(MarkerAdmin):
readonly_fields = ('associated_file', 'ref_item', 'has_associated_marker')
actions = [validate, disable, managed_modified, export_to_kml,
export_to_shapefile, export_to_csv]
- fieldsets = ((None, {
- 'fields': ['route', 'name', 'status', 'categories',
- 'start_date', 'end_date']
- }),
- (_(u"Submitter"), {
- 'classes':('collapse',),
- 'fields': ('submiter_name', 'submiter_email',
- 'submiter_comment')
- }),
- (_(u"Import"), {
- 'classes':('collapse',),
- 'fields': ('modified_since_import', 'import_source',
- 'origin', 'license')
- }),
- (_(u"Associated items"), {
- 'classes':('collapse',),
- 'fields': ('ref_item', 'associated_file',
- 'has_associated_marker')
- }),
- )
+ fieldsets = ROUTE_FIELDSETS
inlines = []
has_properties = False
@@ -409,10 +428,29 @@ class RouteAdmin(MarkerAdmin):
return managed_modified(self, request,
Route.objects.filter(pk=item_id))
+
+class PolygonAdmin(MarkerAdmin):
+ """
+ Specialized the Polygon field.
+ """
+ list_filter = ('status', AreaPolygonListFilter, 'categories')
+ form = PolygonAdminForm
+ actions = [validate, disable, managed_modified, export_to_kml,
+ export_to_shapefile, export_to_csv]
+ readonly_fields = [
+ 'submiter_email', 'submiter_comment', 'import_source',
+ 'submiter_name', 'ref_item', 'modified_since_import']
+ exclude = ['submiter_session_key', 'import_key', 'import_version',
+ 'ref_item']
+ inlines = []
+ fieldsets = POLYGON_FIELDSETS
+
+
class LayerInline(admin.TabularInline):
model = AreaLayers
extra = 1
+
class AreaAdmin(admin.ModelAdmin):
"""
Specialized the area field.
@@ -422,6 +460,7 @@ class AreaAdmin(admin.ModelAdmin):
inlines = [LayerInline]
list_display = ['name', 'order', 'available', 'default']
+
def importing(modeladmin, request, queryset):
for importer in queryset:
importer.state = unicode(tasks.IMPORT_MESSAGES['import_pending'][0])
@@ -429,63 +468,72 @@ def importing(modeladmin, request, queryset):
tasks.importing(importer.pk)
importing.short_description = _(u"Import")
+
def cancel_import(modeladmin, request, queryset):
for importer in queryset:
importer.state = tasks.IMPORT_MESSAGES['import_cancel'][0]
importer.save()
cancel_import.short_description = _(u"Cancel import")
+
def cancel_export(modeladmin, request, queryset):
for importer in queryset:
importer.state = tasks.IMPORT_MESSAGES['export_cancel'][0]
importer.save()
cancel_export.short_description = _(u"Cancel export")
+
def export_to_osm(modeladmin, request, queryset):
if queryset.count() > 1:
- messages.error(request, _(u"Can manage only one OSM export at a time."))
+ messages.error(request,
+ _(u"Can manage only one OSM export at a time."))
return HttpResponseRedirect(request.get_full_path())
importer = queryset.all()[0]
if Marker.objects.filter(categories__in=importer.categories.all(),
status='I').count():
- messages.error(request, _(u"You must treat all item with the status "\
+ messages.error(request, _(u"You must treat all item with the status "
u"\"imported\" before exporting to OSM."))
return HttpResponseRedirect(request.get_full_path())
if importer.importer_type != 'OSM':
- messages.error(request, _(u"Only OSM importer are managed for export."))
+ messages.error(request,
+ _(u"Only OSM importer are managed for export."))
return HttpResponseRedirect(request.get_full_path())
- item_nb = Marker.objects.filter(status='A',
- categories=importer.categories.all(),
- not_for_osm=False, modified_since_import=True,
- route=None).count()
+ item_nb = Marker.objects.filter(
+ status='A', categories=importer.categories.all(), not_for_osm=False,
+ modified_since_import=True, route=None).count()
if not item_nb:
- messages.error(request, _(u"No point of interest are concerned by this "
- u"export."))
+ messages.error(request,
+ _(u"No point of interest are concerned by this "
+ u"export."))
return HttpResponseRedirect(request.get_full_path())
form = None
if request.method == 'POST' and (
- 'email' in request.POST or 'api' in request.POST
- or 'password' in request.POST):
+ 'email' in request.POST or 'api' in request.POST
+ or 'password' in request.POST):
form = OSMForm(request.POST)
if form.is_valid():
- importer.state = unicode(tasks.IMPORT_MESSAGES['export_pending'][0])
+ importer.state = unicode(
+ tasks.IMPORT_MESSAGES['export_pending'][0])
importer.save()
tasks.exporting(importer.pk, form.cleaned_data)
messages.success(request, _(u"Export launched."))
return HttpResponseRedirect(request.get_full_path())
else:
form = OSMForm()
- msg_item = _(u"%s point(s) of interest concerned by this export before "\
+ msg_item = _(u"%s point(s) of interest concerned by this export before "
u"bounding box filter.") % item_nb
- return render_to_response('admin/chimere/osm_export.html', {'item':importer,
- 'form':form, 'msg_item':msg_item},
+ return render_to_response('admin/chimere/osm_export.html',
+ {'item': importer, 'form': form,
+ 'msg_item': msg_item},
context_instance=RequestContext(request))
export_to_osm.short_description = _(u"Export to osm")
+
class ImporterKeyInline(admin.TabularInline):
model = ImporterKeyCategories
extra = 1
+
class ImporterAdmin(admin.ModelAdmin):
form = ImporterAdminForm
list_display = ('importer_type', 'display_categories', 'default_name',
@@ -496,14 +544,13 @@ class ImporterAdmin(admin.ModelAdmin):
inlines = [ImporterKeyInline]
admin.site.register(Importer, ImporterAdmin)
+
class PageAdmin(admin.ModelAdmin):
"""
Use the TinyMCE widget for the page content
"""
form = PageAdminForm
-class PropertyModelAdmin(admin.ModelAdmin):
- list_display = ('name', 'order', 'available')
class NewsAdmin(admin.ModelAdmin):
"""
@@ -511,10 +558,12 @@ class NewsAdmin(admin.ModelAdmin):
"""
form = NewsAdminForm
+
class SubcatInline(admin.TabularInline):
model = SubCategory
extra = 1
+
class CategoryAdmin(admin.ModelAdmin):
"""
Use the TinyMCE widget for categories
@@ -523,20 +572,27 @@ class CategoryAdmin(admin.ModelAdmin):
inlines = [SubcatInline]
list_display = ['name', 'order']
+
class ColorInline(admin.TabularInline):
model = Color
+
class ColorThemeAdmin(admin.ModelAdmin):
- inlines = [ColorInline,]
+ inlines = [ColorInline]
+
class IconAdmin(admin.ModelAdmin):
exclude = ['height', 'width']
list_display = ['name']
+
class PropertyModelChoiceInline(admin.TabularInline):
model = PropertyModelChoice
extra = 1
+
+
class PropertyModelAdmin(admin.ModelAdmin):
+ list_display = ('name', 'order', 'available')
inlines = [PropertyModelChoiceInline]
# register of differents database fields
@@ -545,7 +601,8 @@ admin.site.register(News, NewsAdmin)
admin.site.register(Category, CategoryAdmin)
admin.site.register(Icon, IconAdmin)
admin.site.register(Marker, MarkerAdmin)
-admin.site.register(Route, RouteAdmin)
+admin.site.register(models.Route, RouteAdmin)
+admin.site.register(models.Polygon, PolygonAdmin)
if not settings.CHIMERE_HIDE_PROPERTYMODEL:
admin.site.register(PropertyModel, PropertyModelAdmin)
admin.site.register(Area, AreaAdmin)
diff --git a/chimere/feeds.py b/chimere/feeds.py
index 53444ac..025ceb0 100644
--- a/chimere/feeds.py
+++ b/chimere/feeds.py
@@ -31,6 +31,7 @@ from django.shortcuts import get_object_or_404
from chimere.models import Category, SubCategory, Marker, Area
+
class BaseFeed(Feed):
"""
Base feed for Chimere objects
@@ -42,8 +43,8 @@ class BaseFeed(Feed):
if item.categories.all() and item.categories.all()[0]:
cat = item.categories.all()[0].pk
return reverse('chimere:index') + '?zoom=16&lat=%f&lon=%f&'\
- 'current_feature=%d&checked_categories=%d' % (coord.y, coord.x, item.id,
- cat)
+ 'current_feature=%d&checked_categories=%d' % (coord.y, coord.x,
+ item.id, cat)
def item_pubdate(self, item):
"""
@@ -57,6 +58,7 @@ class BaseFeed(Feed):
def item_geometry(self, obj):
return obj.point
+
class LatestPOIsByCategory(BaseFeed):
'''
Last Points of interests by category in Feeds
@@ -87,11 +89,13 @@ class LatestPOIsByCategory(BaseFeed):
and its status is available
This returns a list of the 15 last markers/POIs ordering by date
"""
- q = Marker.objects.filter(status__exact='A',
+ q = Marker.objects.filter(
+ status__exact='A',
categories__category__id__exact=obj.id,
available_date__isnull=False).order_by('-available_date')[:15]
return q
+
class LatestPOIsBySubCategory(BaseFeed):
'''
Last Points of interests by SubCategory in Feeds
@@ -112,11 +116,13 @@ class LatestPOIsBySubCategory(BaseFeed):
return reverse('chimere:feeds-subcat', args=['', obj.id])
def items(self, obj):
- q = Marker.objects.filter(categories__id__exact=obj.id,
- available_date__isnull=False, status__exact='A').order_by(
- '-available_date')[:15]
+ q = Marker.objects.filter(
+ categories__id__exact=obj.id,
+ available_date__isnull=False, status__exact='A')\
+ .order_by('-available_date')[:15]
return q
+
class LatestPOIs(BaseFeed):
'''
Last Points of interests
@@ -134,10 +140,12 @@ class LatestPOIs(BaseFeed):
return _("Latest points of interest from ") + settings.PROJECT_NAME
def items(self):
- q = Marker.objects.filter(status__exact='A',
- available_date__isnull=False).order_by('-available_date')[:15]
+ q = Marker.objects.filter(
+ status__exact='A',
+ available_date__isnull=False).order_by('-available_date')[:15]
return q
+
class LatestPOIsByZone(BaseFeed):
'''
Last Points of interests by zone by coordinates
@@ -168,16 +176,16 @@ class LatestPOIsByZone(BaseFeed):
lower_left_lon = upper_left_lon
# Define a Polygon with the 4 points of the zone.
areaBox = Polygon(((upper_left_lon, upper_left_lat),
- (upper_right_lon, upper_right_lat),
- (lower_right_lon, lower_right_lat),
- (lower_left_lon, lower_left_lat),
- (upper_left_lon, upper_left_lat)),
- srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ (upper_right_lon, upper_right_lat),
+ (lower_right_lon, lower_right_lat),
+ (lower_left_lon, lower_left_lat),
+ (upper_left_lon, upper_left_lat)),
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
return areaBox
def title(self, obj):
return settings.PROJECT_NAME + u" - " +\
- _(u"Last points of interest by area")
+ _(u"Last points of interest by area")
def link(self, obj):
"""
@@ -187,7 +195,7 @@ class LatestPOIsByZone(BaseFeed):
if not obj:
raise FeedDoesNotExist
area = str(self.upper_left_lat) + '_' + str(self.upper_left_lon) + \
- '_' + str(self.lower_right_lat) + '_' + str(self.lower_right_lon)
+ '_' + str(self.lower_right_lat) + '_' + str(self.lower_right_lon)
return reverse('chimere:feeds-area', args=['', area])
def items(self, obj):
@@ -196,10 +204,12 @@ class LatestPOIsByZone(BaseFeed):
which is requested.
This returns a list of the 15 last markers/POIs ordering by date
"""
- q = Marker.objects.filter(point__contained=obj, status__exact='A',
- available_date__isnull=False).order_by('-available_date')[:15]
+ q = Marker.objects.filter(
+ point__contained=obj, status__exact='A',
+ available_date__isnull=False).order_by('-available_date')[:15]
return q
+
class LatestPOIsByZoneID(BaseFeed):
'''
Last Points of interests by zone by id
@@ -212,7 +222,7 @@ class LatestPOIsByZoneID(BaseFeed):
def title(self, obj):
return settings.PROJECT_NAME + u" - " + \
- _(u"Last points of interest") + u" - " + obj.name
+ _(u"Last points of interest") + u" - " + obj.name
def link(self, obj):
if not obj:
diff --git a/chimere/fixtures/initial_data.json b/chimere/fixtures/initial_data.json
index c44eb63..592e589 100644
--- a/chimere/fixtures/initial_data.json
+++ b/chimere/fixtures/initial_data.json
@@ -194,32 +194,8 @@
"pk": 1,
"model": "chimere.layer",
"fields": {
- "layer_code": "new OpenLayers.Layer.OSM.Mapnik(\"Mapnik OSM\",\r\n{attribution:\"\", keyid:\"mapnik\", displayOutsideMaxExtent:!0,wrapDateLine:!0,layerCode:\"M\"})",
+ "layer_code": "new ol.layer.Tile({\r\n source: new ol.source.OSM(),\r\n baselayer: true,\r\n name: 'OSM - Mapnik'\r\n})",
"name": "OSM - Mapnik"
}
- },
- {
- "pk": 2,
- "model": "chimere.layer",
- "fields": {
- "layer_code": "new OpenLayers.Layer.OSM.CycleMap(\"Cycle map\",\r\n{attribution:\"Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>\",\r\nkeyid:\"cyclemap\",displayOutsideMaxExtent:!0,wrapDateLine:!0,layerCode:\"C\"})",
- "name": "OSM - CycleMap"
- }
- },
- {
- "pk": 3,
- "model": "chimere.layer",
- "fields": {
- "layer_code": "new OpenLayers.Layer.OSM.TransportMap(\"Transport map\",\r\n{attribution:\"Tiles courtesy of <a href='http://www.opencyclemap.org/' target='_blank'>Andy Allan</a>\",\r\nkeyid:\"transportmap\",displayOutsideMaxExtent:!0,wrapDateLine:!0,layerCode:\"T\"})",
- "name": "OSM - TransportMap"
- }
- },
- {
- "pk": 4,
- "model": "chimere.layer",
- "fields": {
- "layer_code": "new OpenLayers.Layer.MapQuestOSM()",
- "name": "OSM - MapQuest"
- }
}
]
diff --git a/chimere/forms.py b/chimere/forms.py
index b62859c..8b86df1 100644
--- a/chimere/forms.py
+++ b/chimere/forms.py
@@ -38,7 +38,7 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') and \
from chimere.models import Marker, Route, PropertyModel, Area,\
News, Category, RouteFile, MultimediaFile, MultimediaType, \
PictureFile, Importer, PropertyModelChoice, Page, IMPORTER_CHOICES, \
- get_areas_for_user, SubCategoryUserLimit
+ get_areas_for_user, SubCategoryUserLimit, Polygon
from chimere.widgets import AreaField, PointField, TextareaWidget, \
FullTextareaWidget, DatePickerWidget, ButtonSelectWidget, NominatimWidget,\
TextareaAdminWidget, ImportFiltrWidget, ImporterChoicesWidget, RE_XAPI
@@ -203,7 +203,7 @@ class ImporterAdminForm(forms.ModelForm):
model = Importer
widgets = {
'source': forms.TextInput(attrs={'size': 80}),
- 'filtr': forms.TextInput(attrs={'size': 80}),
+ 'filtr': forms.Textarea(attrs={'size': 80}),
}
def clean(self):
@@ -256,20 +256,69 @@ class CategoryAdminForm(forms.ModelForm):
model = Category
+def get_properties(queryset):
+ # As we have dynamic fields, it's cleaner to make the class dynamic too
+ fields = {}
+ for prop in queryset:
+ key = "property_%d_%d" % (prop.order, prop.id)
+ if prop.type == 'C':
+ choices = PropertyModelChoice.objects.filter(propertymodel=prop,
+ available=True
+ ).order_by('value')
+ fields[key] = forms.ChoiceField(
+ label=prop.name, choices=[('', '--')] +
+ [(choice.pk, unicode(choice)) for choice in choices],
+ required=False)
+ elif prop.type == 'A':
+ widget = PropertyModel.TYPE_WIDGET[prop.type]
+ widget = widget(slug=prop.slug)
+ fields[key] = forms.CharField(label=prop.name, widget=widget,
+ required=False)
+ else:
+ widget = PropertyModel.TYPE_WIDGET[prop.type]
+ fields[key] = forms.CharField(
+ label=prop.name, widget=widget,
+ required=False)
+ return fields
+
+
class MarkerAdminFormBase(forms.ModelForm):
"""
Main form for marker
"""
+ is_admin = True
+ name = forms.CharField(_(u"Name"), required=True)
description = forms.CharField(widget=TextareaAdminWidget, required=False)
+ _PROPERTY_FILTERS = {}
class Meta:
model = Marker
+ @classmethod
+ def _set_cls_fields(cls):
+ fields = get_properties(
+ PropertyModel.objects.filter(**cls._PROPERTY_FILTERS).all())
+ for key in fields:
+ print(key)
+ setattr(cls, key, fields[key])
+
+ def _set_fields(self):
+ fields = get_properties(
+ PropertyModel.objects.filter(**self._PROPERTY_FILTERS).all())
+ for key in fields:
+ self.fields[key] = fields[key]
+
def __init__(self, *args, **keys):
"""
Custom initialization method in order to manage properties
"""
- self.pms = [pm for pm in PropertyModel.objects.filter(available=True)]
+ area_name = None
+ if 'area_name' in keys:
+ area_name = keys.pop('area_name')
+ querys = PropertyModel.getAvailable(area_name=area_name)
+ self.pms = []
+ for query in querys:
+ self.pms += [pm for pm in query.all()]
if 'instance' in keys and keys['instance']:
instance = keys['instance']
property_dct = {}
@@ -284,13 +333,45 @@ class MarkerAdminFormBase(forms.ModelForm):
subcategories = keys.pop('subcategories') \
if 'subcategories' in keys else []
super(MarkerAdminFormBase, self).__init__(*args, **keys)
+ self._set_fields()
if settings.CHIMERE_DAYS_BEFORE_EVENT:
self.fields['start_date'].widget = DatePickerWidget()
self.fields['end_date'].widget = DatePickerWidget()
+ if self.is_admin:
+ return
if subcategories:
self.fields['categories'].choices = subcategories
- elif hasattr(self, 'categories_choices'):
- self.fields['categories'].choices = self.categories_choices
+ # auto select if there is only one category
+ choices = list(self.fields['categories'].choices)
+ self.fields['categories'].choices = choices
+ self.fields['categories'].label = ""
+ if (len(choices) == 1):
+ self.fields['categories'].widget = forms.MultipleHiddenInput()
+ choices = list(self.fields['categories'].choices)
+ if type(choices[0][1]) in (list, tuple):
+ # hierarchical choices
+ self.fields['categories'].label = u"{} / {}".format(
+ choices[0][0], choices[0][1][0][1])
+ self.fields['categories'].initial = \
+ [self.fields['categories'].choices[0][1][0][0]]
+ else:
+ self.fields['categories'].label = u"{}".format(
+ choices[0][1])
+ self.fields['categories'].initial = \
+ [self.fields['categories'].choices[0][0]]
+ if not settings.CHIMERE_SEARCH_ENGINE and 'keywords' in self.fields:
+ self.fields.pop('keywords')
+ if not settings.CHIMERE_DAYS_BEFORE_EVENT:
+ self.fields.pop('start_date')
+ self.fields.pop('end_date')
+ # not a clean way to filter properties...
+ # to do: change creation process
+ pms = [pm.getNamedId() for pm in self.pms]
+ for k in self.fields.keys():
+ if not k.startswith('property_') or \
+ k in pms:
+ continue
+ self.fields.pop(k)
def clean(self):
'''
@@ -341,46 +422,34 @@ class MarkerAdminFormBase(forms.ModelForm):
return new_marker
-def get_properties(queryset):
- # As we have dynamic fields, it's cleaner to make the class dynamic too
- fields = {}
- for prop in queryset:
- key = "property_%d_%d" % (prop.order, prop.id)
- if prop.type == 'C':
- choices = PropertyModelChoice.objects.filter(propertymodel=prop,
- available=True
- ).order_by('value')
- fields[key] = forms.ChoiceField(
- label=prop.name, choices=[('', '--')] +
- [(choice.pk, unicode(choice)) for choice in choices],
- required=False)
- else:
- fields[key] = forms.CharField(
- label=prop.name, widget=PropertyModel.TYPE_WIDGET[prop.type],
- required=False)
- return fields
+class MarkerAdminForm(MarkerAdminFormBase):
+ pass
+
-# in admin all fields are displayed
-MarkerAdminForm = type(
- "MarkerAdminForm", (MarkerAdminFormBase,),
- get_properties(PropertyModel.objects.all()))
-MarkerBaseForm = type(
- "MarkerBaseForm", (MarkerAdminFormBase,),
- get_properties(PropertyModel.objects.filter(available=True)))
+class MarkerBaseForm(MarkerAdminFormBase):
+ # in public form only visible fields are displayed
+ _PROPERTY_FILTERS = {'available': True}
+
+
+EXCLUDED_FIELDS = ['status']
+if not settings.CHIMERE_SEARCH_ENGINE:
+ EXCLUDED_FIELDS.append('keywords')
class MarkerForm(MarkerBaseForm):
"""
Form for the edit page
"""
+ is_admin = False
ref_pk = forms.IntegerField(label=u" ", widget=forms.HiddenInput(),
required=False)
description = forms.CharField(widget=TextareaWidget, required=False)
- keywords = forms.CharField(max_length=200, required=False)
+ keywords = forms.CharField(widget=TextareaWidget, max_length=200,
+ required=False)
class Meta:
model = Marker
- exclude = ('status',)
+ exclude = EXCLUDED_FIELDS
widgets = {
'description': TextareaWidget(),
}
@@ -390,6 +459,9 @@ class RouteAdminForm(forms.ModelForm):
"""
Main form for route
"""
+ is_admin = True
+ name = forms.CharField(_(u"Name"), required=True)
+
class Meta:
model = Route
@@ -397,6 +469,13 @@ class RouteAdminForm(forms.ModelForm):
"""
Custom initialization method in order to manage properties
"""
+ area_name = None
+ if 'area_name' in keys:
+ area_name = keys.pop('area_name')
+ querys = PropertyModel.getAvailable(area_name=area_name)
+ self.pms = []
+ for query in querys:
+ self.pms += [pm for pm in query.all()]
if 'instance' in keys and keys['instance']:
instance = keys['instance']
property_dct = {}
@@ -411,11 +490,24 @@ class RouteAdminForm(forms.ModelForm):
subcategories = keys.pop('subcategories') \
if 'subcategories' in keys else []
super(RouteAdminForm, self).__init__(*args, **keys)
+ if self.is_admin:
+ return
+ if not settings.CHIMERE_SEARCH_ENGINE and 'keywords' in self.fields:
+ self.fields.pop('keywords')
if settings.CHIMERE_DAYS_BEFORE_EVENT:
self.fields['start_date'].widget = DatePickerWidget()
self.fields['end_date'].widget = DatePickerWidget()
+ self.fields['categories'].choices = []
if subcategories:
self.fields['categories'].choices = subcategories
+ # not a clean way to filter properties...
+ # to do: change creation process
+ pms = [pm.getNamedId() for pm in self.pms]
+ for k in self.fields.keys():
+ if not k.startswith('property_') or \
+ k in pms:
+ continue
+ self.fields.pop(k)
def save(self, *args, **keys):
"""
@@ -432,15 +524,18 @@ class RouteForm(RouteAdminForm):
"""
Form for the edit page
"""
+ is_admin = False
description = forms.CharField(widget=TextareaWidget, required=False)
point = forms.CharField(label=" ", required=False,
widget=forms.HiddenInput)
associated_file_id = forms.CharField(
label=" ", required=False, widget=forms.HiddenInput)
+ keywords = forms.CharField(widget=TextareaWidget, max_length=200,
+ required=False)
class Meta:
model = Route
- exclude = ('status',)
+ exclude = EXCLUDED_FIELDS
def __init__(self, *args, **kwargs):
if kwargs.get('instance'):
@@ -493,6 +588,26 @@ class RouteForm(RouteAdminForm):
return new_route
+class PolygonAdminForm(MarkerAdminForm):
+ """
+ Main form for polygon
+ """
+ class Meta:
+ model = Polygon
+
+
+class PolygonForm(PolygonAdminForm):
+ """
+ Form for the edit page
+ """
+ is_admin = False
+ description = forms.CharField(widget=TextareaWidget, required=False)
+
+ class Meta:
+ model = Polygon
+ exclude = EXCLUDED_FIELDS
+
+
class BaseFileForm(forms.ModelForm):
id = forms.IntegerField(label=u"", widget=forms.HiddenInput(),
required=False)
@@ -502,8 +617,9 @@ class BaseFileForm(forms.ModelForm):
raise ImproperlyConfigured
super(BaseFileForm, self).__init__(*args, **kwargs)
self.fields.pop('marker')
+ self.fields.pop('polygon')
- def save(self, associated_marker):
+ def save(self, associated_item):
if not hasattr(self, 'cleaned_data') or not self.cleaned_data:
return
instance = None
@@ -519,7 +635,10 @@ class BaseFileForm(forms.ModelForm):
instance.delete()
return
self.cleaned_data.pop('DELETE')
- self.cleaned_data['marker'] = associated_marker
+ if type(associated_item) == Marker:
+ self.cleaned_data['marker'] = associated_item
+ if type(associated_item) == Polygon:
+ self.cleaned_data['polygon'] = associated_item
if instance:
for k in self.cleaned_data:
setattr(instance, k, self.cleaned_data[k])
diff --git a/chimere/locale/fr/LC_MESSAGES/django.po b/chimere/locale/fr/LC_MESSAGES/django.po
index 75049e3..72e7fa0 100644
--- a/chimere/locale/fr/LC_MESSAGES/django.po
+++ b/chimere/locale/fr/LC_MESSAGES/django.po
@@ -6,192 +6,214 @@ msgid ""
msgstr ""
"Project-Id-Version: 0.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-04-20 09:15+0200\n"
+"POT-Creation-Date: 2016-05-15 19:12+0200\n"
"PO-Revision-Date: 2010-03-20 20:00+0100\n"
"Last-Translator: Étienne Loks <etienne.loks@peacefrogs.net>\n"
+"Language-Team: Iggdrasil\n"
+"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: actions.py:44
+#: actions.py:48
msgid "View"
msgstr "Voir"
-#: actions.py:45
+#: actions.py:49
msgid "Contribute"
msgstr "Participer"
-#: actions.py:46
+#: actions.py:50
msgid "Add a new point of interest"
msgstr "Ajout d'un point remarquable"
-#: actions.py:47
+#: actions.py:51
msgid "Add a new route"
msgstr "Ajout d'un nouveau trajet"
#: actions.py:52
+msgid "Add a new polygon"
+msgstr "Ajout d'un nouveau polygone"
+
+#: actions.py:57
msgid "Directory"
msgstr "Annuaire"
-#: actions.py:56
+#: actions.py:61
msgid "RSS feeds"
msgstr "Flux RSS"
-#: actions.py:60
+#: actions.py:65
msgid "Contact us"
msgstr "Nous contacter"
-#: admin.py:55
+#: admin.py:59
msgid "Disable"
msgstr "Désactiver"
-#: admin.py:61 templates/admin/chimere/managed_modified.html:44
+#: admin.py:66 templates/admin/chimere/managed_modified.html:44
#: templates/chimere/feeds/rss.html:70
msgid "Validate"
msgstr "Valider"
-#: admin.py:72
+#: admin.py:78
msgid "Export to KML"
msgstr "Exporter en KML"
-#: admin.py:86
+#: admin.py:93
msgid "Export to Shapefile"
msgstr "Exporter en Shapefile"
-#: admin.py:96
+#: admin.py:104
msgid "Export to CSV"
msgstr "Exporter en CSV"
-#: admin.py:103
+#: admin.py:112
msgid "Only one item can be managed at a time."
msgstr "Seul un élément à la fois peut-être géré."
-#: admin.py:113
+#: admin.py:122
msgid "No modified item associated to the selected item."
msgstr "Pas d'élément modifié associé à l'élément sélectionné."
-#: admin.py:159
+#: admin.py:168
msgid "Modified item traited."
msgstr "Élément modifié traité."
-#: admin.py:164
+#: admin.py:173
msgid "Managed modified items"
msgstr "Gérer les éléments modifiés"
-#: admin.py:181
+#: admin.py:206
msgid "area"
msgstr "zone"
-#: admin.py:221 admin.py:298
+#: admin.py:239
+msgid "Has categories"
+msgstr "A des catégories"
+
+#: admin.py:244
+msgid "Yes"
+msgstr "Oui"
+
+#: admin.py:245
+msgid "No"
+msgstr "Non"
+
+#: admin.py:257
+msgid "categories"
+msgstr "Catégories"
+
+#: admin.py:296
msgid "Submitter"
msgstr "Demandeur"
-#: admin.py:226 admin.py:303 admin.py:355
+#: admin.py:300 admin.py:464
msgid "Import"
msgstr "Import"
-#: admin.py:231 admin.py:308
+#: admin.py:305
msgid "Associated items"
msgstr "Éléments associés"
-#: admin.py:361
+#: admin.py:471
msgid "Cancel import"
msgstr "Annuler l'import"
-#: admin.py:367
+#: admin.py:478
msgid "Cancel export"
msgstr "Annuler l'export"
-#: admin.py:371
+#: admin.py:484
msgid "Can manage only one OSM export at a time."
msgstr "Ne peux gérer qu'un seul export OSM à la fois."
-#: admin.py:376
+#: admin.py:489
msgid ""
"You must treat all item with the status \"imported\" before exporting to OSM."
msgstr ""
"Vous devez traiter tous les éléments avec le status « importé » avant "
"d'exporter vers OSM."
-#: admin.py:380
+#: admin.py:494
msgid "Only OSM importer are managed for export."
msgstr "Seul les imports de type OSM peuvent être gérés pour les exports."
-#: admin.py:387
+#: admin.py:501
msgid "No point of interest are concerned by this export."
msgstr "Aucun point d'intérêt n'est concerné par cet export."
-#: admin.py:399
+#: admin.py:514
msgid "Export launched."
msgstr "Export lancé."
-#: admin.py:403
+#: admin.py:518
#, python-format
msgid ""
"%s point(s) of interest concerned by this export before bounding box filter."
msgstr ""
"%s point(s) d'intérêt concerné par cet export (avant le filtre sur la zone)"
-#: admin.py:408
+#: admin.py:524
msgid "Export to osm"
msgstr "Exporter vers osm"
-#: feeds.py:128 feeds.py:215
+#: feeds.py:134 feeds.py:225
msgid "Last points of interest"
msgstr "Derniers points d'intérêt"
-#: feeds.py:134
+#: feeds.py:140
msgid "Latest points of interest from "
msgstr "Nouveaux points d'intérêt de "
-#: feeds.py:180
+#: feeds.py:188
msgid "Last points of interest by area"
msgstr "Nouveaux points d'intérêt par zone"
-#: forms.py:87
+#: forms.py:126
msgid "New submission for"
msgstr "Nouvelle proposition pour"
-#: forms.py:88
+#: forms.py:127
#, python-format
msgid "The new item \"%s\" has been submited in the category: "
msgstr "Le nouvel élément « %s » a été proposé dans la catégorie : "
-#: forms.py:90
+#: forms.py:129
msgid "To valid, precise or unvalid this item: "
msgstr "Pour valider, préciser ou rejeter cet élément : "
-#: forms.py:100
+#: forms.py:144
msgid "Email (optional)"
msgstr "Courriel (optionnel) "
-#: forms.py:101
+#: forms.py:145
msgid "Object"
msgstr "Objet"
-#: forms.py:121
+#: forms.py:169
msgid "OSM user"
msgstr "Utilisateur OSM"
-#: forms.py:122 models.py:1552
+#: forms.py:170 models.py:1813
msgid "Password"
msgstr "Mot de passe"
-#: forms.py:126
+#: forms.py:175
msgid "API"
msgstr "API"
-#: forms.py:129
+#: forms.py:178
#, python-format
msgid "Test API - %s"
msgstr "API de test - %s"
-#: forms.py:131
+#: forms.py:180
#, python-format
msgid "Main API - %s"
msgstr "API principale - %s"
-#: forms.py:162 forms.py:166
+#: forms.py:217 forms.py:222
msgid ""
"For OSM import you must be provide a filter. Select an area and node/way "
"filter."
@@ -199,554 +221,611 @@ msgstr ""
"Pour les imports OSM vous devez fournir un filtre. Sélectionnez une zone et "
"un filtre sur les nœuds/routes."
-#: forms.py:170
+#: forms.py:226
msgid "Shapefiles must be provided in a zipped archive."
msgstr ""
"Les fichiers Shapefiles doivent être fournis regroupés dans une archive zip."
-#: forms.py:175
+#: forms.py:231
msgid "You have to set \"source\" or \"source file\" but not both."
msgstr ""
"Vous devez spécifier le champ « Source » ou « Fichier source » mais pas les "
"deux."
-#: forms.py:180
+#: forms.py:236
msgid "You have to set \"source\" or \"source file\"."
msgstr "Vous devez spécifier le champ « Source » ou « Fichier source »."
-#: forms.py:241
+#: forms.py:304
msgid "End date has been set with no start date"
msgstr "Une date de fin a été donnée sans date de début"
-#: forms.py:245
+#: forms.py:308
msgid "End date can't be before start date"
msgstr "La date de fin ne peut pas être antérieure à la date de début"
-#: forms.py:255
+#: forms.py:319
msgid "This field is mandatory for the selected categories"
msgstr "Ce champ est obligatoire pour les catégories sélectionnées"
-#: forms.py:507
+#: forms.py:622
msgid "File"
msgstr "Fichier"
-#: forms.py:513
+#: forms.py:628
msgid "Bad file format: this must be a GPX or KML file"
msgstr "Mauvais format de fichier : KML et GPX sont supportés"
-#: forms.py:518 models.py:54 models.py:102 models.py:164 models.py:185
-#: models.py:198 models.py:213 models.py:424 models.py:773 models.py:829
-#: models.py:888 models.py:1006 models.py:1356 models.py:1368 models.py:1542
-#: utils.py:490 templates/admin/chimere/managed_modified.html:23
-#: templates/chimere/edit.html:40 templates/chimere/edit_route.html:37
+#: forms.py:634 models.py:56 models.py:109 models.py:178 models.py:206
+#: models.py:222 models.py:251 models.py:498 models.py:980 models.py:1039
+#: models.py:1107 models.py:1229 models.py:1586 models.py:1599 models.py:1801
+#: utils.py:557 templates/admin/chimere/managed_modified.html:23
+#: templates/chimere/edit.html:47 templates/chimere/edit_route.html:37
#: templates/chimere/blocks/alternate_multimedia.html:39
msgid "Name"
msgstr "Nom"
-#: forms.py:527 models.py:1405
+#: forms.py:645 models.py:1650
msgid "Area"
msgstr "Zone"
-#: forms.py:567
+#: forms.py:686
msgid "No area selected."
msgstr "Pas de zone sélectionnée."
-#: forms.py:574
+#: forms.py:693
#, python-format
-msgid "The area \"%s\" has the same order, you need to choose another one."
+msgid "The area \"%s\" has the same order, you need to choose another one."
msgstr ""
"La zone « %s » a le même numéro d'ordre, vous devez un choisir un autre."
-#: forms.py:625
+#: forms.py:746
msgid "Start"
msgstr "Départ"
-#: forms.py:626
+#: forms.py:747
msgid "Finish"
msgstr "Arrivée"
-#: forms.py:627
+#: forms.py:748
msgid "Speed"
msgstr "Vitesse"
-#: models.py:55
+#: models.py:57
msgid "Mnemonic"
msgstr "Mnémonique"
-#: models.py:57 models.py:103 models.py:186 models.py:214 models.py:417
-#: models.py:777 models.py:1374 models.py:1544 models.py:1587
+#: models.py:59 models.py:110 models.py:207 models.py:252 models.py:377
+#: models.py:984 models.py:1605 models.py:1804 models.py:1849
msgid "Available"
msgstr "Disponible"
-#: models.py:58 models.py:174 models.py:187 models.py:231 models.py:831
-#: models.py:903 models.py:1373 models.py:1531 models.py:1543
+#: models.py:60 models.py:192 models.py:208 models.py:271 models.py:1041
+#: models.py:1122 models.py:1604 models.py:1789 models.py:1803
msgid "Order"
msgstr "Ordre"
-#: models.py:59
+#: models.py:61
msgid "Template path"
msgstr "Chemin du patron"
-#: models.py:66 models.py:67
+#: models.py:67 models.py:68
msgid "Page"
msgstr "Page"
-#: models.py:104 models.py:520
+#: models.py:111 models.py:722
msgid "Is front page"
msgstr "Est en page principale"
-#: models.py:106 models.py:1553
+#: models.py:113 models.py:1814
msgid "Date"
msgstr "Date"
-#: models.py:108 models.py:830
+#: models.py:115 models.py:1040
msgid "Url"
msgstr "Url"
-#: models.py:109
+#: models.py:116
msgid "Associated areas"
msgstr "Zones associées"
-#: models.py:115 models.py:116 templates/chimere/blocks/news.html:3
+#: models.py:121 models.py:122 templates/chimere/blocks/news.html:3
#: templates/chimere/blocks/news.html:5
msgid "News"
msgstr "Actualités"
-#: models.py:125
+#: models.py:135
msgid "Parameters"
msgstr "Paramètres"
-#: models.py:129
+#: models.py:141
msgid "TinyUrl"
msgstr "Mini-url"
-#: models.py:168 models.py:175 models.py:226
+#: models.py:181 models.py:193 models.py:266
msgid "Color theme"
msgstr "Thème de couleur"
-#: models.py:173
-msgid "Code"
-msgstr "Code"
+#: models.py:190
+msgid "Code/name"
+msgstr "Code/nom"
+
+#: models.py:191 models.py:901 models.py:905 models.py:1303
+msgid "HTML code/name"
+msgstr "HTML code/nom"
-#: models.py:180
+#: models.py:197 models.py:901 models.py:1303
msgid "Color"
msgstr "Couleur"
-#: models.py:193 models.py:211 models.py:410
+#: models.py:213 models.py:249 models.py:489
msgid "Category"
msgstr "Catégorie"
-#: models.py:199 models.py:769 models.py:889 models.py:1072
+#: models.py:223 models.py:896 models.py:976 models.py:1108 models.py:1296
#: templates/chimere/blocks/alternate_multimedia.html:43
msgid "Image"
msgstr "Image"
-#: models.py:201 models.py:891 models.py:1074
+#: models.py:225 models.py:898 models.py:1110 models.py:1298
msgid "Height"
msgstr "Hauteur"
-#: models.py:202 models.py:892 models.py:1075
+#: models.py:226 models.py:899 models.py:1111 models.py:1299
msgid "Width"
msgstr "Largeur"
-#: models.py:206 models.py:223
+#: models.py:228
+msgid "Offset x"
+msgstr "Décalage en x"
+
+#: models.py:229
+msgid "Common value is half the icon width"
+msgstr "Une valeur courante est la moitié de la largeur de l'icône"
+
+#: models.py:231
+msgid "Offset y"
+msgstr "Décalage en y"
+
+#: models.py:232 models.py:237
+msgid "Common value is icon height"
+msgstr "Une valeur courante est la hauteur de l'icône"
+
+#: models.py:233
+msgid "Popup offset x"
+msgstr "Décalage en x pour le popup"
+
+#: models.py:234
+msgid "Common value is 0"
+msgstr "Une valeur courante est 0"
+
+#: models.py:236
+msgid "Popup offset y"
+msgstr "Décalage en y pour le popup"
+
+#: models.py:243 models.py:262
msgid "Icon"
msgstr "Icône"
-#: models.py:215
+#: models.py:253
msgid "Available for submission"
msgstr "Disponible pour soumission"
-#: models.py:217
+#: models.py:255
msgid "Marker"
msgstr "Point d'intérêt"
-#: models.py:218 models.py:1068 models.py:1085
+#: models.py:256 models.py:1291 models.py:1309
#: templates/chimere/edit_route.html:28
msgid "Route"
msgstr "Trajet"
-#: models.py:219
+#: models.py:257 models.py:894 models.py:910 models.py:1864
+#: templates/chimere/edit_polygon.html:9
+msgid "Polygon"
+msgstr "Polygone"
+
+#: models.py:258
msgid "Both"
msgstr "Mixte"
-#: models.py:220
+#: models.py:259
msgid "Item type"
msgstr "Type d'élément"
-#: models.py:221
+#: models.py:260
msgid "Is dated"
msgstr "Est daté"
-#: models.py:224
+#: models.py:264
msgid "Hover icon"
msgstr "Icône en survol"
-#: models.py:228
+#: models.py:268
msgid "Displayed in the layer menu"
msgstr "Apparaît dans le menu des couches ?"
-#: models.py:230
+#: models.py:270
msgid "Routing warn"
msgstr "Avertissement sur les itinéraires"
-#: models.py:232 models.py:435 templates/chimere/edit.html:56
+#: models.py:272 models.py:508 templates/chimere/edit.html:58
msgid "Keywords"
msgstr "Mots clés"
-#: models.py:238
+#: models.py:277
msgid "Sub-category"
msgstr "Sous-catégorie"
-#: models.py:239
+#: models.py:278
msgid "Sub-categories"
msgstr "Sous-catégories"
-#: models.py:336
+#: models.py:372
+msgid "Sub-category limit for user"
+msgstr "Limitation de sous-catégorie par utilisateur"
+
+#: models.py:373
+msgid "Sub-category limits for users"
+msgstr "Limitations de sous-catégories par utilisateurs"
+
+#: models.py:376
+msgid "Submited"
+msgstr "Soumis"
+
+#: models.py:378
+msgid "Modified"
+msgstr "Modifié"
+
+#: models.py:379
+msgid "Disabled"
+msgstr "Désactivé"
+
+#: models.py:380
+msgid "Imported"
+msgstr "Importé"
+
+#: models.py:412
msgid "Importer type"
msgstr "Type d'import"
-#: models.py:338
+#: models.py:414
msgid "Filter"
msgstr "Filtre"
-#: models.py:340 templates/chimere/blocks/alternate_multimedia.html:49
+#: models.py:415 templates/chimere/blocks/alternate_multimedia.html:49
msgid "Web address"
msgstr "Adresse web"
-#: models.py:342
+#: models.py:417
msgid "Don't forget the trailing slash"
msgstr "N'oubliez pas la barre oblique (« / ») finale"
-#: models.py:343
+#: models.py:419
msgid "Source file"
msgstr "Fichier source"
-#: models.py:345
+#: models.py:421
msgid "Alt source file"
msgstr "Fichier source alternatif"
-#: models.py:347
+#: models.py:422
msgid "Name by default"
msgstr "Nom par défaut"
-#: models.py:349
+#: models.py:424
msgid "SRID"
msgstr "SRID"
-#: models.py:350
+#: models.py:425
msgid "Zipped file"
msgstr "Fichier zippé"
-#: models.py:351
+#: models.py:426
msgid "Overwrite existing data"
msgstr "Écraser les données existantes"
-#: models.py:353
+#: models.py:428
msgid "Get description from source"
msgstr "Obtenir une description depuis la source"
-#: models.py:355
+#: models.py:430
msgid "Default description"
msgstr "Description par défaut"
-#: models.py:357 models.py:447
+#: models.py:432 models.py:520
msgid "Origin"
msgstr "Origine"
-#: models.py:359 models.py:449
+#: models.py:434 models.py:522
msgid "License"
msgstr "Licence"
-#: models.py:362
+#: models.py:438
msgid "Associated subcategories"
msgstr "Sous-catégories associées"
-#: models.py:363 utils.py:494
+#: models.py:439 utils.py:560
msgid "State"
msgstr "État"
-#: models.py:364
+#: models.py:441
msgid "Automatically associate a marker to a way"
msgstr "Associer automatiquement un marqueur à une route"
-#: models.py:366
+#: models.py:442
msgid "Automatically updated"
msgstr "Mis à jour automatiquement"
-#: models.py:368
+#: models.py:444
+msgid "Default status"
+msgstr "Statut par défaut"
+
+#: models.py:447
msgid "Default localisation"
msgstr "Localisation par défaut"
-#: models.py:374 models.py:408
+#: models.py:452 models.py:487
msgid "Importer"
msgstr "Import"
-#: models.py:411 models.py:437
+#: models.py:490 models.py:510
msgid "Import key"
msgstr "Clé d'import"
-#: models.py:414
+#: models.py:493
msgid "Importer - Key categories"
msgstr "Importeur - clés / catégories"
-#: models.py:416
-msgid "Submited"
-msgstr "Soumis"
-
-#: models.py:418
-msgid "Modified"
-msgstr "Modifié"
-
-#: models.py:419
-msgid "Disabled"
-msgstr "Désactivé"
-
-#: models.py:420
-msgid "Imported"
-msgstr "Importé"
-
-#: models.py:426
+#: models.py:500
msgid "Submitter session key"
msgstr "Clé de session du demandeur"
-#: models.py:428
+#: models.py:501
msgid "Submitter name or nickname"
msgstr "Nom ou pseudo du demandeur"
-#: models.py:430
+#: models.py:503
msgid "Submitter email"
msgstr "Courriel du demandeur"
-#: models.py:432
+#: models.py:505
msgid "Submitter comment"
msgstr "Commentaire du demandeur"
-#: models.py:434 models.py:1248
+#: models.py:507 models.py:1448
msgid "Status"
msgstr "État"
-#: models.py:439
+#: models.py:512
msgid "Import version"
msgstr "Version de l'import"
-#: models.py:441
+#: models.py:514
msgid "Source"
msgstr "Source"
-#: models.py:443
+#: models.py:517
msgid "Modified since last import"
msgstr "Modifié depuis le dernier import"
-#: models.py:445
+#: models.py:518
msgid "Not to be exported to OSM"
msgstr "À ne pas exporter vers OSM"
-#: models.py:451 templates/chimere/edit.html:63
+#: models.py:525 templates/chimere/edit.html:65
#: templates/chimere/edit_route.html:53
msgid "Start date"
msgstr "Date de début"
-#: models.py:452
+#: models.py:526
msgid "Not mandatory. Set it for dated item such as event. Format YYYY-MM-DD"
msgstr ""
"Optionnel. Précisez ce champ pour les éléments datés comme un événement. "
"Format du champ : AAAA-MM-JJ"
-#: models.py:454 templates/chimere/edit.html:69
+#: models.py:529 templates/chimere/edit.html:71
#: templates/chimere/edit_route.html:59
msgid "End date"
msgstr "Date de fin"
-#: models.py:455
+#: models.py:530
msgid ""
"Not mandatory. Set it only if you have a multi-day event. Format YYYY-MM-DD"
msgstr ""
"Optionnel. Précisez ce champ seulement pour des événements durant plusieurs "
"jours. Format du champ : AAAA-MM-JJ"
-#: models.py:512
+#: models.py:713
msgid "Reference marker"
msgstr "Point d'intérêt de référence"
-#: models.py:513 utils.py:496
+#: models.py:715 utils.py:562
msgid "Localisation"
msgstr "Localisation"
-#: models.py:515
+#: models.py:717
msgid "Available Date"
msgstr "Date de mise en disponibilité"
-#: models.py:519 utils.py:495 templates/admin/chimere/managed_modified.html:31
-#: templates/chimere/edit.html:50 templates/chimere/edit_route.html:47
+#: models.py:721 utils.py:561 templates/admin/chimere/managed_modified.html:31
+#: templates/chimere/edit.html:52 templates/chimere/edit_route.html:47
msgid "Description"
msgstr "Description"
-#: models.py:590 models.py:1597
+#: models.py:728 models.py:1862
msgid "Point of interest"
msgstr "Point d'intérêt"
-#: models.py:767
+#: models.py:891
+msgid "Reference polygon"
+msgstr "Polygone de référence"
+
+#: models.py:904
+msgid "Inner color"
+msgstr "Couleur intérieure"
+
+#: models.py:974
msgid "Audio"
msgstr "Audio"
-#: models.py:768
+#: models.py:975
msgid "Video"
msgstr "Vidéo"
-#: models.py:770
+#: models.py:977
msgid "Other"
msgstr "Autre"
-#: models.py:771
+#: models.py:978
msgid "Media type"
msgstr "Type de media"
-#: models.py:774
+#: models.py:981
msgid "Mime type"
msgstr "Type mime"
-#: models.py:776
+#: models.py:983
msgid "Inside an iframe"
msgstr "À l'intérieur d'un iframe"
-#: models.py:780
+#: models.py:987
msgid "Multimedia type"
msgstr "Type de multimedia"
-#: models.py:781
+#: models.py:988
msgid "Multimedia types"
msgstr "Types de multimedia"
-#: models.py:790
+#: models.py:997
msgid "Automatic recognition"
msgstr "Reconnaissance automatique"
-#: models.py:816
+#: models.py:1025
msgid "Extension name"
msgstr "Nom de l'extension"
-#: models.py:818
+#: models.py:1027
msgid "Associated multimedia type"
msgstr "Type de multimedia associé"
-#: models.py:822
+#: models.py:1031
msgid "Multimedia extension"
msgstr "Extension multimedia"
-#: models.py:823
+#: models.py:1032
msgid "Multimedia extensions"
msgstr "Extensions multimedia"
-#: models.py:833 models.py:893
+#: models.py:1044 models.py:1113
msgid "Display inside the description?"
msgstr "Apparaît dans la description ?"
-#: models.py:838
+#: models.py:1052
msgid "Multimedia file"
msgstr "Fichier multimedia"
-#: models.py:839
+#: models.py:1053
msgid "Multimedia files"
msgstr "Fichiers multimedias"
-#: models.py:895
+#: models.py:1116
msgid "Thumbnail"
msgstr "Miniature"
-#: models.py:899
+#: models.py:1118
msgid "Thumbnail height"
msgstr "Hauteur de la miniature"
-#: models.py:901
+#: models.py:1120
msgid "Thumbnail width"
msgstr "Largeur de la miniature"
-#: models.py:910
+#: models.py:1132
msgid "Picture file"
msgstr "Fichier d'image"
-#: models.py:911
+#: models.py:1133
msgid "Picture files"
msgstr "Fichiers d'image"
-#: models.py:1007
+#: models.py:1230
msgid "Raw file (gpx or kml)"
msgstr "Fichier brut (gpx ou kml)"
-#: models.py:1009
+#: models.py:1233
msgid "Simplified file"
msgstr "Fichier simplifié"
-#: models.py:1011
+#: models.py:1234
msgid "KML"
msgstr "KML"
-#: models.py:1011
+#: models.py:1234
msgid "GPX"
msgstr "GPX"
-#: models.py:1016
+#: models.py:1239
msgid "Route file"
msgstr "Fichier de trajet"
-#: models.py:1017
+#: models.py:1240
msgid "Route files"
msgstr "Fichiers de trajet"
-#: models.py:1067
+#: models.py:1289
msgid "Reference route"
msgstr "Trajet de référence"
-#: models.py:1071
+#: models.py:1294
msgid "Associated file"
msgstr "Fichier associé"
-#: models.py:1076
+#: models.py:1300
msgid "Has an associated marker"
msgstr "Dispose d'un marqueur associé"
-#: models.py:1357
+#: models.py:1587
msgid "Layer code"
msgstr "Code pour la couche"
-#: models.py:1363
+#: models.py:1593
msgid "Layer"
msgstr "Couche"
-#: models.py:1369
+#: models.py:1600
msgid "Area urn"
msgstr "Urn de la zone"
-#: models.py:1371 templates/chimere/blocks/welcome.html:3
+#: models.py:1602 templates/chimere/blocks/welcome.html:3
msgid "Welcome message"
msgstr "Message d'accueil"
-#: models.py:1375
+#: models.py:1607
msgid "Upper left corner"
msgstr "Coin en haut à gauche"
-#: models.py:1377
+#: models.py:1610
msgid "Lower right corner"
msgstr "Coin en bas à droite"
-#: models.py:1379
+#: models.py:1613
msgid "Default area"
msgstr "Zone par défaut"
-#: models.py:1380
+#: models.py:1613
msgid "Only one area is set by default"
msgstr "Seule une zone est définie par défaut"
-#: models.py:1384
+#: models.py:1618
msgid "Sub-categories checked by default"
msgstr "Sous-catégories cochées par défaut"
-#: models.py:1386
+#: models.py:1620
msgid "Sub-categories dynamicaly displayed"
msgstr "Sous-categories affichées dynamiquement"
-#: models.py:1387
+#: models.py:1621
msgid ""
"If checked, categories are only displayed in the menu if they are available "
"on the current extent."
@@ -754,76 +833,104 @@ msgstr ""
"Si coché, les catégories sont disponibles sur le menu seulement si elles "
"apparaissent sur la zone affichée."
-#: models.py:1391 models.py:1547
+#: models.py:1626 models.py:1808
msgid "Restricted to theses sub-categories"
msgstr "Restreindre à ces sous-categories"
-#: models.py:1392
+#: models.py:1627
msgid "If no sub-category is set all sub-categories are available"
msgstr ""
"Si aucune sous-catégorie n'est définie toutes les sous-catégories sont "
"disponibles"
-#: models.py:1394
+#: models.py:1630
+msgid "Display category menu"
+msgstr "Afficher le menu des catégories"
+
+#: models.py:1631
+msgid ""
+"If set to False, category menu will be hide and all categories will be "
+"always displayed."
+msgstr ""
+"Si mis à Faux, le meny des catégories sera caché et toutes les catégories "
+"seront toujours affichées."
+
+#: models.py:1633
msgid "Link to an external CSS"
msgstr "Lien vers une feuille de style externe"
-#: models.py:1396
+#: models.py:1635
msgid "Restrict to the area extent"
msgstr "Restreindre à l'étendue de la zone"
-#: models.py:1532 widgets.py:89
+#: models.py:1637
+msgid "Allow point edition"
+msgstr "Permetre l'édition de point"
+
+#: models.py:1639
+msgid "Allow route edition"
+msgstr "Permettre l'édition de trajet"
+
+#: models.py:1641
+msgid "Allow polygon edition"
+msgstr "Permettre l'édition de polygone"
+
+#: models.py:1790 widgets.py:90
msgid "Default layer"
msgstr "Couche par défaut"
-#: models.py:1536 models.py:1537
+#: models.py:1794 models.py:1795
msgid "Layers"
msgstr "Couches"
-#: models.py:1545
+#: models.py:1802
+msgid "Slug"
+msgstr "Identifiant textuel"
+
+#: models.py:1805
msgid "Mandatory"
msgstr "Obligatoire"
-#: models.py:1548
+#: models.py:1809
msgid ""
"If no sub-category is set all the property applies to all sub-categories"
msgstr ""
"Si aucune sous-catégorie n'est précisée, cette propriété est disponible pour "
"toutes les sous-catégories"
-#: models.py:1550
+#: models.py:1811
msgid "Text"
msgstr "Texte"
-#: models.py:1551
+#: models.py:1812
msgid "Long text"
msgstr "Texte long"
-#: models.py:1554
+#: models.py:1815
msgid "Choices"
msgstr "Choix"
-#: models.py:1555
+#: models.py:1816
msgid "Boolean"
msgstr "Booléen"
-#: models.py:1564
+#: models.py:1825
msgid "Type"
msgstr "Type"
-#: models.py:1569 models.py:1585 models.py:1599
+#: models.py:1829 models.py:1847 models.py:1866
msgid "Property model"
msgstr "Modèle de propriété"
-#: models.py:1586 models.py:1600
+#: models.py:1848 models.py:1867
msgid "Value"
msgstr "Valeur"
-#: models.py:1592
+#: models.py:1852
msgid "Model property choice"
msgstr "Choix pour les modèles de propriété"
-#: models.py:1611
+#: models.py:1881
msgid "Property"
msgstr "Propriété"
@@ -905,28 +1012,47 @@ msgstr "Export échoué"
msgid "Export canceled"
msgstr "Export annulé"
-#: utils.py:153 utils.py:202
+#: utils.py:169 utils.py:218
msgid "Bad zip file"
msgstr "Mauvais fichier zip"
-#: utils.py:205
+#: utils.py:221
msgid "Missing file(s) inside the zip file"
msgstr "Fichier(s) manquant(s) dans l'archive zip"
-#: utils.py:246
+#: utils.py:264
msgid "Bad XML file"
msgstr "Mauvais fichier XML"
-#: utils.py:333
+#: utils.py:356
msgid "Error while reading the data source."
msgstr "Erreur lors de la lecture de la source."
-#: utils.py:351
+#: utils.py:374
#, python-format
msgid "SRID cannot be guessed. The default SRID (%s) has been used."
msgstr "Le SRID n'a pu être trouvé. Le SRID par défaut (%s) a été utilisé."
-#: utils.py:372
+#: utils.py:389
+msgid "Bad configuration: filter must be a valid JSON string"
+msgstr ""
+"Erreur de configuration : lefiltre doit être une chaîne de caractère JSON"
+" valide"
+
+#: utils.py:395
+#, python-format
+msgid "The key \"%s\" is missing in the filter."
+msgstr "La clé \"%s\" est manquante dans le filtre."
+
+#: utils.py:403
+msgid ""
+"Config: {} is not an appropriate column name for this Shapefile. Available "
+"columns are: {}"
+msgstr ""
+"Configuration : {} n'est un nom de colonne approprié pour ce Shapefile. Les "
+"colonnes disponibles sont : {}"
+
+#: utils.py:429
#, python-format
msgid ""
"Type of geographic item (%s) of this shapefile is not managed by Chimère."
@@ -934,42 +1060,57 @@ msgstr ""
"Les types des éléments géographiques (%s) de ce fichier Shapefile ne sont "
"pas gérés par Chimère."
-#: utils.py:392
+#: utils.py:461
msgid "Bad Shapefile"
msgstr "Mauvais fichier Shapefile"
-#: utils.py:434
+#: utils.py:500
msgid "Could not create file!"
msgstr "Ne peut pas créer le fichier !"
-#: utils.py:445
+#: utils.py:511
msgid "Failed to create field"
msgstr "Ne peut pas créer un champ"
-#: utils.py:491 templates/admin/chimere/managed_modified.html:25
-#: templates/chimere/edit.html:45 templates/chimere/edit_route.html:42
+#: utils.py:558 templates/admin/chimere/managed_modified.html:25
+#: templates/chimere/edit.html:42 templates/chimere/edit_route.html:42
#: templates/chimere/main_map.html:16
#: templates/chimere/main_map_simple.html:10
msgid "Categories"
msgstr "Catégories"
-#: utils.py:524
+#: utils.py:590
msgid "Invalid CSV format"
-msgstr "Fichier CSV non valide"
+msgstr "CSV non valide"
-#: utils.py:603
+#: utils.py:671
msgid "RSS feed is not well formed"
msgstr "Flux RSS non valide"
-#: utils.py:679
+#: utils.py:743
+msgid "JSON file is not well formed: "
+msgstr "Fichier JSON non valide : "
+
+#: utils.py:750
+msgid "Bad configuration: filter field must be a valid JSON string"
+msgstr ""
+"Erreur de configuration : le champ filtre doit être un fichier JSON"
+" valide"
+
+#: utils.py:758
+#, python-format
+msgid "A key must be associated to \"%s\" in the filter."
+msgstr "Une clé doit être associée à \"%s\" dans le filtre."
+
+#: utils.py:849
msgid "Nothing to import"
msgstr "Rien à importer"
-#: utils.py:763
+#: utils.py:933
msgid "New items imported - validate them before exporting"
msgstr "Nouveaux éléments importés - valider ceux-ci avant d'exporter"
-#: utils.py:765
+#: utils.py:935
msgid ""
"There are items from a former import not yet validated - validate them "
"before exporting"
@@ -977,19 +1118,19 @@ msgstr ""
"Il y a des éléments d'un import précédent pas encore validé - Validez les "
"avant d'exporter"
-#: utils.py:777
+#: utils.py:947
msgid "Bad params - programming error"
msgstr "Mauvais paramètres - erreur de programmation"
-#: utils.py:787
+#: utils.py:957
msgid "Bad param"
msgstr "Mauvais paramètre"
-#: utils.py:802
+#: utils.py:972
msgid "No non ambigious tag is defined in the XAPI request"
msgstr "Pas de tag non ambigü définis dans la requête XAPI"
-#: utils.py:804
+#: utils.py:975
msgid ""
"No bounding box is defined in the XAPI request.If you are sure to manage the "
"entire planet set the bounding box to -180,-90,180,90"
@@ -998,19 +1139,19 @@ msgstr ""
"vouloir lancer la requête sur la planète entière fixez la « bounding box » "
"à -180,-90,180,90"
-#: utils.py:933
+#: utils.py:1109
msgid "Source page is unreachable."
msgstr "La page source est inatteignable"
-#: utils.py:949
+#: utils.py:1125
msgid "The source file is not a valid XSLT file."
msgstr "Le fichier source n'est pas un fichier XSLT valide"
-#: utils.py:961
+#: utils.py:1137
msgid "The alt source file is not a valid XSLT file."
msgstr "Le fichier source alternatif n'est pas un fichier XSLT valide"
-#: utils.py:1005
+#: utils.py:1182
#, python-format
msgid ""
"Names \"%s\" doesn't match existing categories. Modify the import to match "
@@ -1019,19 +1160,27 @@ msgstr ""
"Les noms \"%s\" ne correspondent pas à des catégories existantes. Modifiez "
"l'import pour faire correspondre ces noms avec des catégories."
-#: views.py:302
+#: utils.py:1297
+msgid "Error on icalendar parsing: "
+msgstr "Erreur de parsing icalendar"
+
+#: utils.py:1318
+msgid "Link"
+msgstr "Lien"
+
+#: views.py:319
msgid "There are missing field(s) and/or errors in the submited form."
msgstr "Il y a des champs manquants ou des erreurs dans ce formulaire."
-#: views.py:387
+#: views.py:407
msgid "Bad file. Please check it with an external software."
msgstr "Fichier incohérent. Merci de le vérifier avec un logiciel externe."
-#: views.py:502
+#: views.py:571
msgid "Comments/request on the map"
msgstr "Commentaires/requètes sur la carte"
-#: views.py:505
+#: views.py:574
msgid ""
"Thank you for your contribution. It will be taken into account. If you have "
"left your email you may be contacted soon for more details."
@@ -1040,60 +1189,60 @@ msgstr ""
"laissé votre courriel vous serez peut-être contacté bientôt pour plus de "
"détails."
-#: views.py:509
+#: views.py:578
msgid "Temporary error. Renew your message later."
msgstr "Erreur temporaire. Réenvoyez votre message plus tard."
-#: views.py:715
+#: views.py:830
msgid "No category available in this area."
msgstr "Pas de catégorie disponible sur cette zone."
-#: views.py:842
+#: views.py:963
msgid "Category does not exist"
msgstr "Cette catégorie n'existe pas"
-#: views.py:900
+#: views.py:1024
msgid "Bad geometry"
msgstr "Géométrie incorrecte"
-#: views.py:985
+#: views.py:1110
msgid "Incorrect choice in the list"
msgstr "Choix incorrect dans la liste"
-#: widgets.py:243
+#: widgets.py:271
msgid "Street, City, Country"
msgstr "Rue, Commune, Pays"
-#: widgets.py:281
+#: widgets.py:327
msgid "Latitude"
msgstr "Latitude"
-#: widgets.py:283
+#: widgets.py:329
msgid "Longitude"
msgstr "Longitude"
-#: widgets.py:326
+#: widgets.py:377
msgid "Invalid point"
msgstr "Point invalide"
-#: widgets.py:382
+#: widgets.py:441
msgid "Creation mode"
msgstr "Mode création"
-#: widgets.py:383
+#: widgets.py:442
msgid "To start drawing the route click on the toggle button: \"Draw\"."
msgstr ""
"Pour commencer le dessin cliquez sur le bouton&nbsp;: «&nbsp;Tracer&nbsp;»."
-#: widgets.py:385
+#: widgets.py:444
msgid "Then click on the map to begin the drawing."
msgstr "Puis cliquez sur la carte pour commencer le dessin."
-#: widgets.py:386
+#: widgets.py:445
msgid "You can add points by clicking again."
msgstr "Vous pouvez ajouter des points en cliquant de nouveau."
-#: widgets.py:387
+#: widgets.py:446
msgid ""
"To finish the drawing double click. When the drawing is finished you can "
"edit it."
@@ -1101,7 +1250,7 @@ msgstr ""
"Pour finir le tracé double-cliquez. Quand le tracé est fini vous pouvez "
"toujours l'éditer."
-#: widgets.py:389
+#: widgets.py:448
msgid ""
"While creating to undo a drawing click again on the toggle button \"Stop "
"drawing\"."
@@ -1109,17 +1258,17 @@ msgstr ""
"En mode création vous pouvez annuler un tracé en appuyant sur le bouton "
"«&nbsp;Arrêter le tracé&nbsp;»."
-#: widgets.py:394
+#: widgets.py:454
msgid "Modification mode"
msgstr "Mode modification"
-#: widgets.py:395
+#: widgets.py:455
msgid "To move a point click on it and drag it to the desired position."
msgstr ""
"Pour bouger un point, cliquez dessus, maintenez le click pour le déposer à "
"la position désirée."
-#: widgets.py:396
+#: widgets.py:457
msgid ""
"To delete a point move the mouse cursor over it and press the \"d\" or \"Del"
"\" key."
@@ -1127,7 +1276,7 @@ msgstr ""
"Pour supprimer un point, mettez le curseur de la souris sur celui-ci et "
"appuyez sur le touche «&nbsp;d&nbsp;» ou «&nbsp;Suppr&nbsp;»."
-#: widgets.py:398
+#: widgets.py:459
msgid ""
"To add a point click in the middle of a segment and drag the new point to "
"the desired position"
@@ -1136,51 +1285,51 @@ msgstr ""
"maintenez le bouton appuyé et déplacez le nouveau point à la position "
"désirée."
-#: widgets.py:405
+#: widgets.py:466
msgid "Give a name and set category before uploading a file."
msgstr ""
"Renseignez le nom et choisissez au moins une catégorie avant de déposer un "
"fichier."
-#: widgets.py:408
+#: widgets.py:469
msgid "Upload a route file (GPX or KML)"
msgstr "Déposer un trajet (fichier GPX ou KML)"
-#: widgets.py:409
+#: widgets.py:470
msgid "or"
msgstr "ou"
-#: widgets.py:414
+#: widgets.py:475
msgid "Start \"hand\" drawing"
msgstr "Commencer le tracé manuellement"
-#: widgets.py:437
+#: widgets.py:499
msgid "Move on the map"
msgstr "Se déplacer"
-#: widgets.py:437
+#: widgets.py:499
msgid "Draw"
msgstr "Tracer"
-#: widgets.py:527
+#: widgets.py:592
msgid "Hold CTRL, click and drag to select area on the map"
msgstr ""
"Maintenir la touche Control, cliquez puis glissez pour sélectionner une zone "
"sur la carte"
-#: widgets.py:584
+#: widgets.py:697
msgid "Type:"
msgstr "Type :"
-#: widgets.py:584
+#: widgets.py:697
msgid "Node"
msgstr "Nœud"
-#: widgets.py:585
+#: widgets.py:698
msgid "Way"
msgstr "Route"
-#: widgets.py:596
+#: widgets.py:711
msgid ""
"Enter an OSM \"tag=value\" string such as \"amenity=pub\". A list of common "
"tag is available <a href='https://wiki.openstreetmap.org/wiki/Map_Features' "
@@ -1190,39 +1339,39 @@ msgstr ""
"liste des clés est disponible <a href='https://wiki.openstreetmap.org/wiki/"
"FR:Map_Features' target='_blank'>ici</a>."
-#: widgets.py:603
+#: widgets.py:718
msgid "Tag:"
msgstr "Clé/valeur :"
-#: widgets.py:607
+#: widgets.py:722
msgid "You have to select an area."
msgstr "Vous devez sélectionner une zone."
-#: widgets.py:609
+#: widgets.py:724
msgid "You have to select a type."
msgstr "Vous devez sélectionner un type."
-#: widgets.py:611
+#: widgets.py:726
msgid "You have to insert a filter tag."
msgstr "Vous devez saisir une clé=valeur."
-#: widgets.py:613
+#: widgets.py:728
msgid "If you change the above form don't forget to refresh before submit!"
msgstr ""
"Si vous modifiez le formulaire ci-dessus n'oubliez pas de rafraîchir avant "
"de valider !"
-#: widgets.py:616
+#: widgets.py:731
msgid "You can put a Folder name of the KML file to filter on it."
msgstr ""
"Vous pouvez saisir le nom d'un « Folder » du fichier KML pour filter sur "
"celui-ci."
-#: widgets.py:624
+#: widgets.py:739
msgid "Refresh"
msgstr "Rafraîchir"
-#: widgets.py:690
+#: widgets.py:808
msgid "Select..."
msgstr "Sélectionner..."
@@ -1372,6 +1521,10 @@ msgstr ""
msgid "Submit"
msgstr "Proposer"
+#: templates/chimere/detail.html:24 templates/chimere/feeds/rss_descr.html:8
+msgid ":"
+msgstr " :"
+
#: templates/chimere/detail.html:29
msgid "Show multimedia gallery"
msgstr "Montrer la galerie multimedia"
@@ -1396,23 +1549,23 @@ msgstr "Modifier un point d'intérêt"
msgid "Add a point of interest"
msgstr "Ajout d'un point d'intérêt"
-#: templates/chimere/edit.html:31
+#: templates/chimere/edit.html:32
msgid "Point"
msgstr "Point"
-#: templates/chimere/edit.html:32 templates/chimere/edit_route.html:29
+#: templates/chimere/edit.html:33 templates/chimere/edit_route.html:29
msgid "Select a location for this new site"
msgstr "Choisissez une localisation pour ce nouveau site"
-#: templates/chimere/edit.html:38 templates/chimere/edit_route.html:35
+#: templates/chimere/edit.html:40 templates/chimere/edit_route.html:35
msgid "indicates a mandatory field"
msgstr "indique un champ obligatoire"
-#: templates/chimere/edit.html:120
+#: templates/chimere/edit.html:122
msgid "Personal information"
msgstr "Informations personnelles"
-#: templates/chimere/edit.html:122
+#: templates/chimere/edit.html:124
msgid ""
"This fields are not mandatory. If you provided them they not will be made "
"public and they will only used to join you for this project."
@@ -1421,26 +1574,38 @@ msgstr ""
"pas publiés et ne seront utilisés seulement pour vous joindre dans le cadre "
"de ce projet."
-#: templates/chimere/edit.html:125
+#: templates/chimere/edit.html:127
msgid "Your name or nickname"
msgstr "Votre nom ou pseudo"
-#: templates/chimere/edit.html:130
+#: templates/chimere/edit.html:132
msgid "Your email"
msgstr "Votre courriel"
-#: templates/chimere/edit.html:135
+#: templates/chimere/edit.html:137
msgid "Comments about your submission"
msgstr "Commentaires au sujet de votre proposition"
-#: templates/chimere/edit.html:141
+#: templates/chimere/edit.html:143
msgid "Upload in progress. Please wait..."
msgstr "Dépôt en cours. Veuillez patienter..."
-#: templates/chimere/edit.html:159 templates/chimere/edit_route.html:78
+#: templates/chimere/edit.html:161 templates/chimere/edit_route.html:78
msgid "Propose"
msgstr "Proposez"
+#: templates/chimere/edit_polygon.html:5
+msgid "Modify a polygon"
+msgstr "Modifier un polygone"
+
+#: templates/chimere/edit_polygon.html:5
+msgid "Add a polygon"
+msgstr "Ajouter un polygone"
+
+#: templates/chimere/edit_polygon.html:10
+msgid "Draw the associated polygon"
+msgstr "Dessine le polygone associé"
+
#: templates/chimere/edit_route.html:22
msgid "Modify a route"
msgstr "Modifier un trajet"
@@ -1603,6 +1768,10 @@ msgstr ""
msgid "See it on the map"
msgstr "Voir sur la carte"
+#: templates/chimere/blocks/polygon_edit.html:22
+msgid "To delete a vertice, hold the SHIFT key and click."
+msgstr "Pour supprimer un sommet laisse appuyé la touche MAJ et cliquez."
+
#: templates/chimere/blocks/routing.html:5
msgid "Itinerary"
msgstr "Itinéraire"
@@ -1707,10 +1876,6 @@ msgstr "Ou sélectionner une zone en zoomant et en se déplaçant sur cette cart
msgid "Description:"
msgstr "Description :"
-#: templates/chimere/feeds/rss_descr.html:8
-msgid ":"
-msgstr " :"
-
#: templates/search/search.html:3
msgid "Do you mean: "
msgstr "Voulez-vous dire :"
@@ -1735,7 +1900,7 @@ msgstr "Plus de résultats..."
msgid "No exact match."
msgstr "Pas de correspondance exacte."
-#: templatetags/chimere_tags.py:93
+#: templatetags/chimere_tags.py:99
#, python-format
msgid "Welcome to the %s"
msgstr "Bienvenue sur %s"
diff --git a/chimere/managers.py b/chimere/managers.py
index 89aa35f..807b493 100644
--- a/chimere/managers.py
+++ b/chimere/managers.py
@@ -1,14 +1,13 @@
# -*- coding: utf-8 -*-
-import sys
-from django.contrib.gis.db import models
-
-from logging import getLogger
-from datetime import datetime, date, timedelta
+from datetime import date, timedelta
+from django.contrib.gis.db import models
from django.conf import settings
# BASE
+
+
class BaseGeoQuerySet(models.query.QuerySet):
"""
Custom queryset for Geo objects.
@@ -16,11 +15,11 @@ class BaseGeoQuerySet(models.query.QuerySet):
def available(self):
""" Chainable filter to retrieve only available elements. """
return self.filter(status="A")
-
+
def submited(self):
""" Chainable filter to retrieve only submited elements. """
return self.filter(status="S")
-
+
def active(self):
"""
Returns objects where within the active date period of events.
@@ -31,7 +30,8 @@ class BaseGeoQuerySet(models.query.QuerySet):
today = date.today()
after = today + timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)
return self.filter(end_date__gte=today, start_date__lte=after)
-
+
+
class BaseGeoManager(models.GeoManager):
"""
Custom base manager for Geo objects.
@@ -39,14 +39,14 @@ class BaseGeoManager(models.GeoManager):
def get_query_set(self):
""" Use our custom QuerySet. """
return BaseGeoQuerySet(self.model)
-
+
# Methods defined in the queryset that we also want exposed in the
# It would be nice to implement it with a magic method instead, later :)
def available(self):
return self.get_query_set().available()
-
+
def submited(self):
return self.get_query_set().submited()
-
+
def active(self):
return self.get_query_set().active()
diff --git a/chimere/migrations/0015_auto__add_field_icon_offset_x__add_field_icon_offset_y.py b/chimere/migrations/0015_auto__add_field_icon_offset_x__add_field_icon_offset_y.py
new file mode 100644
index 0000000..8e8e794
--- /dev/null
+++ b/chimere/migrations/0015_auto__add_field_icon_offset_x__add_field_icon_offset_y.py
@@ -0,0 +1,302 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Icon.offset_x'
+ db.add_column('chimere_icon', 'offset_x',
+ self.gf('django.db.models.fields.IntegerField')(default=10),
+ keep_default=False)
+
+ # Adding field 'Icon.offset_y'
+ db.add_column('chimere_icon', 'offset_y',
+ self.gf('django.db.models.fields.IntegerField')(default=25),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Icon.offset_x'
+ db.delete_column('chimere_icon', 'offset_x')
+
+ # Deleting field 'Icon.offset_y'
+ db.delete_column('chimere_icon', 'offset_y')
+
+
+ models = {
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '25'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0016_auto__add_field_icon_popup_offset_x__add_field_icon_popup_offset_y.py b/chimere/migrations/0016_auto__add_field_icon_popup_offset_x__add_field_icon_popup_offset_y.py
new file mode 100644
index 0000000..0374cfc
--- /dev/null
+++ b/chimere/migrations/0016_auto__add_field_icon_popup_offset_x__add_field_icon_popup_offset_y.py
@@ -0,0 +1,304 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Icon.popup_offset_x'
+ db.add_column('chimere_icon', 'popup_offset_x',
+ self.gf('django.db.models.fields.IntegerField')(default=20),
+ keep_default=False)
+
+ # Adding field 'Icon.popup_offset_y'
+ db.add_column('chimere_icon', 'popup_offset_y',
+ self.gf('django.db.models.fields.IntegerField')(default=50),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Icon.popup_offset_x'
+ db.delete_column('chimere_icon', 'popup_offset_x')
+
+ # Deleting field 'Icon.popup_offset_y'
+ db.delete_column('chimere_icon', 'popup_offset_y')
+
+
+ models = {
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '25'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '50'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0015_auto__add_subcategoryuserlimit.py b/chimere/migrations/0017_auto__add_subcategoryuserlimit.py
index e24663a..9ae257c 100644
--- a/chimere/migrations/0015_auto__add_subcategoryuserlimit.py
+++ b/chimere/migrations/0017_auto__add_subcategoryuserlimit.py
@@ -11,8 +11,8 @@ class Migration(SchemaMigration):
# Adding model 'SubCategoryUserLimit'
db.create_table('chimere_subcategoryuserlimit', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
- ('subcategory', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['chimere.SubCategory'])),
- ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('subcategory', self.gf('django.db.models.fields.related.ForeignKey')(related_name='limited_for_user', to=orm['chimere.SubCategory'])),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='subcategory_limit_to', to=orm['auth.User'])),
))
db.send_create_signal('chimere', ['SubCategoryUserLimit'])
@@ -111,6 +111,10 @@ class Migration(SchemaMigration):
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
'width': ('django.db.models.fields.IntegerField', [], {})
},
'chimere.importer': {
@@ -317,8 +321,8 @@ class Migration(SchemaMigration):
'chimere.subcategoryuserlimit': {
'Meta': {'object_name': 'SubCategoryUserLimit'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
- 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
},
'chimere.tinyurl': {
'Meta': {'object_name': 'TinyUrl'},
diff --git a/chimere/migrations/0018_auto__add_polygon.py b/chimere/migrations/0018_auto__add_polygon.py
new file mode 100644
index 0000000..7fed4f0
--- /dev/null
+++ b/chimere/migrations/0018_auto__add_polygon.py
@@ -0,0 +1,397 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'Polygon'
+ db.create_table('chimere_polygon', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=150)),
+ ('submiter_session_key', self.gf('django.db.models.fields.CharField')(max_length=40, null=True, blank=True)),
+ ('submiter_name', self.gf('django.db.models.fields.CharField')(max_length=40, null=True, blank=True)),
+ ('submiter_email', self.gf('django.db.models.fields.EmailField')(max_length=75, null=True, blank=True)),
+ ('submiter_comment', self.gf('django.db.models.fields.TextField')(max_length=200, null=True, blank=True)),
+ ('status', self.gf('django.db.models.fields.CharField')(max_length=1)),
+ ('keywords', self.gf('django.db.models.fields.TextField')(max_length=200, null=True, blank=True)),
+ ('import_key', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True)),
+ ('import_version', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('import_source', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True)),
+ ('modified_since_import', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('not_for_osm', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('origin', self.gf('django.db.models.fields.CharField')(max_length=1000, null=True, blank=True)),
+ ('license', self.gf('django.db.models.fields.CharField')(max_length=1000, null=True, blank=True)),
+ ('start_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)),
+ ('end_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)),
+ ('ref_item', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='submited_polygon', null=True, to=orm['chimere.Polygon'])),
+ ('polygon', self.gf('chimere.widgets.PolygonField')()),
+ ('picture', self.gf('django.db.models.fields.files.ImageField')(max_length=100, null=True, blank=True)),
+ ('height', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ('width', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('chimere', ['Polygon'])
+
+ # Adding M2M table for field categories on 'Polygon'
+ db.create_table('chimere_polygon_categories', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('polygon', models.ForeignKey(orm['chimere.polygon'], null=False)),
+ ('subcategory', models.ForeignKey(orm['chimere.subcategory'], null=False))
+ ))
+ db.create_unique('chimere_polygon_categories', ['polygon_id', 'subcategory_id'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'Polygon'
+ db.delete_table('chimere_polygon')
+
+ # Removing M2M table for field categories on 'Polygon'
+ db.delete_table('chimere_polygon_categories')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0016_auto__chg_field_marker_name__chg_field_route_name.py b/chimere/migrations/0019_auto__chg_field_marker_name__chg_field_polygon_name__chg_field_route_n.py
index 19859fa..67156d7 100644
--- a/chimere/migrations/0016_auto__chg_field_marker_name__chg_field_route_name.py
+++ b/chimere/migrations/0019_auto__chg_field_marker_name__chg_field_polygon_name__chg_field_route_n.py
@@ -12,6 +12,9 @@ class Migration(SchemaMigration):
# Changing field 'Marker.name'
db.alter_column('chimere_marker', 'name', self.gf('django.db.models.fields.TextField')())
+ # Changing field 'Polygon.name'
+ db.alter_column('chimere_polygon', 'name', self.gf('django.db.models.fields.TextField')())
+
# Changing field 'Route.name'
db.alter_column('chimere_route', 'name', self.gf('django.db.models.fields.TextField')())
@@ -20,6 +23,9 @@ class Migration(SchemaMigration):
# Changing field 'Marker.name'
db.alter_column('chimere_marker', 'name', self.gf('django.db.models.fields.CharField')(max_length=150))
+ # Changing field 'Polygon.name'
+ db.alter_column('chimere_polygon', 'name', self.gf('django.db.models.fields.CharField')(max_length=150))
+
# Changing field 'Route.name'
db.alter_column('chimere_route', 'name', self.gf('django.db.models.fields.CharField')(max_length=150))
@@ -112,6 +118,10 @@ class Migration(SchemaMigration):
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
'width': ('django.db.models.fields.IntegerField', [], {})
},
'chimere.importer': {
@@ -203,7 +213,7 @@ class Migration(SchemaMigration):
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
'chimere.news': {
- 'Meta': {'object_name': 'News'},
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'content': ('django.db.models.fields.TextField', [], {}),
@@ -214,7 +224,7 @@ class Migration(SchemaMigration):
'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
},
'chimere.page': {
- 'Meta': {'object_name': 'Page'},
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
@@ -237,6 +247,32 @@ class Migration(SchemaMigration):
'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
'chimere.property': {
'Meta': {'object_name': 'Property'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
diff --git a/chimere/migrations/0017_auto__add_unique_tinyurl_parameters.py b/chimere/migrations/0020_auto__add_unique_tinyurl_parameters.py
index 502628a..3c2d65a 100644
--- a/chimere/migrations/0017_auto__add_unique_tinyurl_parameters.py
+++ b/chimere/migrations/0020_auto__add_unique_tinyurl_parameters.py
@@ -106,6 +106,10 @@ class Migration(SchemaMigration):
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
'width': ('django.db.models.fields.IntegerField', [], {})
},
'chimere.importer': {
@@ -197,7 +201,7 @@ class Migration(SchemaMigration):
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
'chimere.news': {
- 'Meta': {'object_name': 'News'},
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'content': ('django.db.models.fields.TextField', [], {}),
@@ -208,7 +212,7 @@ class Migration(SchemaMigration):
'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
},
'chimere.page': {
- 'Meta': {'object_name': 'Page'},
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
@@ -231,6 +235,32 @@ class Migration(SchemaMigration):
'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
'chimere.property': {
'Meta': {'object_name': 'Property'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
diff --git a/chimere/migrations/0021_auto__add_field_polygon_color__add_field_polygon_inner_color__add_fiel.py b/chimere/migrations/0021_auto__add_field_polygon_color__add_field_polygon_inner_color__add_fiel.py
new file mode 100644
index 0000000..afc59fc
--- /dev/null
+++ b/chimere/migrations/0021_auto__add_field_polygon_color__add_field_polygon_inner_color__add_fiel.py
@@ -0,0 +1,389 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Polygon.color'
+ db.add_column('chimere_polygon', 'color',
+ self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Polygon.inner_color'
+ db.add_column('chimere_polygon', 'inner_color',
+ self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Route.color'
+ db.add_column('chimere_route', 'color',
+ self.gf('django.db.models.fields.CharField')(max_length=20, null=True, blank=True),
+ keep_default=False)
+
+
+ # Changing field 'Color.code'
+ db.alter_column('chimere_color', 'code', self.gf('django.db.models.fields.CharField')(max_length=20))
+
+ def backwards(self, orm):
+ # Deleting field 'Polygon.color'
+ db.delete_column('chimere_polygon', 'color')
+
+ # Deleting field 'Polygon.inner_color'
+ db.delete_column('chimere_polygon', 'inner_color')
+
+ # Deleting field 'Route.color'
+ db.delete_column('chimere_route', 'color')
+
+
+ # Changing field 'Color.code'
+ db.alter_column('chimere_color', 'code', self.gf('django.db.models.fields.CharField')(max_length=6))
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0022_auto__chg_field_polygon_color__chg_field_polygon_inner_color__chg_fiel.py b/chimere/migrations/0022_auto__chg_field_polygon_color__chg_field_polygon_inner_color__chg_fiel.py
new file mode 100644
index 0000000..66fc6bb
--- /dev/null
+++ b/chimere/migrations/0022_auto__chg_field_polygon_color__chg_field_polygon_inner_color__chg_fiel.py
@@ -0,0 +1,383 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Changing field 'Polygon.color'
+ db.alter_column('chimere_polygon', 'color', self.gf('django.db.models.fields.CharField')(max_length=200, null=True))
+
+ # Changing field 'Polygon.inner_color'
+ db.alter_column('chimere_polygon', 'inner_color', self.gf('django.db.models.fields.CharField')(max_length=200, null=True))
+
+ # Changing field 'Route.color'
+ db.alter_column('chimere_route', 'color', self.gf('django.db.models.fields.CharField')(max_length=200, null=True))
+
+ # Changing field 'Color.code'
+ db.alter_column('chimere_color', 'code', self.gf('django.db.models.fields.CharField')(max_length=200))
+
+ def backwards(self, orm):
+
+ # Changing field 'Polygon.color'
+ db.alter_column('chimere_polygon', 'color', self.gf('django.db.models.fields.CharField')(max_length=20, null=True))
+
+ # Changing field 'Polygon.inner_color'
+ db.alter_column('chimere_polygon', 'inner_color', self.gf('django.db.models.fields.CharField')(max_length=20, null=True))
+
+ # Changing field 'Route.color'
+ db.alter_column('chimere_route', 'color', self.gf('django.db.models.fields.CharField')(max_length=20, null=True))
+
+ # Changing field 'Color.code'
+ db.alter_column('chimere_color', 'code', self.gf('django.db.models.fields.CharField')(max_length=20))
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0023_auto__add_field_area_allow_point_edition__add_field_area_allow_route_e.py b/chimere/migrations/0023_auto__add_field_area_allow_point_edition__add_field_area_allow_route_e.py
new file mode 100644
index 0000000..7446f0c
--- /dev/null
+++ b/chimere/migrations/0023_auto__add_field_area_allow_point_edition__add_field_area_allow_route_e.py
@@ -0,0 +1,386 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Area.allow_point_edition'
+ db.add_column('chimere_area', 'allow_point_edition',
+ self.gf('django.db.models.fields.BooleanField')(default=True),
+ keep_default=False)
+
+ # Adding field 'Area.allow_route_edition'
+ db.add_column('chimere_area', 'allow_route_edition',
+ self.gf('django.db.models.fields.BooleanField')(default=True),
+ keep_default=False)
+
+ # Adding field 'Area.allow_polygon_edition'
+ db.add_column('chimere_area', 'allow_polygon_edition',
+ self.gf('django.db.models.fields.BooleanField')(default=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Area.allow_point_edition'
+ db.delete_column('chimere_area', 'allow_point_edition')
+
+ # Deleting field 'Area.allow_route_edition'
+ db.delete_column('chimere_area', 'allow_route_edition')
+
+ # Deleting field 'Area.allow_polygon_edition'
+ db.delete_column('chimere_area', 'allow_polygon_edition')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0024_auto__add_field_picturefile_polygon__chg_field_picturefile_marker__add.py b/chimere/migrations/0024_auto__add_field_picturefile_polygon__chg_field_picturefile_marker__add.py
new file mode 100644
index 0000000..7a83c9e
--- /dev/null
+++ b/chimere/migrations/0024_auto__add_field_picturefile_polygon__chg_field_picturefile_marker__add.py
@@ -0,0 +1,392 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'PictureFile.polygon'
+ db.add_column('chimere_picturefile', 'polygon',
+ self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='pictures', null=True, to=orm['chimere.Polygon']),
+ keep_default=False)
+
+
+ # Changing field 'PictureFile.marker'
+ db.alter_column('chimere_picturefile', 'marker_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['chimere.Marker']))
+ # Adding field 'MultimediaFile.polygon'
+ db.add_column('chimere_multimediafile', 'polygon',
+ self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='multimedia_files', null=True, to=orm['chimere.Polygon']),
+ keep_default=False)
+
+
+ # Changing field 'MultimediaFile.marker'
+ db.alter_column('chimere_multimediafile', 'marker_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['chimere.Marker']))
+
+ def backwards(self, orm):
+ # Deleting field 'PictureFile.polygon'
+ db.delete_column('chimere_picturefile', 'polygon_id')
+
+
+ # User chose to not deal with backwards NULL issues for 'PictureFile.marker'
+ raise RuntimeError("Cannot reverse this migration. 'PictureFile.marker' and its values cannot be restored.")
+ # Deleting field 'MultimediaFile.polygon'
+ db.delete_column('chimere_multimediafile', 'polygon_id')
+
+
+ # User chose to not deal with backwards NULL issues for 'MultimediaFile.marker'
+ raise RuntimeError("Cannot reverse this migration. 'MultimediaFile.marker' and its values cannot be restored.")
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0025_auto__add_field_area_display_category_menu.py b/chimere/migrations/0025_auto__add_field_area_display_category_menu.py
new file mode 100644
index 0000000..6126fca
--- /dev/null
+++ b/chimere/migrations/0025_auto__add_field_area_display_category_menu.py
@@ -0,0 +1,373 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Area.display_category_menu'
+ db.add_column('chimere_area', 'display_category_menu',
+ self.gf('django.db.models.fields.BooleanField')(default=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Area.display_category_menu'
+ db.delete_column('chimere_area', 'display_category_menu')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0026_auto__add_field_propertymodel_slug.py b/chimere/migrations/0026_auto__add_field_propertymodel_slug.py
new file mode 100644
index 0000000..b20e5cb
--- /dev/null
+++ b/chimere/migrations/0026_auto__add_field_propertymodel_slug.py
@@ -0,0 +1,378 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+from django.template import defaultfilters
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'PropertyModel.slug'
+ db.add_column('chimere_propertymodel', 'slug',
+ self.gf('django.db.models.fields.SlugField')(max_length=50, null=True, blank=True),
+ keep_default=False)
+ for pm in orm.PropertyModel.objects.all():
+ pm.slug = defaultfilters.slugify(pm.name)
+ pm.save()
+
+
+ def backwards(self, orm):
+ # Deleting field 'PropertyModel.slug'
+ db.delete_column('chimere_propertymodel', 'slug')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere']
diff --git a/chimere/migrations/0027_auto__add_field_property_polygon__chg_field_property_marker.py b/chimere/migrations/0027_auto__add_field_property_polygon__chg_field_property_marker.py
new file mode 100644
index 0000000..59d8983
--- /dev/null
+++ b/chimere/migrations/0027_auto__add_field_property_polygon__chg_field_property_marker.py
@@ -0,0 +1,381 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Property.polygon'
+ db.add_column('chimere_property', 'polygon',
+ self.gf('django.db.models.fields.related.ForeignKey')(to=orm['chimere.Polygon'], null=True, blank=True),
+ keep_default=False)
+
+
+ # Changing field 'Property.marker'
+ db.alter_column('chimere_property', 'marker_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['chimere.Marker'], null=True))
+
+ def backwards(self, orm):
+ # Deleting field 'Property.polygon'
+ db.delete_column('chimere_property', 'polygon_id')
+
+
+ # User chose to not deal with backwards NULL issues for 'Property.marker'
+ raise RuntimeError("Cannot reverse this migration. 'Property.marker' and its values cannot be restored.")
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0028_auto__add_field_area_extra_map_def.py b/chimere/migrations/0028_auto__add_field_area_extra_map_def.py
new file mode 100644
index 0000000..64a5ae7
--- /dev/null
+++ b/chimere/migrations/0028_auto__add_field_area_extra_map_def.py
@@ -0,0 +1,376 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Area.extra_map_def'
+ db.add_column('chimere_area', 'extra_map_def',
+ self.gf('django.db.models.fields.TextField')(null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Area.extra_map_def'
+ db.delete_column('chimere_area', 'extra_map_def')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0029_auto__add_field_layer_extra_js_code__chg_field_layer_layer_code.py b/chimere/migrations/0029_auto__add_field_layer_extra_js_code__chg_field_layer_layer_code.py
new file mode 100644
index 0000000..36c48fc
--- /dev/null
+++ b/chimere/migrations/0029_auto__add_field_layer_extra_js_code__chg_field_layer_layer_code.py
@@ -0,0 +1,383 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Layer.extra_js_code'
+ db.add_column('chimere_layer', 'extra_js_code',
+ self.gf('django.db.models.fields.TextField')(default='', null=True, blank=True),
+ keep_default=False)
+
+
+ # Changing field 'Layer.layer_code'
+ db.alter_column('chimere_layer', 'layer_code', self.gf('django.db.models.fields.TextField')())
+
+ def backwards(self, orm):
+ # Deleting field 'Layer.extra_js_code'
+ db.delete_column('chimere_layer', 'extra_js_code')
+
+
+ # Changing field 'Layer.layer_code'
+ db.alter_column('chimere_layer', 'layer_code', self.gf('django.db.models.fields.TextField')(max_length=300))
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0030_auto.py b/chimere/migrations/0030_auto.py
new file mode 100644
index 0000000..19291e8
--- /dev/null
+++ b/chimere/migrations/0030_auto.py
@@ -0,0 +1,381 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding M2M table for field areas on 'PropertyModel'
+ db.create_table('chimere_propertymodel_areas', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('propertymodel', models.ForeignKey(orm['chimere.propertymodel'], null=False)),
+ ('area', models.ForeignKey(orm['chimere.area'], null=False))
+ ))
+ db.create_unique('chimere_propertymodel_areas', ['propertymodel_id', 'area_id'])
+
+
+ def backwards(self, orm):
+ # Removing M2M table for field areas on 'PropertyModel'
+ db.delete_table('chimere_propertymodel_areas')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0031_auto__add_field_marker_weight__add_field_marker_normalised_weight__add.py b/chimere/migrations/0031_auto__add_field_marker_weight__add_field_marker_normalised_weight__add.py
new file mode 100644
index 0000000..39e21ce
--- /dev/null
+++ b/chimere/migrations/0031_auto__add_field_marker_weight__add_field_marker_normalised_weight__add.py
@@ -0,0 +1,433 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Marker.weight'
+ db.add_column('chimere_marker', 'weight',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Marker.normalised_weight'
+ db.add_column('chimere_marker', 'normalised_weight',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'SubCategory.weight_formula'
+ db.add_column('chimere_subcategory', 'weight_formula',
+ self.gf('django.db.models.fields.TextField')(default='', null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Polygon.weight'
+ db.add_column('chimere_polygon', 'weight',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Polygon.normalised_weight'
+ db.add_column('chimere_polygon', 'normalised_weight',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Route.weight'
+ db.add_column('chimere_route', 'weight',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Route.normalised_weight'
+ db.add_column('chimere_route', 'normalised_weight',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Marker.weight'
+ db.delete_column('chimere_marker', 'weight')
+
+ # Deleting field 'Marker.normalised_weight'
+ db.delete_column('chimere_marker', 'normalised_weight')
+
+ # Deleting field 'SubCategory.weight_formula'
+ db.delete_column('chimere_subcategory', 'weight_formula')
+
+ # Deleting field 'Polygon.weight'
+ db.delete_column('chimere_polygon', 'weight')
+
+ # Deleting field 'Polygon.normalised_weight'
+ db.delete_column('chimere_polygon', 'normalised_weight')
+
+ # Deleting field 'Route.weight'
+ db.delete_column('chimere_route', 'weight')
+
+ # Deleting field 'Route.normalised_weight'
+ db.delete_column('chimere_route', 'normalised_weight')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'weight_formula': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0032_create_aggregate_polygon_view.py b/chimere/migrations/0032_create_aggregate_polygon_view.py
new file mode 100644
index 0000000..51eacd5
--- /dev/null
+++ b/chimere/migrations/0032_create_aggregate_polygon_view.py
@@ -0,0 +1,404 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ sql = """
+ create view chimere_aggregated_polygons (id, subcategory_id, status, polygon) as
+ SELECT row_number()
+ OVER (ORDER BY "chimere_polygon_categories"."subcategory_id",
+ "chimere_polygon"."status"),
+ "chimere_polygon_categories"."subcategory_id", "chimere_polygon"."status",
+ ST_Multi(ST_Collect("chimere_polygon"."polygon")) FROM "chimere_polygon"
+ LEFT OUTER JOIN "chimere_polygon_categories" ON (
+ "chimere_polygon"."id" = "chimere_polygon_categories"."polygon_id")
+ WHERE ("chimere_polygon"."start_date" IS NULL
+ OR ("chimere_polygon"."start_date" <= CURRENT_DATE
+ AND "chimere_polygon"."start_date" >= CURRENT_DATE)
+ OR ("chimere_polygon"."start_date" <= CURRENT_DATE
+ AND "chimere_polygon"."end_date" >= CURRENT_DATE))
+ GROUP BY "chimere_polygon_categories"."subcategory_id",
+ "chimere_polygon"."status";
+ """
+ db.execute(sql)
+
+ def backwards(self, orm):
+ sql = "drop view chimere_aggregated_polygons;"
+ db.execute(sql)
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedpolygon': {
+ 'Meta': {'object_name': 'AggregatedPolygon', 'db_table': "'chimere_aggregated_polygons'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'polygon': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'weight_formula': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere']
diff --git a/chimere/migrations/0033_auto__add_field_color_inner_code.py b/chimere/migrations/0033_auto__add_field_color_inner_code.py
new file mode 100644
index 0000000..bc7748b
--- /dev/null
+++ b/chimere/migrations/0033_auto__add_field_color_inner_code.py
@@ -0,0 +1,393 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Color.inner_code'
+ db.add_column('chimere_color', 'inner_code',
+ self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Color.inner_code'
+ db.delete_column('chimere_color', 'inner_code')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedpolygon': {
+ 'Meta': {'object_name': 'AggregatedPolygon', 'db_table': "'chimere_aggregated_polygons'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'polygon': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'inner_code': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'weight_formula': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0034_auto__add_field_subcategory_min_zoom.py b/chimere/migrations/0034_auto__add_field_subcategory_min_zoom.py
new file mode 100644
index 0000000..97ab39b
--- /dev/null
+++ b/chimere/migrations/0034_auto__add_field_subcategory_min_zoom.py
@@ -0,0 +1,394 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'SubCategory.min_zoom'
+ db.add_column('chimere_subcategory', 'min_zoom',
+ self.gf('django.db.models.fields.IntegerField')(null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'SubCategory.min_zoom'
+ db.delete_column('chimere_subcategory', 'min_zoom')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedpolygon': {
+ 'Meta': {'object_name': 'AggregatedPolygon', 'db_table': "'chimere_aggregated_polygons'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'polygon': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'inner_code': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'min_zoom': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'weight_formula': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/migrations/0035_auto__add_field_subcategory_simplify_tolerance.py b/chimere/migrations/0035_auto__add_field_subcategory_simplify_tolerance.py
new file mode 100644
index 0000000..69f1ff2
--- /dev/null
+++ b/chimere/migrations/0035_auto__add_field_subcategory_simplify_tolerance.py
@@ -0,0 +1,395 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'SubCategory.simplify_tolerance'
+ db.add_column('chimere_subcategory', 'simplify_tolerance',
+ self.gf('django.db.models.fields.FloatField')(null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'SubCategory.simplify_tolerance'
+ db.delete_column('chimere_subcategory', 'simplify_tolerance')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'chimere.aggregatedpolygon': {
+ 'Meta': {'object_name': 'AggregatedPolygon', 'db_table': "'chimere_aggregated_polygons'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'polygon': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.aggregatedroute': {
+ 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"})
+ },
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'allow_point_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_polygon_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'allow_route_edition': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'display_category_menu': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'extra_map_def': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'inner_code': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'offset_x': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'popup_offset_x': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'popup_offset_y': ('django.db.models.fields.IntegerField', [], {'default': '20'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}),
+ 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}),
+ 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'source_file_alt': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.importerkeycategories': {
+ 'Meta': {'object_name': 'ImporterKeyCategories'},
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'extra_js_code': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediaextension': {
+ 'Meta': {'object_name': 'MultimediaExtension'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']", 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'multimedia_files'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'ordering': "['-date']", 'object_name': 'News'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.page': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Page'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}),
+ 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'pictures'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.polygon': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Polygon'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'inner_color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('chimere.widgets.PolygonField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_polygon'", 'null': 'True', 'to': "orm['chimere.Polygon']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']", 'null': 'True', 'blank': 'True'}),
+ 'polygon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Polygon']", 'null': 'True', 'blank': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'color': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'normalised_weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'origin': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcategories'", 'null': 'True', 'to': "orm['chimere.ColorTheme']"}),
+ 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'min_zoom': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}),
+ 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'simplify_tolerance': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'weight_formula': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategoryuserlimit': {
+ 'Meta': {'object_name': 'SubCategoryUserLimit'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'limited_for_user'", 'to': "orm['chimere.SubCategory']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategory_limit_to'", 'to': "orm['auth.User']"})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '500'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/models.py b/chimere/models.py
index 0a2906c..a1e00f9 100644
--- a/chimere/models.py
+++ b/chimere/models.py
@@ -20,7 +20,11 @@
"""
Models description
"""
-import os, datetime, pyexiv2, re, string, copy
+import os
+import datetime
+import pyexiv2
+import re
+import copy
import simplejson as json
from lxml import etree
from PIL import Image
@@ -29,22 +33,19 @@ from BeautifulSoup import BeautifulSoup
from django import forms
from django.conf import settings
-from django.contrib import admin
from django.contrib.auth.models import User, Permission, ContentType, Group
from django.contrib.gis.db import models
-from django.contrib.gis.gdal import SpatialReference
from django.core.files import File
-from django.core.exceptions import ValidationError, ObjectDoesNotExist
+from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.urlresolvers import reverse
-from django.db.models import Q
+from django.db.models import Q, Count
from django.db.models.signals import post_save, pre_save, m2m_changed
from django.template import defaultfilters
from django.utils.translation import ugettext_lazy as _
from chimere.widgets import HiddenPointChooserWidget, PointField, RouteField, \
- SelectMultipleField, TextareaWidget, \
- DatePickerWidget
-from chimere.managers import BaseGeoManager
+ SelectMultipleField, TextareaWidget, DatePickerWidget, PolygonField, \
+ JQueryAutoComplete
from chimere.utils import KMLManager, OSMManager, ShapefileManager, \
GeoRSSManager, CSVManager, HtmlXsltManager, XMLXsltManager, JsonManager, \
IcalManager
@@ -61,13 +62,16 @@ class Page(models.Model):
template_path = models.CharField(_(u"Template path"), max_length=150,
blank=True, null=True)
content = models.TextField(blank=True, null=True)
- def __unicode__(self):
- ordering = ["order"]
- return self.title
+
class Meta:
+ ordering = ["order"]
verbose_name = _(u"Page")
verbose_name_plural = _(u"Page")
+ def __unicode__(self):
+ return self.title
+
+
def page_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -77,6 +81,7 @@ def page_post_save(sender, **kwargs):
page.save()
post_save.connect(page_post_save, sender=Page)
+
def shortify(text):
if not text:
return ''
@@ -89,15 +94,16 @@ def shortify(text):
if c == '>':
break
if c == '<':
- short_desc = desc[:-(idx+1)]
+ short_desc = desc[:-(idx + 1)]
break
if not short_desc:
for idx, c in enumerate(reversed(desc)):
if c == ' ' or c == '\n':
- short_desc = desc[:-(idx+1)]
+ short_desc = desc[:-(idx + 1)]
break
return BeautifulSoup(short_desc).prettify()
+
class News(models.Model):
"""News of the site
"""
@@ -110,33 +116,39 @@ class News(models.Model):
url = models.URLField(_(u"Url"), max_length=200, blank=True, null=True)
areas = SelectMultipleField('Area', verbose_name=_(u"Associated areas"),
blank=True, null=True)
- def __unicode__(self):
- ordering = ["-date"]
- return self.title
+
class Meta:
+ ordering = ["-date"]
verbose_name = _(u"News")
verbose_name_plural = _(u"News")
+ def __unicode__(self):
+ return self.title
+
@property
def short_desc(self):
return shortify(self.content)
+
class TinyUrl(models.Model):
"""Tinyfied version of permalink parameters
"""
- parameters = models.CharField(_(u"Parameters"), max_length=500, unique=True)
- def __unicode__(self):
- return self.parameters
- class Meta:
- verbose_name = _(u"TinyUrl")
+ parameters = models.CharField(_(u"Parameters"), max_length=500,
+ unique=True)
digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
base = len(digits)
+ class Meta:
+ verbose_name = _(u"TinyUrl")
+
+ def __unicode__(self):
+ return self.parameters
+
@classmethod
def getParametersByUrn(cls, urn):
c_id = 0
for idx, char in enumerate(reversed(urn)):
- c_id += cls.digits.index(char)*pow(cls.base, idx)
+ c_id += cls.digits.index(char) * pow(cls.base, idx)
try:
params = cls.objects.get(id=c_id).parameters
except cls.DoesNotExist:
@@ -160,27 +172,46 @@ class TinyUrl(models.Model):
break
return urn
+
class ColorTheme(models.Model):
"""Color theme
"""
name = models.CharField(_(u"Name"), max_length=150)
- def __unicode__(self):
- return self.name
+
class Meta:
verbose_name = _(u"Color theme")
+ def __unicode__(self):
+ return self.name
+
+
class Color(models.Model):
"""Color
"""
- code = models.CharField(_(u"Code"), max_length=6)
+ code = models.CharField(_(u"Code/name"), max_length=200,
+ help_text=_(u"HTML code/name"))
+ inner_code = models.CharField(_(u"Code/name (inner)"), max_length=200,
+ help_text=_(u"HTML code/name"),
+ blank=True, null=True)
order = models.IntegerField(_(u"Order"))
color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"))
- def __unicode__(self):
- return self.code
+
class Meta:
ordering = ["order"]
verbose_name = _(u"Color")
+ def __unicode__(self):
+ return self.code
+
+ @property
+ def color(self):
+ return self.code
+
+ @property
+ def inner_color(self):
+ return self.inner_code
+
+
class Category(models.Model):
"""Category of Point Of Interest (POI)
"""
@@ -188,12 +219,15 @@ class Category(models.Model):
available = models.BooleanField(_(u"Available"))
order = models.IntegerField(_(u"Order"))
description = models.TextField(blank=True, null=True)
- def __unicode__(self):
- return self.name
+
class Meta:
ordering = ["order"]
verbose_name = _(u"Category")
+ def __unicode__(self):
+ return self.name
+
+
class Icon(models.Model):
'''Icon
'''
@@ -202,11 +236,25 @@ class Icon(models.Model):
height_field='height', width_field='width')
height = models.IntegerField(_(u"Height"))
width = models.IntegerField(_(u"Width"))
+ offset_x = models.IntegerField(
+ _(u"Offset x"), default=10,
+ help_text=_(u"Common value is half the icon width"))
+ offset_y = models.IntegerField(
+ _(u"Offset y"), default=20,
+ help_text=_(u"Common value is icon height"))
+ popup_offset_x = models.IntegerField(_(u"Popup offset x"), default=0,
+ help_text=_(u"Common value is 0"))
+ popup_offset_y = models.IntegerField(
+ _(u"Popup offset y"), default=20,
+ help_text=_(u"Common value is icon height"))
+
def __unicode__(self):
return self.name
+
class Meta:
verbose_name = _(u"Icon")
+
class SubCategory(models.Model):
'''Sub-category
'''
@@ -218,30 +266,49 @@ class SubCategory(models.Model):
default=True)
TYPE = (('M', _(u'Marker')),
('R', _(u'Route')),
+ ('P', _(u'Polygon')),
('B', _(u'Both')),)
item_type = models.CharField(_(u"Item type"), max_length=1, choices=TYPE)
dated = models.BooleanField(_(u"Is dated"), default=False)
description = models.TextField(blank=True, null=True)
icon = models.ForeignKey(Icon, verbose_name=_(u"Icon"))
- hover_icon = models.ForeignKey(Icon, verbose_name=_(u"Hover icon"),
- blank=True, null=True, related_name='subcat_hovered')
+ hover_icon = models.ForeignKey(
+ Icon, verbose_name=_(u"Hover icon"), blank=True, null=True,
+ related_name='subcat_hovered')
color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"),
- blank=True, null=True)
+ blank=True, null=True,
+ related_name='subcategories')
as_layer = models.BooleanField(_(u"Displayed in the layer menu"),
default=False)
+ weight_formula = models.TextField(_(u"Weight formula"), default="",
+ blank=True, null=True)
routing_warn = models.BooleanField(_(u"Routing warn"), default=False)
order = models.IntegerField(_(u"Order"), default=1000)
keywords = models.TextField(_(u"Keywords"), max_length=200,
- blank=True, null=True)
- def __unicode__(self):
- return u"%s / %s" % (self.category.name, self.name)
+ blank=True, null=True)
+ min_zoom = models.IntegerField(
+ _(u"Minimum zoom for loading details"), blank=True, null=True,
+ help_text=_(u"Optimization when too many data have to be displayed. "
+ u"Currently available only for route and polygon."))
+ simplify_tolerance = models.FloatField(
+ _(u"Simplify tolerance for lower zoom"), blank=True, null=True,
+ help_text=_(u"Only relevant when Minimum zoom is set. Use the "
+ u"Douglas-Peucker algorythm to simplify the geometry when "
+ u"details is not alvailable. Adjust to your data volume "
+ u"and your performance need. 0.0003 is a good starting "
+ u"point. Note: typology is not preserved."))
+
class Meta:
ordering = ["category", "order"]
verbose_name = _(u"Sub-category")
verbose_name_plural = _(u"Sub-categories")
+ def __unicode__(self):
+ return u"%s / %s" % (self.category.name, self.name)
+
@classmethod
- def getAvailable(cls, item_types=None, area_name=None, public=False):
+ def getAvailable(cls, item_types=None, area_name=None, public=False,
+ instance=False):
'''Get list of tuples with first the category and second the associated
subcategories
'''
@@ -262,6 +329,10 @@ class SubCategory(models.Model):
subcategories = subcategories.filter(id__in=sub_ids)
selected_cats = [subcat.pk
for subcat in area.default_subcategories.all()]
+
+ if instance:
+ return subcategories.order_by('order')
+
for sub_category in subcategories.order_by('order'):
if sub_category.category not in sub_categories:
sub_categories[sub_category.category] = []
@@ -269,9 +340,8 @@ class SubCategory(models.Model):
sub_category.selected = True
sub_category.category.selected = True
sub_categories[sub_category.category].append(sub_category)
-
- subcategories = [(cat, subcats) \
- for cat, subcats in sub_categories.items()]
+ subcategories = [(cat, subcats)
+ for cat, subcats in sub_categories.items()]
get_cat_order = lambda cat_tuple: cat_tuple[0].order
subcategories = sorted(subcategories, key=get_cat_order)
return subcategories
@@ -286,15 +356,20 @@ class SubCategory(models.Model):
return cats
def getJSONDict(self):
- items = {'id':self.pk, 'name':self.name,
- 'description':self.description if self.description\
- else '',
- 'icon':{'url':self.icon.image.url,
- 'width':self.icon.image.width,
- 'height':self.icon.image.height}
- }
+ items = {'id': self.pk, 'name': self.name,
+ 'description': self.description if self.description
+ else '',
+ 'icon': {'url': self.icon.image.url,
+ 'width': self.icon.image.width,
+ 'height': self.icon.image.height,
+ 'offset_x': self.icon.offset_x,
+ 'offset_y': self.icon.offset_y,
+ 'popup_offset_x': self.icon.popup_offset_x,
+ 'popup_offset_y': self.icon.popup_offset_y}
+ }
+
if self.hover_icon:
- items['icon_hover'] = {'url':self.hover_icon.image.url}
+ items['icon_hover'] = {'url': self.hover_icon.image.url}
return items
def getJSON(self, categories_id=[]):
@@ -370,10 +445,10 @@ class Importer(models.Model):
source = models.CharField(_(u"Web address"), max_length=200,
blank=True, null=True,
help_text=_(u"Don't forget the trailing slash"))
- source_file = models.FileField(_(u"Source file"),
- upload_to='import_files', blank=True, null=True)
- source_file_alt = models.FileField(_(u"Alt source file"),
- upload_to='import_files', blank=True, null=True)
+ source_file = models.FileField(
+ _(u"Source file"), upload_to='import_files', blank=True, null=True)
+ source_file_alt = models.FileField(
+ _(u"Alt source file"), upload_to='import_files', blank=True, null=True)
default_name = models.CharField(_(u"Name by default"), max_length=200,
blank=True, null=True)
srid = models.IntegerField(_(u"SRID"), blank=True, null=True)
@@ -388,19 +463,20 @@ class Importer(models.Model):
blank=True, null=True)
license = models.CharField(_(u"License"), max_length=1000,
blank=True, null=True)
- categories = SelectMultipleField(SubCategory, blank=True, null=True,
- verbose_name=_(u"Associated subcategories"))
+ categories = SelectMultipleField(
+ SubCategory, blank=True, null=True,
+ verbose_name=_(u"Associated subcategories"))
state = models.TextField(_(u"State"), blank=True, null=True)
- associate_marker_to_way = models.BooleanField(_(u"Automatically associate "\
- u"a marker to a way"), default=False)
+ associate_marker_to_way = models.BooleanField(
+ _(u"Automatically associate a marker to a way"), default=False)
automatic_update = models.BooleanField(_(u"Automatically updated"),
default=False)
default_status = models.CharField(_(u"Default status"), max_length=1,
choices=STATUS, default='I')
- default_localisation = PointField(_(u"Default localisation"),
- srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- blank=True, null=True,
- widget=HiddenPointChooserWidget)
+ default_localisation = PointField(
+ _(u"Default localisation"),
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION, blank=True, null=True,
+ widget=HiddenPointChooserWidget)
class Meta:
verbose_name = _(u"Importer")
@@ -446,47 +522,166 @@ class ImporterKeyCategories(models.Model):
class Meta:
verbose_name = _(u"Importer - Key categories")
+
class GeographicItem(models.Model):
- name = models.TextField(_(u"Name"))
categories = SelectMultipleField(SubCategory)
- submiter_session_key = models.CharField(_(u"Submitter session key"),
- blank=True, null=True, max_length=40)
+ name = models.TextField(_(u"Name"))
+ submiter_session_key = models.CharField(
+ _(u"Submitter session key"), blank=True, null=True, max_length=40)
submiter_name = models.CharField(_(u"Submitter name or nickname"),
blank=True, null=True, max_length=40)
submiter_email = models.EmailField(_(u"Submitter email"), blank=True,
null=True)
- submiter_comment = models.TextField(_(u"Submitter comment"), max_length=200,
- blank=True, null=True)
+ submiter_comment = models.TextField(_(u"Submitter comment"),
+ max_length=200, blank=True, null=True)
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)
- keywords = models.TextField(_(u"Keywords"), max_length=200,
- blank=True, null=True)
+ keywords = models.TextField(_(u"Keywords"), max_length=200, blank=True,
+ null=True)
import_key = models.CharField(_(u"Import key"), max_length=200,
blank=True, null=True)
import_version = models.IntegerField(_(u"Import version"),
blank=True, null=True)
import_source = models.CharField(_(u"Source"), max_length=200,
blank=True, null=True)
- modified_since_import = models.BooleanField(_(u"Modified since last import"),
- default=True)
+ modified_since_import = models.BooleanField(
+ _(u"Modified since last import"), default=True)
not_for_osm = models.BooleanField(_(u"Not to be exported to OSM"),
default=False)
origin = models.CharField(_(u"Origin"), max_length=1000,
blank=True, null=True)
license = models.CharField(_(u"License"), max_length=1000,
blank=True, null=True)
- start_date = models.DateField(_(u"Start date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it for dated item such as event. "\
+ start_date = models.DateField(
+ _(u"Start date"), blank=True, null=True,
+ help_text=_(u"Not mandatory. Set it for dated item such as event. "
u"Format YYYY-MM-DD"))
- end_date = models.DateField(_(u"End date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it only if you have a multi-day "\
+ end_date = models.DateField(
+ _(u"End date"), blank=True, null=True,
+ help_text=_(u"Not mandatory. Set it only if you have a multi-day "
u"event. Format YYYY-MM-DD"))
+ weight = models.FloatField(
+ _(u"Weight"), blank=True, null=True,
+ help_text=_(
+ u"Weight are used for heatmap and clustering. A formula must "
+ u"defined in the associated category."))
+ normalised_weight = models.FloatField(
+ _(u"Normalised weight"), blank=True, null=True,
+ help_text=_(u"The weight normalised to be between 0 and 1. "
+ u"Automatically recalculated."))
+
class Meta:
abstract = True
+ def __unicode__(self):
+ return self.name
+
+ def __init__(self, *args, **kwargs):
+ super(GeographicItem, self).__init__(*args, **kwargs)
+ # add read attributes for properties
+ for pm in self.all_properties():
+ attr_name = pm.getAttrName()
+ if not hasattr(self, attr_name):
+ val = ''
+ property = self.getProperty(pm)
+ if property:
+ val = property.python_value
+ setattr(self, attr_name, val)
+ if not hasattr(self, attr_name + '_set'):
+ setattr(self, attr_name + '_set',
+ property_setter(self.__class__, pm))
+
+ def get_geometry(self):
+ return getattr(self, self.geom_attr)
+
+ @property
+ def geometry(self):
+ return getattr(self, self.geom_attr).wkt
+
+ def _get_geom_item_fk_name(self):
+ geom_attr = self.geom_attr
+ if self.geom_attr == 'route':
+ # # TODO v3 - backport routes
+ geom_attr = 'point'
+ return GEOM_TO_GEOM_ITEM[geom_attr].lower()
+
+ def getProperty(self, propertymodel, safe=None):
+ """Get the property of an associated property model.
+ If safe set to True, verify if the property is available
+ """
+ if safe and not propertymodel.available:
+ return
+ geom_item = self._get_geom_item_fk_name()
+ try:
+ d = {'propertymodel': propertymodel,
+ geom_item: self}
+ property = Property.objects.get(**d)
+ except Property.DoesNotExist:
+ return
+ return property
+
+ def getProperties(self, area_name=None):
+ """Get all the property availables
+ """
+ properties = []
+ querys = PropertyModel.getAvailable(area_name=area_name)
+ for query in querys:
+ for pm in query.all():
+ property = self.getProperty(pm)
+ if property:
+ properties.append(property)
+ return properties
+
+ def setProperty(self, pm, value):
+ u"""
+ Set a property
+ """
+ if not hasattr(pm, 'pk'):
+ pm = PropertyModel.objects.get(slug=pm)
+ geom_item = self._get_geom_item_fk_name()
+ d = {'propertymodel': pm, geom_item: self}
+ q = Property.objects.filter(**d)
+ properties = q.all()
+ # in case of multiple edition as the same time delete arbitrary
+ # the others
+ if len(properties) > 1:
+ for property in properties[1:]:
+ property.delete()
+ if pm.type == 'C' and value:
+ try:
+ value = str(int(value))
+ except ValueError:
+ choice = PropertyModelChoice.objects.filter(propertymodel=pm,
+ value=value)
+ if choice.count():
+ value = choice.all()[0].pk
+ else:
+ choice = PropertyModelChoice.objects.create(
+ value=value, propertymodel=pm)
+ value = choice.pk
+ # new property
+ if not properties:
+ d = {'propertymodel': pm, geom_item: self, 'value': value}
+ new_property = Property.objects.create(**d)
+ new_property.save()
+ else:
+ property = properties[0]
+ property.value = value
+ property.save()
+
+ def saveProperties(self, values):
+ """
+ Save properties
+ """
+ for propertymodel in PropertyModel.objects.filter(available=True):
+ val = u""
+ if unicode(propertymodel.id) in values:
+ val = values[unicode(propertymodel.id)]
+ self.setProperty(propertymodel, val)
+
def get_key(self, key):
key_vals = self.import_key.split(';')
for k_v in key_vals:
- if k_v.startswith(key+':'):
+ if k_v.startswith(key + ':'):
return k_v.split(':')[1]
def set_key(self, key, value):
@@ -513,8 +708,8 @@ class GeographicItem(models.Model):
def has_modified(self):
if (self.ref_item and self.ref_item != self) \
- or self.__class__.objects.filter(ref_item=self
- ).exclude(pk=self.pk).count():
+ or self.__class__.objects.filter(
+ ref_item=self).exclude(pk=self.pk).count():
return True
return False
@@ -526,25 +721,103 @@ class GeographicItem(models.Model):
def all_properties(cls):
return [pm for pm in PropertyModel.objects.all()]
+ def get_init_multi(self):
+ multis = [forms.model_to_dict(multi)
+ for multi in self.multimedia_files.all()]
+ return multis
+
+ def get_init_picture(self):
+ picts = [forms.model_to_dict(pict)
+ for pict in self.pictures.all()]
+ return picts
+
+ def get_full_dict(self):
+ dct = {}
+ # get all property even the one not displayed
+ for pm in PropertyModel.objects.all():
+ dct[pm.slug] = unicode(self.getProperty(pm))
+ return dct
+
+ def calculate_weight(self, formula):
+ try:
+ # try to eval the formula
+ # safe because open to admin only
+ return round(eval(formula.format(**self.get_full_dict())), 10)
+ except:
+ return 0
+
+ def get_weight_formula(self, get_associated_cat=False):
+ for sub in self.categories.order_by('order').all():
+ if sub.weight_formula:
+ if get_associated_cat:
+ return sub.weight_formula, sub
+ return sub.weight_formula
+ if get_associated_cat:
+ return None, None
+ return None
+
+ def normalise_weight(self):
+ formula, cat = self.get_weight_formula(get_associated_cat=True)
+ if not formula:
+ return
+ q = self.__class__.objects.filter(
+ categories__pk=cat.pk, weight__isnull=False)
+ if not q.count():
+ return 0
+ min_weight = q.order_by('weight')[0].weight or 0
+ max_weight = q.order_by('-weight')[0].weight or 0
+ return 1 - round(
+ (max_weight - self.weight or 0) /
+ (float((max_weight - min_weight)) or 1), 5)
+
+
+def weighted_post_save(sender, **kwargs):
+ if not kwargs['instance']:
+ return
+ obj = kwargs['instance']
+ formula = obj.get_weight_formula()
+ weight, normalised_weight = None, None
+ if formula:
+ weight = obj.calculate_weight(formula)
+ if weight != obj.weight:
+ obj.weight = weight
+ obj.save()
+ return
+ normalised_weight = obj.normalise_weight()
+ if weight != obj.weight or normalised_weight != obj.normalised_weight:
+ obj.weight = weight
+ obj.normalised_weight = normalised_weight
+ obj.save()
+
+
def property_setter(cls, propertymodel):
def setter(self, value):
- marker = self
+ item = self
if cls == Route:
+ # TODO v3
if not self.associated_marker.objects.count():
return
- marker = self.associated_marker.objects.all()[0]
- marker.setProperty(propertymodel, value)
+ item = self.associated_marker.objects.all()[0]
+ item.setProperty(propertymodel, value)
return setter
+GEOM_TO_GEOM_ITEM = {
+ "point": "Marker",
+ "route": "Route",
+ "polygon": "Polygon"
+}
+
+
class Marker(GeographicItem):
'''Marker for a POI
'''
- ref_item = models.ForeignKey("Marker", blank=True, null=True,
- verbose_name=_(u"Reference marker"), related_name='submited_marker')
+ ref_item = models.ForeignKey(
+ "Marker", blank=True, null=True, verbose_name=_(u"Reference marker"),
+ related_name='submited_marker')
point = PointField(_(u"Localisation"),
srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
available_date = models.DateTimeField(_(u"Available Date"), blank=True,
- null=True) # used by feeds
+ null=True) # used by feeds
route = models.ForeignKey(u"Route", blank=True, null=True,
related_name='associated_marker')
description = models.TextField(_(u"Description"), blank=True, null=True)
@@ -552,33 +825,9 @@ class Marker(GeographicItem):
null=True)
objects = models.GeoManager()
- def __unicode__(self):
- return self.name
-
- def __init__(self, *args, **kwargs):
- super(Marker, self).__init__(*args, **kwargs)
- # add read attributes for properties
- for pm in self.all_properties():
- attr_name = pm.getAttrName()
- if not hasattr(self, attr_name):
- val = ''
- property = self.getProperty(pm)
- if property:
- val = property.python_value
- setattr(self, attr_name, val)
- if not hasattr(self, attr_name + '_set'):
- setattr(self, attr_name + '_set',
- property_setter(self.__class__, pm))
-
- def get_init_multi(self):
- multis = [forms.model_to_dict(multi)
- for multi in self.multimedia_files.all()]
- return multis
-
- def get_init_picture(self):
- picts = [forms.model_to_dict(pict)
- for pict in self.pictures.all()]
- return picts
+ class Meta:
+ ordering = ('status', 'name')
+ verbose_name = _(u"Point of interest")
@property
def multimedia_items(self):
@@ -609,17 +858,9 @@ class Marker(GeographicItem):
return shortify(self.description)
@property
- def geometry(self):
- return self.point.wkt
-
- @property
def geom_attr(self):
return 'point'
- class Meta:
- ordering = ('status', 'name')
- verbose_name = _(u"Point of interest")
-
def getLatitude(self):
'''Return the latitude
'''
@@ -630,78 +871,11 @@ class Marker(GeographicItem):
'''
return self.point.x
- def getProperty(self, propertymodel, safe=None):
- """Get the property of an associated property model.
- If safe set to True, verify if the property is available
- """
- if safe and not propertymodel.available:
- return
- try:
- property = Property.objects.get(propertymodel=propertymodel,
- marker=self)
- except Property.DoesNotExist:
- return
- return property
-
- def getProperties(self):
- """Get all the property availables
- """
- properties = []
- for pm in PropertyModel.objects.filter(available=True):
- property = self.getProperty(pm)
- if property:
- properties.append(property)
- return properties
-
- def setProperty(self, pm, value):
- u"""
- Set a property
- """
- properties = Property.objects.filter(marker=self,
- propertymodel=pm).all()
- # in case of multiple edition as the same time delete arbitrary
- # the others
- if len(properties) > 1:
- for property in properties[1:]:
- property.delete()
- if pm.type == 'C' and value:
- try:
- value = str(int(value))
- except ValueError:
- choice = PropertyModelChoice.objects.filter(propertymodel=pm,
- value=value)
- if choice.count():
- value = choice.all()[0].pk
- else:
- choice = PropertyModelChoice.objects.create(value=value,
- propertymodel=pm)
- value = choice.pk
- # new property
- if not properties:
- new_property = Property.objects.create(marker=self,
- propertymodel=pm,
- value=value)
- new_property.save()
- else:
- property = properties[0]
- property.value = value
- property.save()
-
- def saveProperties(self, values):
- """
- Save properties
- """
- for propertymodel in PropertyModel.objects.filter(available=True):
- val = u""
- if unicode(propertymodel.id) in values:
- val = values[unicode(propertymodel.id)]
- self.setProperty(propertymodel, val)
-
def getGeoJSON(self, categories_id=[]):
'''Return a GeoJSON string
'''
jsons = []
- json_tpl = {"type":"Feature", "properties":{}}
+ json_tpl = {"type": "Feature", "properties": {}}
for cat in self.categories.all():
if categories_id and cat.id not in categories_id:
continue
@@ -711,15 +885,22 @@ class Marker(GeographicItem):
except json.JSONDecodeError:
continue
items['properties'].update({
- 'pk':self.id,
- 'name':self.name,
- 'icon_path':unicode(cat.icon.image),
- 'icon_hover_path':unicode(cat.hover_icon.image) \
- if cat.hover_icon else '',
- 'category_name':cat.name})
+ 'pk': self.id,
+ 'key': "marker-{}".format(self.id),
+ 'name': self.name,
+ 'icon_path': unicode(cat.icon.image),
+ 'icon_hover_path': unicode(cat.hover_icon.image)
+ if cat.hover_icon else '',
+ 'icon_offset_x': cat.icon.offset_x,
+ 'icon_offset_y': cat.icon.offset_y,
+ 'icon_popup_offset_x': cat.icon.popup_offset_x,
+ 'icon_popup_offset_y': cat.icon.popup_offset_y,
+ 'category_name': cat.name})
try:
- items['properties'].update({'icon_width':cat.icon.image.width,
- 'icon_height':cat.icon.image.height,})
+ items['properties'].update(
+ {'icon_width': cat.icon.image.width,
+ 'icon_height': cat.icon.image.height,
+ })
except IOError:
pass
@@ -745,11 +926,13 @@ class Marker(GeographicItem):
return url
PRE_ATTRS = {
- 'Marker':('name', 'description', 'start_date', 'geometry', 'import_version',
- 'modified_since_import'),
- 'Route':('name', 'geometry', 'import_version', 'modified_since_import'),
- 'Area':('urn', 'name'),
- }
+ 'Marker': ('name', 'description', 'start_date', 'geometry',
+ 'import_version', 'modified_since_import'),
+ 'Route': ('name', 'geometry', 'import_version', 'modified_since_import'),
+ 'Area': ('urn', 'name'),
+}
+
+
def geometry_pre_save(cls, pre_save_geom_values):
def geom_pre_save(sender, **kwargs):
if not kwargs['instance'] or not kwargs['instance'].pk:
@@ -765,12 +948,15 @@ def geometry_pre_save(cls, pre_save_geom_values):
return geom_pre_save
pre_save_marker_values = {}
+
+
def marker_pre_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_pre_save(Marker, pre_save_marker_values)(sender, **kwargs)
pre_save.connect(marker_pre_save, sender=Marker)
+
def geometry_post_save(pre_save_geom_values):
def geom_post_save(sender, **kwargs):
if not kwargs['instance'] \
@@ -788,18 +974,174 @@ def geometry_post_save(pre_save_geom_values):
return
if instance.modified_since_import:
return
- if [key for key in pre if pre not in ('import_version',
- 'modified_since_import') and
- getattr(instance, key) != pre[key]]:
+ if [key for key in pre if pre not in (
+ 'import_version', 'modified_since_import') and
+ getattr(instance, key) != pre[key]]:
instance.modified_since_import = True
instance.save()
return geom_post_save
+
+
def marker_post_save(sender, **kwargs):
+ weighted_post_save(sender, **kwargs)
if not kwargs['instance'] or kwargs['created']:
return
geometry_post_save(pre_save_marker_values)(sender, **kwargs)
post_save.connect(marker_post_save, sender=Marker)
+
+class Polygon(GeographicItem):
+ '''Polygon on the map
+ '''
+ ref_item = models.ForeignKey(
+ "Polygon", blank=True, null=True, verbose_name=_(u"Reference polygon"),
+ related_name='submited_polygon')
+ polygon = PolygonField(
+ _(u"Polygon"), srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ picture = models.ImageField(
+ _(u"Image"), upload_to='upload', blank=True, null=True,
+ height_field='height', width_field='width')
+ height = models.IntegerField(_(u"Height"), blank=True, null=True)
+ width = models.IntegerField(_(u"Width"), blank=True, null=True)
+ color = models.CharField(
+ _(u"Color"), max_length=200, help_text=_(u"HTML code/name"),
+ blank=True, null=True)
+ inner_color = models.CharField(
+ _(u"Inner color"), max_length=200,
+ help_text=_(u"HTML code/name"), blank=True, null=True)
+ objects = models.GeoManager()
+
+ class Meta:
+ ordering = ('status', 'name')
+ verbose_name = _(u"Polygon")
+
+ @property
+ def geom_attr(self):
+ return 'polygon'
+
+ def getGeoJSON(self, color="#000", inner_color='#0F0'):
+ '''Return a GeoJSON string
+ '''
+ try:
+ geom = json.loads(self.polygon.geojson)
+ except json.JSONDecodeError:
+ return json.dumps('{}')
+ attributes = {"type": "Feature",
+ "geometry": geom,
+ "properties": {"pk": self.id, "name": self.name,
+ 'key': "polygon-{}".format(self.pk),
+ "color": self.color or color,
+ "inner_color": self.inner_color
+ or inner_color}}
+ return json.dumps(attributes)
+
+ @classmethod
+ def getGeoJSONs(self, queryset, color="#000",
+ inner_color='rgba(180, 180, 180, 0.3)',
+ limit_to_categories=[]):
+ vals, default_color, default_inner_color = [], color, inner_color
+ q = queryset.select_related('categories').extra(
+ select={'json': 'ST_AsGeoJSON(polygon)'}).values(
+ 'json', 'name', 'pk', 'inner_color', 'color', 'categories__pk')
+ added = []
+ current_categories = {}
+ for polygon in q.all():
+ if polygon['pk'] in added:
+ continue
+ if limit_to_categories and \
+ polygon["categories__pk"] not in limit_to_categories:
+ continue
+ color = default_color
+ if polygon["color"]:
+ color = polygon['color']
+ elif polygon["categories__pk"]:
+ if polygon["categories__pk"] not in current_categories:
+ cat = SubCategory.objects.get(pk=polygon["categories__pk"])
+ # [index, color list]
+ current_categories[polygon["categories__pk"]] = \
+ [0, list(Color.objects.filter(
+ color_theme=cat.color_theme))]
+ idx, colors = current_categories[polygon["categories__pk"]]
+ # category have a color theme
+ if colors:
+ c = colors[idx % len(colors)]
+ color = c.code
+ if c.inner_code:
+ inner_color = c.inner_code
+ # index += 1
+ current_categories[polygon["categories__pk"]][0] += 1
+ if polygon["inner_color"]:
+ inner_color = polygon["inner_color"]
+ elif not inner_color:
+ inner_color = default_inner_color
+ vals.append({
+ "type": "Feature",
+ "geometry": json.loads(polygon['json']),
+ "properties": {"pk": polygon['pk'], "name": polygon['name'],
+ 'key': "polygon-{}".format(polygon['pk']),
+ 'color': color,
+ 'inner_color': inner_color}})
+ added.append(polygon['pk'])
+ return vals
+
+ def get_full_dict(self):
+ dct = super(Polygon, self).get_full_dict()
+ # to be done - use local unity
+ dct['area'] = self.polygon.area
+ dct['length'] = self.polygon.length
+ return dct
+
+post_save.connect(weighted_post_save, sender=Polygon)
+
+
+class AggregatedPolygon(models.Model):
+ '''
+ Database view for aggregated polygons
+ '''
+ polygon = models.MultiPolygonField()
+ subcategory = models.ForeignKey(SubCategory)
+ status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)
+
+ class Meta:
+ managed = False
+ db_table = 'chimere_aggregated_polygons'
+
+ def getGeoJSON(self, color="", inner_color=''):
+ '''Return a GeoJSON string
+ '''
+ # get colors
+ if not color or not inner_color:
+ q = Color.objects.filter(
+ color_theme__subcategories=self.subcategory)
+ if not q.count():
+ if not color:
+ color = "rgba(0, 0, 255, 1)"
+ if not inner_color:
+ inner_color = 'rgba(255, 125, 0, 0.6)'
+ else:
+ # get the first
+ c = q.order_by('order').all()[0]
+ if not color:
+ color = c.color
+ if not inner_color:
+ inner_color = c.inner_color
+
+ geom = self.polygon
+ if self.subcategory.simplify_tolerance:
+ geom = self.polygon.simplify(
+ self.subcategory.simplify_tolerance).json
+ else:
+ geom = geom.json
+ attributes = {
+ 'color': color, 'geometry': json.loads(geom),
+ 'type': "Feature", "properties": {
+ 'color': color,
+ 'inner_color': inner_color,
+ 'key': "aggpoly-{}".format(self.pk),
+ "pk": self.id, "name": u'Aggregated polygon'}}
+ return json.dumps(attributes)
+
+
class MultimediaType(models.Model):
MEDIA_TYPES = (('A', _(u"Audio")),
('V', _(u"Video")),
@@ -835,25 +1177,27 @@ class MultimediaType(models.Model):
return tuples
IFRAME_LINKS = {
- 'youtube':((re.compile(r'youtube.com\/watch\?[A-Za-z0-9_\-\=\&]*v=([A-Za-z0-9_-]*)[A-Za-z0-9_\-\=\&]*'),
- re.compile(r'youtu.be\/([A-Za-z0-9_-]*)'),
- re.compile(r'youtube.com\/embed\/([A-Za-z0-9_-]*)')),
- "http://www.youtube.com/embed/%s"),
- 'dailymotion':(
+ 'youtube': ((re.compile(r'youtube.com\/watch\?[A-Za-z0-9_\-\=\&]*v='
+ r'([A-Za-z0-9_-]*)[A-Za-z0-9_\-\=\&]*'),
+ re.compile(r'youtu.be\/([A-Za-z0-9_-]*)'),
+ re.compile(r'youtube.com\/embed\/([A-Za-z0-9_-]*)')),
+ "http://www.youtube.com/embed/%s"),
+ 'dailymotion': (
(re.compile(r'dailymotion.com/video/([A-Za-z0-9]*)_[A-Za-z0-9_-]*'),
re.compile(r'dailymotion.com/embed/video/([A-Za-z0-9]*)'),
re.compile("http://www.dailymotion.com/embed/video/%s")),
- 'http://www.dailymotion.com/embed/video/%s'),
- 'vimeo':((re.compile(r'vimeo.com/video/([A-Za-z0-9]*)'),
- re.compile(r'vimeo.com/([A-Za-z0-9]*)'),),
+ 'http://www.dailymotion.com/embed/video/%s'),
+ 'vimeo': ((re.compile(r'vimeo.com/video/([A-Za-z0-9]*)'),
+ re.compile(r'vimeo.com/([A-Za-z0-9]*)'),),
"http://player.vimeo.com/video/%s")
}
+
class MultimediaExtension(models.Model):
name = models.CharField(_(u"Extension name"), max_length=6)
- multimedia_type = models.ForeignKey(MultimediaType,
- verbose_name=_(u"Associated multimedia type"),
- related_name='extensions')
+ multimedia_type = models.ForeignKey(
+ MultimediaType, verbose_name=_(u"Associated multimedia type"),
+ related_name='extensions')
class Meta:
verbose_name = _(u"Multimedia extension")
@@ -862,14 +1206,19 @@ class MultimediaExtension(models.Model):
def __unicode__(self):
return self.name
+
class MultimediaFile(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
url = models.URLField(_(u"Url"), max_length=200)
order = models.IntegerField(_(u"Order"), default=1)
multimedia_type = models.ForeignKey(MultimediaType, blank=True, null=True)
- miniature = models.BooleanField(_(u"Display inside the description?"),
- default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
- marker = models.ForeignKey(Marker, related_name='multimedia_files')
+ miniature = models.BooleanField(
+ _(u"Display inside the description?"),
+ default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
+ marker = models.ForeignKey(Marker, related_name='multimedia_files',
+ blank=True, null=True)
+ polygon = models.ForeignKey(Polygon, related_name='multimedia_files',
+ blank=True, null=True)
class Meta:
verbose_name = _(u"Multimedia file")
@@ -878,6 +1227,7 @@ class MultimediaFile(models.Model):
def __unicode__(self):
return self.name or u""
+
def multimediafile_post_save(sender, **kwargs):
if not kwargs['instance'] or not kwargs['created']:
return
@@ -889,7 +1239,7 @@ def multimediafile_post_save(sender, **kwargs):
res, embeded_url = IFRAME_LINKS[mm_type]
if [r for r in res if r.search(url)]:
multimedia_type = MultimediaType.objects.get(
- name__iexact=mm_type)
+ name__iexact=mm_type)
multimediafile.multimedia_type = multimedia_type
if not multimediafile.multimedia_type:
ext = url.split(".")[-1]
@@ -899,10 +1249,12 @@ def multimediafile_post_save(sender, **kwargs):
else:
# default to an iframe
multimediafile.multimedia_type = \
- MultimediaType.objects.filter(name__iexact='iframe').all()[0]
+ MultimediaType.objects.filter(name__iexact='iframe')\
+ .all()[0]
# manage iframe of video providers
if multimediafile.multimedia_type.name.lower() in IFRAME_LINKS:
- regexps, lnk = IFRAME_LINKS[multimediafile.multimedia_type.name.lower()]
+ regexps, lnk = IFRAME_LINKS[
+ multimediafile.multimedia_type.name.lower()]
key = None
for regexp in regexps:
key = regexp.findall(multimediafile.url)
@@ -912,8 +1264,9 @@ def multimediafile_post_save(sender, **kwargs):
if key:
multimediafile.url = lnk % key
- mfs = MultimediaFile.objects.filter(marker=multimediafile.marker).exclude(
- pk=multimediafile.pk).order_by('order')
+ mfs = MultimediaFile.objects.filter(marker=multimediafile.marker)\
+ .exclude(pk=multimediafile.pk)\
+ .order_by('order')
for idx, mf in enumerate(mfs.all()):
mf.order = idx + 1
mf.save()
@@ -921,24 +1274,28 @@ def multimediafile_post_save(sender, **kwargs):
multimediafile.save()
post_save.connect(multimediafile_post_save, sender=MultimediaFile)
+
class PictureFile(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
picture = models.ImageField(_(u"Image"), upload_to='pictures',
height_field='height', width_field='width')
height = models.IntegerField(_(u"Height"), blank=True, null=True)
width = models.IntegerField(_(u"Width"), blank=True, null=True)
- miniature = models.BooleanField(_(u"Display inside the description?"),
- default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
- thumbnailfile = models.ImageField(_(u"Thumbnail"), upload_to='pictures',
- blank=True, null=True,
- height_field='thumbnailfile_height',
- width_field='thumbnailfile_width')
+ miniature = models.BooleanField(
+ _(u"Display inside the description?"),
+ default=settings.CHIMERE_MINIATURE_BY_DEFAULT)
+ thumbnailfile = models.ImageField(
+ _(u"Thumbnail"), upload_to='pictures', blank=True, null=True,
+ height_field='thumbnailfile_height', width_field='thumbnailfile_width')
thumbnailfile_height = models.IntegerField(_(u"Thumbnail height"),
blank=True, null=True)
thumbnailfile_width = models.IntegerField(_(u"Thumbnail width"),
blank=True, null=True)
order = models.IntegerField(_(u"Order"), default=1)
- marker = models.ForeignKey(Marker, related_name='pictures')
+ marker = models.ForeignKey(Marker, related_name='pictures', blank=True,
+ null=True)
+ polygon = models.ForeignKey(Polygon, related_name='pictures', blank=True,
+ null=True)
def __unicode__(self):
return self.name or u""
@@ -947,6 +1304,7 @@ class PictureFile(models.Model):
verbose_name = _(u"Picture file")
verbose_name_plural = _(u"Picture files")
+
def scale_image(max_x, pair):
x, y = pair
new_y = (float(max_x) / x) * y
@@ -961,6 +1319,7 @@ IMAGE_EXIF_ORIENTATION_MAP = {
PYEXIV2_OLD_API = not hasattr(pyexiv2, 'ImageMetadata')
+
def picturefile_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -973,12 +1332,12 @@ def picturefile_post_save(sender, **kwargs):
metadata = pyexiv2.Image(filename)
metadata.readMetadata()
orientation = metadata['Exif.Image.Orientation'] \
- if 'Exif.Image.Orientation' in metadata.exifKeys() else None
+ if 'Exif.Image.Orientation' in metadata.exifKeys() else None
else:
metadata = pyexiv2.ImageMetadata(filename)
metadata.read()
orientation = metadata['Exif.Image.Orientation'].value \
- if 'Exif.Image.Orientation' in metadata else None
+ if 'Exif.Image.Orientation' in metadata else None
if orientation and orientation in IMAGE_EXIF_ORIENTATION_MAP \
and orientation > 1:
metadata['Exif.Image.Orientation'] = 1
@@ -996,7 +1355,7 @@ def picturefile_post_save(sender, **kwargs):
filehead, filetail = os.path.split(os.path.abspath(file.path))
basename, format = os.path.splitext(filetail)
basename = defaultfilters.slugify(basename)
- basename = re.sub(r'-','_', basename)
+ basename = re.sub(r'-', '_', basename)
miniature = basename + '_thumb.jpg'
filename = file.path
miniature_filename = os.path.join(filehead, miniature)
@@ -1008,12 +1367,10 @@ def picturefile_post_save(sender, **kwargs):
image_x, image_y = image.size
if settings.CHIMERE_THUMBS_SCALE_HEIGHT:
image_y, image_x = scale_image(
- settings.CHIMERE_THUMBS_SCALE_HEIGHT,
- (image_y, image_x))
+ settings.CHIMERE_THUMBS_SCALE_HEIGHT, (image_y, image_x))
elif settings.CHIMERE_THUMBS_SCALE_WIDTH:
image_x, image_y = scale_image(
- settings.CHIMERE_THUMBS_SCALE_WIDTH,
- (image_x, image_y))
+ settings.CHIMERE_THUMBS_SCALE_WIDTH, (image_x, image_y))
image.thumbnail([image_x, image_y], Image.ANTIALIAS)
temp_image = open(miniature_filename, 'w')
@@ -1030,8 +1387,8 @@ def picturefile_post_save(sender, **kwargs):
if not kwargs['created']:
return
- pfs = PictureFile.objects.filter(marker=picturefile.marker).exclude(
- pk=picturefile.pk).order_by('order')
+ pfs = PictureFile.objects.filter(marker=picturefile.marker)\
+ .exclude(pk=picturefile.pk).order_by('order')
for idx, pf in enumerate(pfs.all()):
pf.order = idx + 1
pf.save()
@@ -1039,12 +1396,13 @@ def picturefile_post_save(sender, **kwargs):
picturefile.save()
post_save.connect(picturefile_post_save, sender=PictureFile)
+
class RouteFile(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
raw_file = models.FileField(_(u"Raw file (gpx or kml)"),
upload_to='route_files')
- simplified_file = models.FileField(_(u"Simplified file"),
- upload_to='route_files', blank=True, null=True)
+ simplified_file = models.FileField(
+ _(u"Simplified file"), upload_to='route_files', blank=True, null=True)
TYPE = (('K', _(u'KML')), ('G', _(u'GPX')))
file_type = models.CharField(max_length=1, choices=TYPE)
@@ -1061,7 +1419,7 @@ class RouteFile(models.Model):
return
input_name = settings.MEDIA_ROOT + self.raw_file.name
output_name = settings.MEDIA_ROOT + self.raw_file.name[:-4] + \
- "_simplified" + ".gpx"
+ "_simplified" + ".gpx"
cli_args = [settings.GPSBABEL, '-i']
if self.file_type == 'K':
cli_args.append('kml')
@@ -1073,7 +1431,7 @@ class RouteFile(models.Model):
p.wait()
if p.returncode:
print p.stderr.read()
- #logger.error(p.stderr.read())
+ # logger.error(p.stderr.read())
else:
self.simplified_file = File(open(output_name))
self.save()
@@ -1091,32 +1449,33 @@ class RouteFile(models.Model):
if not pt.tag.endswith('trkpt'):
continue
pts.append((pt.get("lon"), pt.get("lat")))
- geojson_tpl = u'{"type":"Feature", "geometry":{ "type": "LineString", '\
- '"coordinates":[%s]}}'
wkt_tpl = u'LINESTRING(%s)'
- return wkt_tpl % u','.join([u'%s %s' % (pt[0], pt[1]) \
- for pt in pts])
+ return wkt_tpl % u','.join([u'%s %s' % (pt[0], pt[1])
+ for pt in pts])
+
class Route(GeographicItem):
'''Route on the map
'''
- ref_item = models.ForeignKey("Route", blank=True, null=True,
- verbose_name=_(u"Reference route"), related_name='submited_route')
+ ref_item = models.ForeignKey(
+ "Route", blank=True, null=True, verbose_name=_(u"Reference route"),
+ related_name='submited_route')
route = RouteField(_(u"Route"),
srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
associated_file = models.ForeignKey(RouteFile, blank=True, null=True,
verbose_name=_(u"Associated file"))
- picture = models.ImageField(_(u"Image"), upload_to='upload', blank=True,
- null=True, height_field='height', width_field='width')
+ picture = models.ImageField(
+ _(u"Image"), upload_to='upload', blank=True, null=True,
+ height_field='height', width_field='width')
height = models.IntegerField(_(u"Height"), blank=True, null=True)
width = models.IntegerField(_(u"Width"), blank=True, null=True)
has_associated_marker = models.BooleanField(_(u"Has an associated marker"),
default=True)
+ color = models.CharField(
+ _(u"Color"), max_length=200, help_text=_(u"HTML code/name"),
+ blank=True, null=True)
objects = models.GeoManager()
- def __unicode__(self):
- return self.name
-
class Meta:
ordering = ('status', 'name')
verbose_name = _(u"Route")
@@ -1141,11 +1500,7 @@ class Route(GeographicItem):
setattr(self, attr_name, val)
if not hasattr(self, attr_name + '_set'):
setattr(self, attr_name + '_set',
- property_setter(self.__class__, pm))
-
- @property
- def geometry(self):
- return self.route.wkt
+ property_setter(self.__class__, pm))
@property
def geom_attr(self):
@@ -1154,8 +1509,10 @@ class Route(GeographicItem):
def get_init_multi(self):
if not self.associated_marker.count():
return []
- multis = [forms.model_to_dict(multi)
- for multi in self.associated_marker.all()[0].multimedia_files.all()]
+ multis = [
+ forms.model_to_dict(multi)
+ for multi in self.associated_marker.all()[0].multimedia_files.all()
+ ]
return multis
def get_init_picture(self):
@@ -1165,72 +1522,59 @@ class Route(GeographicItem):
for pict in self.associated_marker.all()[0].pictures.all()]
return picts
- def getProperty(self, propertymodel, safe=None):
- """Get the property of an associated property model.
- If safe set to True, verify if the property is available
- """
- if safe and not propertymodel.available:
- return
- try:
- property = Property.objects.get(propertymodel=propertymodel,
- marker=self)
- except Property.DoesNotExist:
- return
- return property
-
- def getProperties(self):
- """Get all the property availables
- """
- properties = []
- for pm in PropertyModel.objects.filter(available=True):
- property = self.getProperty(pm)
- if property:
- properties.append(property)
- return properties
-
def getGeoJSON(self, color="#000"):
'''Return a GeoJSON string
'''
- if '#' not in color:
- color = '#' + color
try:
geom = json.loads(self.route.geojson)
except json.JSONDecodeError:
return json.dumps('{}')
- attributes = {"type":"Feature",
+ attributes = {"type": "Feature",
"geometry": geom,
- "properties":{"pk":self.id, "name":self.name,
- "color":color}}
+ "properties": {"pk": self.id, "name": self.name,
+ 'key': "route-{}".format(self.pk),
+ "color": color}}
return json.dumps(attributes)
- def getTinyUrl(self):
- parameters = 'current_feature=%d&checked_categories=%s' % (self.id,
- self.categories[0].id)
- return TinyUrl.getUrnByParameters(parameters)
+ def get_full_dict(self):
+ dct = super(Route, self).get_full_dict()
+ # to be done - use local unity
+ dct['length'] = self.route.length
+ return dct
pre_save_route_values = {}
+
+
def route_pre_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_pre_save(Route, pre_save_route_values)(sender, **kwargs)
pre_save.connect(route_pre_save, sender=Route)
+
def route_post_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_post_save(pre_save_route_values)(sender, **kwargs)
+ weighted_post_save(sender, **kwargs)
instance = kwargs['instance']
# manage associated marker
if instance.has_associated_marker:
marker_fields = [f.attname for f in Marker._meta.fields]
route_fields = [f.attname for f in Route._meta.fields]
- marker_dct = dict([(k, getattr(instance, k)) for k in marker_fields
- if k in route_fields and k not in ('id', 'ref_item_id')])
- marker_dct['point'] = "SRID=%d;POINT(%f %f)" % (instance.route.srid,
- instance.route[0][0], instance.route[0][1])
- marker, created = Marker.objects.get_or_create(route=instance,
- defaults=marker_dct)
+ marker_dct = dict(
+ [(k, getattr(instance, k)) for k in marker_fields
+ if k in route_fields and k not in ('id', 'ref_item_id')])
+ marker_dct['point'] = "SRID=%d;POINT(%f %f)" % (
+ instance.route.srid, instance.route[0][0], instance.route[0][1])
+ try:
+ marker, created = Marker.objects.get_or_create(route=instance,
+ defaults=marker_dct)
+ except MultipleObjectsReturned:
+ # db error - trying to continue...
+ marker = Marker.objects.filter(route=instance).all()[0]
+ created = False
if not created:
marker.status = instance.status
marker.point = marker_dct['point']
@@ -1248,6 +1592,7 @@ def route_post_save(sender, **kwargs):
post_save.connect(route_post_save, sender=Route)
+
def sync_m2m_route(sender, **kwargs):
if kwargs['action'] not in ('post_add', 'post_clear', 'post_remove'):
return
@@ -1263,6 +1608,7 @@ def sync_m2m_route(sender, **kwargs):
marker.categories.add(cat)
m2m_changed.connect(sync_m2m_route, sender=Route.categories.through)
+
def getDateCondition():
'''
Return an SQL condition for apparition of dates
@@ -1270,9 +1616,9 @@ def getDateCondition():
if not settings.CHIMERE_DAYS_BEFORE_EVENT:
return ""
now = datetime.datetime.now().strftime('%Y-%m-%d')
- after = (datetime.datetime.now() + \
- datetime.timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)
- ).strftime('%Y-%m-%d')
+ after = (datetime.datetime.now() +
+ datetime.timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)).strftime(
+ '%Y-%m-%d')
date_condition = " and (%(alias)s.start_date is null or "
date_condition += "(%(alias)s.start_date >= '" + now + "' and "
date_condition += "%(alias)s.start_date <='" + after + "')"
@@ -1280,6 +1626,7 @@ def getDateCondition():
date_condition += "%(alias)s.end_date >='" + now + "')) "
return date_condition
+
class AggregatedRoute(models.Model):
'''
Database view for aggregated routes
@@ -1287,6 +1634,7 @@ class AggregatedRoute(models.Model):
route = models.MultiLineStringField()
subcategory = models.ForeignKey(SubCategory)
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)
+
class Meta:
managed = False
db_table = 'chimere_aggregated_routes'
@@ -1300,11 +1648,14 @@ class AggregatedRoute(models.Model):
geom = json.loads(self.route.geojson)
except json.JSONDecodeError:
return json.dumps('{}')
- attributes = {'color':color, 'geometry': geom,
- 'type':"Feature", "properties":{"pk": self.id,
- "name": u'Aggregated route',}}
+ attributes = {
+ 'color': color, 'geometry': geom,
+ 'type': "Feature", "properties": {
+ 'key': "aggroute-{}".format(self.pk),
+ "pk": self.id, "name": u'Aggregated route'}}
return json.dumps(attributes)
+
class SimplePoint:
"""
Point in the map (not in the database)
@@ -1312,6 +1663,7 @@ class SimplePoint:
def __init__(self, x, y):
self.x, self.y = x, y
+
class SimpleArea:
"""
Rectangular area of a map (not in the database)
@@ -1347,7 +1699,7 @@ class SimpleArea:
for subcat in subcats:
subcategory_pks.append(unicode(subcat.pk))
if filter_available:
- wheres += ['subcat.available = TRUE', 'cat.available = TRUE']
+ wheres += ['subcat.available = TRUE', 'cat.available = TRUE']
wheres += ['subcat.id in (%s)' % ",".join(subcategory_pks)]
where = " where " + " and ".join(wheres) if wheres else ""
@@ -1357,13 +1709,13 @@ class SimpleArea:
elif status:
equal_status = " in ('%s')" % "','".join(status)
area = u"ST_GeometryFromText('POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f"\
- u"))', %d)" % (self.upper_left_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.upper_left_corner.y,
- settings.CHIMERE_EPSG_DISPLAY_PROJECTION
- )
+ u"))', %d)" % (
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
date_condition = getDateCondition()
sql_main = '''select subcat.id as id, subcat.category_id as category_id,
subcat.name as name, subcat.available as available,
@@ -1371,35 +1723,63 @@ class SimpleArea:
subcat.order as order, subcat.item_type as item_type
from chimere_subcategory subcat
inner join chimere_category cat on cat.id=subcat.category_id'''
+
sql = sql_main + '''
inner join chimere_marker mark on ST_Contains(%s, mark.point)''' % area
if equal_status:
sql += ' and mark.status' + equal_status
- sql += date_condition % {'alias':'mark'}
+ sql += date_condition % {'alias': 'mark'}
sql += '''
- inner join chimere_marker_categories mc on mc.subcategory_id=subcat.id and
- mc.marker_id=mark.id'''
+ inner join chimere_marker_categories mc on mc.subcategory_id=subcat.id
+ and mc.marker_id=mark.id'''
sql += where
subcats = set(SubCategory.objects.raw(sql))
+
sql = sql_main + '''
inner join chimere_route rt on (ST_Intersects(%s, rt.route) or
ST_Contains(%s, rt.route))''' % (area, area)
if equal_status:
sql += ' and rt.status' + equal_status
- sql += date_condition % {'alias':'rt'}
+ sql += date_condition % {'alias': 'rt'}
+ sql += '''
+ inner join chimere_route_categories rc on rc.subcategory_id=subcat.id
+ and rc.route_id=rt.id'''
+ sql += where
+ # subcats.union(set(SubCategory.objects.raw(sql)))
+ # set union behave strangely. Doing it manualy...
+ for c in set(SubCategory.objects.raw(sql)):
+ subcats.add(c)
+
+ sql = sql_main + '''
+ inner join chimere_polygon pol on (ST_Intersects(%s, pol.polygon) or
+ ST_Contains(%s, pol.polygon))''' % (area, area)
+ if equal_status:
+ sql += ' and pol.status' + equal_status
+ sql += date_condition % {'alias': 'pol'}
sql += '''
- inner join chimere_route_categories rc on rc.subcategory_id=subcat.id and
- rc.route_id=rt.id'''
+ inner join chimere_polygon_categories pc on pc.subcategory_id=subcat.id
+ and pc.polygon_id=pol.id'''
sql += where
- # subcats.union(set(SubCategory.objects.raw(sql)))
+ # subcats.union(set(SubCategory.objects.raw(sql)))
# set union behave strangely. Doing it manualy...
for c in set(SubCategory.objects.raw(sql)):
subcats.add(c)
+
return subcats
+ def getExtent(self):
+ return (unicode(self.upper_left_corner.x),
+ unicode(self.upper_left_corner.y),
+ unicode(self.lower_right_corner.x),
+ unicode(self.lower_right_corner.y))
+
+
class Layer(models.Model):
name = models.CharField(_(u"Name"), max_length=150)
- layer_code = models.TextField(_(u"Layer code"), max_length=300)
+ layer_code = models.TextField(_(u"Layer code"))
+ extra_js_code = models.TextField(
+ _(u"Extra JS code"), blank=True, null=True, default='',
+ help_text=_(u"This code is loaded before the layer code."))
def __unicode__(self):
return self.name
@@ -1407,6 +1787,7 @@ class Layer(models.Model):
class Meta:
verbose_name = _("Layer")
+
class Area(models.Model, SimpleArea):
"""Rectangular area of the map
"""
@@ -1417,29 +1798,47 @@ class Area(models.Model, SimpleArea):
null=True)
order = models.IntegerField(_(u"Order"), unique=True)
available = models.BooleanField(_(u"Available"))
- upper_left_corner = models.PointField(_(u"Upper left corner"),
- default='POINT(0 0)', srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
- lower_right_corner = models.PointField(_(u"Lower right corner"),
- default='POINT(0 0)', srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
- default = models.NullBooleanField(_(u"Default area"),
- help_text=_(u"Only one area is set by default"))
+ upper_left_corner = models.PointField(
+ _(u"Upper left corner"), default='POINT(0 0)',
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ lower_right_corner = models.PointField(
+ _(u"Lower right corner"), default='POINT(0 0)',
+ srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION)
+ default = models.NullBooleanField(
+ _(u"Default area"), help_text=_(u"Only one area is set by default"))
layers = SelectMultipleField(Layer, related_name='areas',
through='AreaLayers', blank=True)
- default_subcategories = SelectMultipleField(SubCategory, blank=True,
- verbose_name=_(u"Sub-categories checked by default"))
+ default_subcategories = SelectMultipleField(
+ SubCategory, blank=True,
+ verbose_name=_(u"Sub-categories checked by default"))
dynamic_categories = models.NullBooleanField(
_(u"Sub-categories dynamicaly displayed"),
- help_text=_(u"If checked, categories are only displayed in the menu if "
- u"they are available on the current extent."))
- subcategories = SelectMultipleField(SubCategory, related_name='areas',
- blank=True, db_table='chimere_subcategory_areas',
- verbose_name=_(u"Restricted to theses sub-categories"),
- help_text=_(u"If no sub-category is set all sub-categories are "
- u"available"))
+ help_text=_(u"If checked, categories are only displayed in the menu "
+ u"if they are available on the current extent."))
+ subcategories = SelectMultipleField(
+ SubCategory, related_name='areas',
+ blank=True, db_table='chimere_subcategory_areas',
+ verbose_name=_(u"Restricted to theses sub-categories"),
+ help_text=_(u"If no sub-category is set all sub-categories are "
+ u"available"))
+ display_category_menu = models.BooleanField(
+ _(u"Display category menu"), default=True,
+ help_text=_(u"If set to False, category menu will be hide and all "
+ u"categories will be always displayed."))
external_css = models.URLField(_(u"Link to an external CSS"), blank=True,
null=True)
restrict_to_extent = models.BooleanField(_(u"Restrict to the area extent"),
default=False)
+ allow_point_edition = models.BooleanField(_(u"Allow point edition"),
+ default=True)
+ allow_route_edition = models.BooleanField(_(u"Allow route edition"),
+ default=True)
+ allow_polygon_edition = models.BooleanField(_(u"Allow polygon edition"),
+ default=True)
+ extra_map_def = models.TextField(
+ _(u"Extra map definition"), blank=True, null=True,
+ help_text=_(u"Extra javascript script loaded for this area. "
+ u"Carreful! To prevent breaking the map must be valid."))
objects = models.GeoManager()
def __unicode__(self):
@@ -1457,13 +1856,13 @@ class Area(models.Model, SimpleArea):
def getWkt(self):
return "SRID=%d;POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f))" % (
- settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- self.upper_left_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.upper_left_corner.y,
- )
+ settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.upper_left_corner.y,
+ self.lower_right_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.lower_right_corner.y,
+ self.upper_left_corner.x, self.upper_left_corner.y,
+ )
def getIncludeMarker(self):
"""
@@ -1477,13 +1876,22 @@ class Area(models.Model, SimpleArea):
"""
return Q(route__contained=self.getWkt())
+ def getIncludePolygon(self):
+ """
+ Get the sql statement for the test if the route is included in the area
+ """
+ return Q(polygon__contained=self.getWkt())
+
pre_save_area_values = {}
+
+
def area_pre_save(sender, **kwargs):
if not kwargs['instance']:
return
geometry_pre_save(Area, pre_save_area_values)(sender, **kwargs)
pre_save.connect(area_pre_save, sender=Area)
+
def area_post_save(sender, **kwargs):
if not kwargs['instance']:
return
@@ -1497,7 +1905,7 @@ def area_post_save(sender, **kwargs):
old_urn, old_name = area.urn, area.name
if area.pk in pre_save_area_values:
old_urn, old_name = pre_save_area_values[area.pk]
- perm, old_groups, old_users = None, [], []
+ perm = None
if area.urn != old_urn:
oldmnemo = 'change_area_' + old_urn
old_perm = Permission.objects.filter(codename=oldmnemo)
@@ -1513,7 +1921,7 @@ def area_post_save(sender, **kwargs):
lbl = "Can change " + area.name
if not perm.count():
content_type, created = ContentType.objects.get_or_create(
- app_label="chimere", model="area")
+ app_label="chimere", model="area")
perm = Permission(name=lbl, content_type_id=content_type.id,
codename=mnemo)
perm.save()
@@ -1537,16 +1945,18 @@ def area_post_save(sender, **kwargs):
group.permissions.add(perm)
for app_label, model in (('chimere', 'marker'),
('chimere', 'route'),
+ ('chimere', 'polygon'),
('chimere', 'multimediafile'),
('chimere', 'picturefile'),
('chimere', 'routefile')):
- ct, created = ContentType.objects.get_or_create(app_label=app_label,
- model=model)
+ ct, created = ContentType.objects.get_or_create(
+ app_label=app_label, model=model)
for p in Permission.objects.filter(content_type=ct).all():
group.permissions.add(p)
post_save.connect(area_post_save, sender=Area)
+
def get_areas_for_user(user):
"""
Getting subcats for a specific user
@@ -1563,12 +1973,14 @@ def get_areas_for_user(user):
pass
return areas
+
def get_users_by_area(area):
if not area:
return []
- perm = 'change_area_'+area.urn
- return User.objects.filter(Q(groups__permissions__codename=perm)|
- Q(user_permissions__codename=perm)).all()
+ perm = 'change_area_' + area.urn
+ return User.objects.filter(Q(groups__permissions__codename=perm) |
+ Q(user_permissions__codename=perm)).all()
+
class AreaLayers(models.Model):
area = models.ForeignKey(Area)
@@ -1581,48 +1993,74 @@ class AreaLayers(models.Model):
verbose_name = _("Layers")
verbose_name_plural = _("Layers")
+
class PropertyModel(models.Model):
'''Model for a property
'''
name = models.CharField(_(u"Name"), max_length=150)
+ slug = models.SlugField(_(u"Slug"), blank=True, null=True)
order = models.IntegerField(_(u"Order"))
available = models.BooleanField(_(u"Available"))
mandatory = models.BooleanField(_(u"Mandatory"))
- subcategories = SelectMultipleField(SubCategory, related_name='properties',
- blank=True, verbose_name=_(u"Restricted to theses sub-categories"),
- help_text=_(u"If no sub-category is set all the property applies to all "
- u"sub-categories"))
+ subcategories = SelectMultipleField(
+ SubCategory, related_name='properties',
+ blank=True, verbose_name=_(u"Restricted to theses sub-categories"),
+ help_text=_(u"If no sub-category is set all the property applies to "
+ u"all sub-categories"))
+ areas = SelectMultipleField(
+ 'Area', verbose_name=_(u"Restrict to theses areas"), blank=True,
+ null=True,
+ help_text=_(u"If no area is set the property apply to "
+ u"all areas"))
TYPE = (('T', _('Text')),
('L', _('Long text')),
('P', _('Password')),
('D', _("Date")),
('C', _("Choices")),
+ ('A', _("Choices (autocomplete)")),
('B', _("Boolean")),
)
- TYPE_WIDGET = {'T':forms.TextInput,
- 'L':TextareaWidget,
- 'P':forms.PasswordInput,
- 'D':DatePickerWidget,
- 'C':forms.Select,
- 'B':forms.CheckboxInput,
+ TYPE_WIDGET = {'T': forms.TextInput,
+ 'L': TextareaWidget,
+ 'P': forms.PasswordInput,
+ 'D': DatePickerWidget,
+ 'C': forms.Select,
+ 'A': JQueryAutoComplete,
+ 'B': forms.CheckboxInput,
}
type = models.CharField(_(u"Type"), max_length=1, choices=TYPE)
- def __unicode__(self):
- return self.name
+
class Meta:
ordering = ('order',)
verbose_name = _("Property model")
+ def __unicode__(self):
+ return self.name
+
def getAttrName(self):
- attr_name = defaultfilters.slugify(self.name)
- attr_name = re.sub(r'-','_', attr_name)
- return attr_name
+ return self.slug
def getNamedId(self):
'''Get the name used as named id (easily sortable)
'''
return 'property_%d_%d' % (self.order, self.id)
+ @classmethod
+ def getAvailable(cls, area_name=None):
+ if area_name and area_name.endswith('/'):
+ area_name = area_name[:-1]
+ base_q = cls.objects.filter(available=True).annotate(Count('areas'))
+ q1 = base_q.filter(areas__count=0)
+ if not area_name:
+ return [q1]
+ # areas__count__gt=0 necessary to prevent Django bug
+ q2 = base_q.filter(Q(areas__urn=area_name) & Q(areas__count__gt=0))
+ # if made it a single queryset the condition on 'count' is
+ # wrong - hope this will be fixed on higher Django version (>=1.4)
+ # to make a single query
+ return [q1, q2]
+
+
class PropertyModelChoice(models.Model):
'''Choices for property model
'''
@@ -1630,26 +2068,32 @@ class PropertyModelChoice(models.Model):
verbose_name=_(u"Property model"))
value = models.CharField(_(u"Value"), max_length=150)
available = models.BooleanField(_(u"Available"), default=True)
- def __unicode__(self):
- return unicode(self.value)
class Meta:
verbose_name = _(u"Model property choice")
+ def __unicode__(self):
+ return unicode(self.value)
+
+
class Property(models.Model):
'''Property for a POI
'''
- marker = models.ForeignKey(Marker, verbose_name=_(u"Point of interest"))
+ marker = models.ForeignKey(
+ Marker, verbose_name=_(u"Point of interest"), blank=True, null=True)
+ polygon = models.ForeignKey(
+ Polygon, verbose_name=_(u"Polygon"), blank=True, null=True)
propertymodel = models.ForeignKey(PropertyModel,
verbose_name=_(u"Property model"))
value = models.TextField(_(u"Value"))
+
def __unicode__(self):
if self.propertymodel.type == 'C':
if not self.value:
return ''
try:
return unicode(PropertyModelChoice.objects.get(
- pk=self.value).value)
+ pk=self.value).value)
except (self.DoesNotExist, ValueError):
return ""
return unicode(self.value)
@@ -1661,7 +2105,8 @@ class Property(models.Model):
def python_value(self):
if self.propertymodel.type == 'D':
try:
- return datetime.date(*[int(val) for val in self.value.split('-')])
+ return datetime.date(*[int(val)
+ for val in self.value.split('-')])
except:
return ""
if self.propertymodel.type == 'C' and self.value:
@@ -1671,4 +2116,3 @@ class Property(models.Model):
return None
else:
return self.value
-
diff --git a/chimere/route.py b/chimere/route.py
index 8c4638a..31cf4f0 100644
--- a/chimere/route.py
+++ b/chimere/route.py
@@ -22,7 +22,10 @@
Routing management
"""
-import os, re, shutil, tempfile
+import os
+import re
+import shutil
+import tempfile
from BeautifulSoup import BeautifulSoup
from subprocess import Popen, PIPE
from django.contrib.gis.gdal import DataSource
@@ -30,6 +33,7 @@ from django.contrib.gis.gdal.error import OGRException
from django.conf import settings
+
class Router:
def route(self, lon1, lat1, lon2, lat2, transport='foot'):
'''
@@ -37,9 +41,11 @@ class Router:
'''
return []
+
class RoutinoRouter(Router):
re_desc = [re.compile("<tr class='n'>"), re.compile("<tr class='s'>"),
re.compile("<tr class='t'>")]
+
def route(self, lon1, lat1, lon2, lat2, steps=[], transport='foot',
speed=None):
'''
@@ -57,10 +63,12 @@ class RoutinoRouter(Router):
"--lon1=%0.15f" % lon1,
]
if speed:
- args += ["--speed-%s=%s" % (highway, unicode(speed))
- for highway in ('motorway', 'trunk', 'primary', 'secondary',
- 'tertiary', 'unclassified', 'residential', 'service',
- 'track','cycleway','path','steps')]
+ args += [
+ "--speed-%s=%s" % (highway, unicode(speed))
+ for highway in (
+ 'motorway', 'trunk', 'primary', 'secondary', 'tertiary',
+ 'unclassified', 'residential', 'service', 'track',
+ 'cycleway', 'path', 'steps')]
lonlat_index = 1
for lon, lat in steps:
lonlat_index += 1
@@ -97,9 +105,8 @@ class RoutinoRouter(Router):
desc = desc[1:-2]
# very fragile piece of code but only break the numerotation
number_tpl = '<tr class="n"><span class="number">%d.</span>'
- desc = [re.sub('<tr class="n">', number_tpl % (idx/2+1), d)
- if idx % 2 else d
- for idx, d in enumerate(desc)]
+ desc = [re.sub('<tr class="n">', number_tpl % (idx / 2 + 1), d)
+ if idx % 2 else d for idx, d in enumerate(desc)]
desc = self.webify(BeautifulSoup('\n'.join(desc)).prettify())
desc = re.sub(" \[", "", desc)
desc = re.sub(" \]", "", desc)
@@ -118,4 +125,3 @@ router = None
if hasattr(settings, 'CHIMERE_ROUTING_ENGINE') and \
settings.CHIMERE_ROUTING_ENGINE['ENGINE'] == 'routino':
router = RoutinoRouter()
-
diff --git a/chimere/static/bsmSelect/MIT-LICENSE.txt b/chimere/static/bsmSelect/MIT-LICENSE.txt
index 908016b..c5d6611 100644
--- a/chimere/static/bsmSelect/MIT-LICENSE.txt
+++ b/chimere/static/bsmSelect/MIT-LICENSE.txt
@@ -1,5 +1,5 @@
Copyright (c) 2008 by Ryan Cramer, http://www.ryancramer.com
-Copyright (c) 2010 by Victor Berchet
+Copyright (c) 2010-2013 by Victor Berchet
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -18,4 +18,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/chimere/static/bsmSelect/README.md b/chimere/static/bsmSelect/README.md
index bd14c6a..8d65624 100644
--- a/chimere/static/bsmSelect/README.md
+++ b/chimere/static/bsmSelect/README.md
@@ -50,7 +50,8 @@ The newly created select default option is the original select title attribute:
* listType:
* Specify what list will be created or used as part of the bsmSelect.
- * Can accept a callback that accepts the original <select> as an argument and returns a jQuery object with a single list.
+ * Can accept a callback that accepts the original <select> as an argument and
+ returns a jQuery object with a single list.
* Allowed values:
* 'ol'
* 'ul'
@@ -88,13 +89,16 @@ The newly created select default option is the original select title attribute:
* addItemTarget:
* Where to place new selected items that are added to the list.
- * Allowed values: 'top' or 'bottom' or 'original' to keep the original select sort order
+ * Allowed values: 'top' or 'bottom' or 'original' to keep the original select
+ sort order
* Default: 'bottom'
- * Note: When using the 'original' mode, the sort order can be overriden by setting the 'bsm-order' data on each option.
+ * Note: When using the 'original' mode, the sort order can be overriden by setting
+ the 'bsm-order' data on each option.
* debugMode:
- * Keeps original select multiple visible so that you can monitor live changes made to it when debugging.
+ * Keeps original select multiple visible so that you can monitor live changes
+ made to it when debugging.
* Default: false
* extractLabel:
@@ -104,14 +108,16 @@ The newly created select default option is the original select title attribute:
* plugins
- * An array of plugins objects to enable (they only are required to have an `init` method which is called on init with the Bsmselect instance as single argument).
+ * An array of plugins objects to enable (they only are required to have an `init`
+ method which is called on init with the Bsmselect instance as single argument).
* Default: an empty array (no plugin enabled by default)
### Text Labels ###
* title
- * Text used for the default select label (when original select title attribute is not set)
+ * Text used for the default select label (when original select title attribute
+ is not set)
* Default: 'Select...'
* removeLabel:
@@ -179,7 +185,9 @@ The newly created select default option is the original select title attribute:
* [Victor Berchet](http://github.com/vicb) is the author of bsmSelect
* [Andy Fowler](http://github.com/andyfowler) has contributed many enhancements
* [Cracky](https://github.com/Cracky)
- * [Marc Busqué](https://github.com/laMarciana) has contributed to fix [issue #21](https://github.com/vicb/bsmSelect/issues/21) and with minimal CSS
+ * [Marc Busqué](https://github.com/laMarciana) has contributed to fix
+ [issue #21](https://github.com/vicb/bsmSelect/issues/21) and with minimal CSS
+ * [DrewBe121212](https://github.com/DrewBe121212) has fixed issues 28 et 29.
## History ##
diff --git a/chimere/static/bsmSelect/css/jquery.bsmselect.css b/chimere/static/bsmSelect/css/jquery.bsmselect.css
index ad770d0..cc35cc3 100644
--- a/chimere/static/bsmSelect/css/jquery.bsmselect.css
+++ b/chimere/static/bsmSelect/css/jquery.bsmselect.css
@@ -36,7 +36,7 @@
list-style: none;
background: #ddd;
border: 1px solid #bbb;
- width: 100%;
+ width: auto;
margin: 0 0 -1px 0;
line-height: 1em;
}
@@ -62,3 +62,9 @@
top: 0;
padding: 5px;
}
+
+.bsmScrollWorkaround {
+ /* Fix a bug when the 'html' element has an overflow set to either 'scroll' or 'auto' on FF. */
+ padding-bottom: 1px;
+ overflow: auto;
+}
diff --git a/chimere/static/bsmSelect/js/jquery.bsmselect.compatibility.js b/chimere/static/bsmSelect/js/jquery.bsmselect.compatibility.js
index a743a07..683d865 100644
--- a/chimere/static/bsmSelect/js/jquery.bsmselect.compatibility.js
+++ b/chimere/static/bsmSelect/js/jquery.bsmselect.compatibility.js
@@ -1,17 +1,17 @@
/*
* Better Select Multiple Compatibility Plugin - jQuery Plugin
*
- * Copyright (c) 2010 by Victor Berchet - http://www.github.com/vicb
+ * Copyright (c) 2010-2011 by Victor Berchet - http://www.github.com/vicb
*
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
*
- * version: v1.0.0 - 2010-09-05
+ * version: v1.0.1 - 2011-11-14
*/
(function($) {
$.bsmSelect.plugins.compatibility = function()
{
- if (!(this instanceof arguments.callee)) {
- return new arguments.callee();
+ if (!(this instanceof $.bsmSelect.plugins.compatibility)) {
+ return new $.bsmSelect.plugins.compatibility();
}
}
@@ -31,7 +31,7 @@
o.showEffect = $.bsmSelect.effects[o.animate.add];
} else {
o.showEffect = $.bsmSelect.effects.show;
- }
+ }
if ($.isFunction(o.animate.drop)) {
o.hideEffect = o.animate.drop;
diff --git a/chimere/static/bsmSelect/js/jquery.bsmselect.js b/chimere/static/bsmSelect/js/jquery.bsmselect.js
index 25527c6..7751418 100644
--- a/chimere/static/bsmSelect/js/jquery.bsmselect.js
+++ b/chimere/static/bsmSelect/js/jquery.bsmselect.js
@@ -4,11 +4,11 @@
* based on Alternate Select Multiple (asmSelect) 1.0.4a beta (http://www.ryancramer.com/projects/asmselect/)
*
* Copyright (c) 2009 by Ryan Cramer - http://www.ryancramer.com
- * Copyright (c) 2010 by Victor Berchet - http://www.github.com/vicb
+ * Copyright (c) 2010-2013 by Victor Berchet - http://www.github.com/vicb
*
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
*
- * bsmSelect version: v1.4.3 - 2011-05-05
+ * bsmSelect version: v1.4.7 - 2013-12-19
*/
(function($) {
@@ -39,7 +39,7 @@
if (o.addItemTarget === 'original') {
$('option', this.$original).each(function(i, o) {
- if ($(o).data('bsm-order') === null) { $(o).data('bsm-order', i); }
+ if ($(o).data('bsm-order') === undefined) { $(o).data('bsm-order', i); }
});
}
@@ -47,7 +47,6 @@
this.$select = $('<select>', {
'class': o.selectClass,
- name: o.selectClass + this.uid,
id: o.selectClass + this.uid,
change: $.proxy(this.selectChangeEvent, this),
click: $.proxy(this.selectClickEvent, this)
@@ -69,7 +68,7 @@
if (!this.$list.parent().length) { this.$original.before(this.$list); }
if (this.$original.attr('id')) {
- $('label[for=' + this.$original.attr('id') + ']').attr('for', this.$select.attr('id'));
+ $("label[for='" + this.$original.attr('id') + "']").attr('for', this.$select.attr('id'));
}
// set up remove event (may be a link, or the list item itself)
@@ -86,11 +85,12 @@
* Check to make sure it's not an IE screwup, and add it to the list
*/
selectChangeEvent: function() {
- if ($.browser.msie && $.browser.version < 7 && !this.ieClick) { return; }
+ if ($.browser && $.browser.msie && $.browser.version < 7 && !this.ieClick) { return; }
var bsmOpt = $('option:selected:eq(0)', this.$select);
if (bsmOpt.data('orig-option')) {
- this.addListItem(bsmOpt);
- this.triggerOriginalChange(bsmOpt.data('orig-option'), 'add');
+ if (this.triggerOriginalChange(bsmOpt.data('orig-option'), 'add') == false) {
+ this.addListItem(bsmOpt);
+ }
}
this.ieClick = false;
},
@@ -115,7 +115,7 @@
this.buildSelect();
// opera has an issue where it needs a force redraw, otherwise
// the items won't appear until something else forces a redraw
- if ($.browser.opera) { this.$list.hide().show(); }
+ if ($.browser && $.browser.opera) { this.$list.hide().show(); }
}
},
@@ -198,7 +198,7 @@
.removeAttr('selected')
.attr('disabled', 'disabled')
.toggle(!this.options.hideWhenAdded);
- if ($.browser.msie && $.browser.version < 8) { this.$select.hide().show(); } // this forces IE to update display
+ if ($.browser && $.browser.msie && $.browser.version < 8) { this.$select.hide().show(); } // this forces IE to update display
},
/**
@@ -210,7 +210,7 @@
$bsmOpt.removeClass(this.options.optionDisabledClass)
.removeAttr('disabled')
.toggle(!this.options.hideWhenAdded);
- if ($.browser.msie && $.browser.version < 8) { this.$select.hide().show(); } // this forces IE to update display
+ if ($.browser && $.browser.msie && $.browser.version < 8) { this.$select.hide().show(); } // this forces IE to update display
},
/**
@@ -243,7 +243,7 @@
break;
case 'original':
var order = $origOpt.data('bsm-order'), inserted = false;
- $('.' + o.listItemClass, this.$list).each(function() {
+ this.$list.children().each(function() {
if (order < $(this).data('bsm-option').data('orig-option').data('bsm-order')) {
$item.hide().insertBefore(this);
inserted = true;
@@ -268,15 +268,16 @@
/**
* Remove an item from the list of selection
*
- * @param {jQuey} $item A list item
+ * @param {jQuery} $item A list item
*/
dropListItem: function($item) {
var $bsmOpt = $item.data('bsm-option'), o = this.options;
- $bsmOpt.removeData('item').data('orig-option').removeAttr('selected');
- (this.buildingSelect ? $.bsmSelect.effects.remove : o.hideEffect)($item);
- this.enableSelectOption($bsmOpt);
- o.highlightEffect(this.$select, $item, o.highlightRemovedLabel, o);
- this.triggerOriginalChange($bsmOpt.data('orig-option'), 'drop');
+ if (this.triggerOriginalChange($bsmOpt.data('orig-option'), 'drop') == false) {
+ $bsmOpt.removeData('item').data('orig-option').removeAttr('selected');
+ (this.buildingSelect ? $.bsmSelect.effects.remove : o.hideEffect)($item);
+ this.enableSelectOption($bsmOpt);
+ o.highlightEffect(this.$select, $item, o.highlightRemovedLabel, o);
+ }
},
/**
@@ -285,15 +286,19 @@
*
* @param {jQuery} $origOpt The option from the original select
* @param {String} type Event type
+ *
+ * @return Whether the event default is prevented
*/
triggerOriginalChange: function($origOpt, type) {
+ var event = $.Event('change');
this.ignoreOriginalChangeEvent = true;
- this.$original.trigger('change', [{
+ this.$original.trigger(event, [{
option: $origOpt,
value: $origOpt.val(),
item: $origOpt.data('bsm-option').data('item'),
type: type
}]);
+ return event.isDefaultPrevented();
}
};
diff --git a/chimere/static/bsmSelect/js/jquery.bsmselect.sortable.js b/chimere/static/bsmSelect/js/jquery.bsmselect.sortable.js
index 3e4b9f8..cd79028 100644
--- a/chimere/static/bsmSelect/js/jquery.bsmselect.sortable.js
+++ b/chimere/static/bsmSelect/js/jquery.bsmselect.sortable.js
@@ -1,17 +1,17 @@
/*
* Better Select Multiple Sortable Plugin
*
- * Copyright (c) 2010 by Victor Berchet - http://www.github.com/vicb
+ * Copyright (c) 2010-2012 by Victor Berchet - http://www.github.com/vicb
*
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
*
- * version: v1.1.1 - 2010-11-17
+ * version: v1.4.4 - 2012-01-19
*/
(function($) {
$.bsmSelect.plugins.sortable = function(sortConfig, options)
{
- if (!(this instanceof arguments.callee)) {
- return new arguments.callee(sortConfig, options);
+ if (!(this instanceof $.bsmSelect.plugins.sortable)) {
+ return new $.bsmSelect.plugins.sortable(sortConfig, options);
}
this.sortConfig = sortConfig;
this.options = $.extend({}, this.defaultOpt, options || {});
@@ -27,13 +27,18 @@
config = $.extend({}, this.sortConfig, { items: '.' + o.listItemClass }),
self = this;
bsm.$list.addClass(o.listSortableClass).sortable(config);
+ // Fix a bug when the 'html' element has an overflow set to either 'scroll' or 'auto' on FF.
+ // See issue #21 (https://github.com/vicb/bsmSelect/issues/21)
+ if ($.inArray($('html').css('overflow-x'), ['auto', 'scroll']) > -1 || $.inArray($('html').css('overflow-y'), ['auto', 'scroll']) > -1) {
+ $('.' + o.listSortableClass).addClass('bsmScrollWorkaround');
+ }
bsm.$original.bind('change', function(e, info) { self.onChange.call(self, bsm, e, info); } );
bsm.$list.bind('sortupdate', function(e, ui) { self.onSort.call(self, bsm, e, ui); } );
},
onChange: function(bsm, e, info) {
- if (info && info.type == 'add' && !bsm.buildingSelect) {
- info.option.detach()[bsm.options.addItemTarget == 'top' ? 'prependTo' : 'appendTo'](bsm.$original);
+ if (info && info.type === 'add' && !bsm.buildingSelect) {
+ info.option.detach()[bsm.options.addItemTarget === 'top' ? 'prependTo' : 'appendTo'](bsm.$original);
bsm.$list.sortable('refresh');
}
},
@@ -46,4 +51,3 @@
}
});
})(jQuery);
-
diff --git a/chimere/static/chimere/css/forms.css b/chimere/static/chimere/css/forms.css
index 2c852d7..0a22e74 100644
--- a/chimere/static/chimere/css/forms.css
+++ b/chimere/static/chimere/css/forms.css
@@ -14,32 +14,44 @@
/**/
-div.rightWrapper{
- width: 100%;
- float:left;
+.bsmSelect{
+ max-width: 300px;
}
+ div.rightWrapper{
+ width: 90%;
+ }
-div.rightform{
- margin-left:400px;
- height:400px;
-}
-div.leftform{
- float: left;
- width: 400px;
- margin-left: -100%;
+@media (min-width: 900px) {
+
+ div.rightWrapper{
+ width: 60%;
+ float:right;
+ }
+
+ div.leftform{
+ width: 40%;
+ float:left;
+ }
+
}
div.bottomform{
- clear: left;
+ clear: both;
width: 100%;
}
+.fieldWrapper.full{
+ width:100%;
+ display:block;
+}
+
#map_edit, #map_edit_area{
- margin:0;
+ margin: 0;
border: 1px solid black;
- width:100%;
- height:350px;
+ width: 100%;
+ height: 350px;
+ clear: both;
}
#map_edit #OpenLayers_Control_MaximizeDiv,
@@ -47,6 +59,10 @@ div.bottomform{
display:none;
}
+.edit #map_edit{
+ height: 500px;
+}
+
.map_button{
position:absolute;
z-index:1000;
@@ -69,7 +85,6 @@ div.bottomform{
#live_lonlat{
margin:1em;
- float:left;
}
#live_lonlat p{
diff --git a/chimere/static/chimere/css/styles.css b/chimere/static/chimere/css/styles.css
index c23e843..3c2b2e7 100644
--- a/chimere/static/chimere/css/styles.css
+++ b/chimere/static/chimere/css/styles.css
@@ -36,9 +36,13 @@ h2, h3, th, .action li, .action li a,
color:#000;
}
+th{
+ color: #449506;
+}
+
/* background-color definition */
-body, h2, h3, th,
+body, h2, h3,
.ui-widget-header,
#layer_selection h4,
.action li.selected, #no-js-message,
@@ -58,8 +62,7 @@ fieldset, .action li, #content,
#welcome, #detail, .detail_footer a,
#content .olControlLayerSwitcher .layersDiv,
#content .olControlLayerSwitcher span,
-#chimere_total_label td.l,
-#main-map, .window{
+#chimere_total_label td.l, .window{
background-color:#FFF;
}
@@ -174,7 +177,7 @@ fieldset{
}
.edit label{
- display:block;
+ display: block;
}
a:link[disabled],
@@ -674,6 +677,7 @@ ul.subcategories label img{
height:20px;
}
+li.main_category .category_name:hover,
li.main_category > span:hover,
li.main_category label:hover{
cursor:pointer;
@@ -688,8 +692,7 @@ li.main_category label:hover{
}
.control_image{
- cursor:pointer;
- vertical-align:text-bottom;
+ display: none;
}
.errorlist{
@@ -749,6 +752,18 @@ a#welcome_button,
/* forms */
+button{
+ padding: 2px 4px;
+ font-size: 14px;
+ line-height: 1.42857;
+ color: #555;
+ vertical-align: middle;
+ background-color: #FFF;
+ border: 1px solid #CCC;
+ border-radius: 4px;
+ box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset;
+}
+
table.inline-table{
}
@@ -769,6 +784,11 @@ table.inline-table td input[type=file]{
width:260px;
}
+table.inline-table td input[type=file]{
+ border: 0 solid transparent;
+ box-shadow: none;
+}
+
#live_lonlat p{
display:inline-table;
}
@@ -870,13 +890,12 @@ ul#multimedia_list_content li.multimedia{
}
#waiting-content {
- width:95px;
- position:relative;
- margin:0 auto;
- background-color:white;
- padding:10px 5px 0 5px;
- border:1px solid black;
- text-align:center;
+ width: 35px;
+ position: relative;
+ margin: 0 auto;
+ padding: 0;
+ border: 1px solid #ccc;
+ text-align: center;
}
/* openlayer customisation */
@@ -1205,3 +1224,76 @@ div.pp_default .pp_expand{
left:6px;
bottom:5px;
}
+
+
+/* ol3 */
+
+.ol-zoom{
+ right: .5em;
+ left: auto;
+ top: 3em;
+}
+
+.ol-attribution{
+ right: 12em;
+ bottom: 2.5em;
+}
+
+.ol-overviewmap{
+ right: .5em;
+ left: auto;
+}
+
+.ol-scale-line{
+ right: 12em;
+ left: auto;
+}
+
+
+.LayerSwitcher {
+ width:20em;
+ margin:0.5em;
+ padding:0.5em;
+ z-index:100;
+ position: absolute;
+ background-color: rgba(255,255,255,0.7);
+}
+
+.LayerSwitcher .LayerClickDiv, .LayerSwitcher .LayerClickDiv * {
+ cursor:pointer;
+}
+
+.LayerClickDiv {
+ margin: 0.1em;
+ line-height: 1em;
+}
+
+.LayerSwitcher .Separator {
+ border-bottom:1px solid #999999;
+ margin:0.5em;
+}
+.LayerSwitcher .check {
+ border:1px solid #999999;
+ height:1em;
+ width:1em;
+ background:transparent;
+ float:left;
+ margin: 0 0.5em 0 0;
+}
+.LayerSwitcher .checkbox {
+ /* border-radius:0.2em; */
+}
+.LayerSwitcher .checkbox.checked {
+ background:#666666;
+}
+.LayerSwitcher .radiobutton {
+ border-radius:1em;
+}
+.LayerSwitcher .radiobutton.checked {
+ background:#666666;
+}
+
+.OverlayDiv label{
+ line-height: 20px;
+}
+
diff --git a/chimere/static/chimere/js/edit_area.js b/chimere/static/chimere/js/edit_area.js
index 019ed39..ea30038 100644
--- a/chimere/static/chimere/js/edit_area.js
+++ b/chimere/static/chimere/js/edit_area.js
@@ -23,39 +23,173 @@ var bbox_style = {fill: true, fillColor: "#FFFFFF", fillOpacity: 0.5,
var area_map;
var box_layer;
+var draw;
+var source_features;
+var features = new ol.Collection();
+var old_geom;
-function initForm(bounds){
+function initArea(bounds){
+ if(!bounds) return;
+ area_map.getView().fit(bounds, area_map.getSize());
+ var poly = [
+ [parseFloat(bounds[0]), parseFloat(bounds[1])],
+ [parseFloat(bounds[0]), parseFloat(bounds[3])],
+ [parseFloat(bounds[2]), parseFloat(bounds[3])],
+ [parseFloat(bounds[2]), parseFloat(bounds[1])]
+ ];
+ var feature = new ol.Feature({
+ geometry: new ol.geom.Polygon([poly])
+ });
+ features.push(feature);
+ updateForm(bounds);
}
-/* update form fields on select action */
function updateForm(bounds){
- if(!bounds.toGeometry) return;
- var feature = new OpenLayers.Feature.Vector(
- bounds.toGeometry(), {}, bbox_style);
- box_layer.destroyFeatures()
- box_layer.addFeatures(feature);
- var bounds = bounds.clone().transform(epsg_projection,
- epsg_display_projection);
- document.getElementById('upper_left_lat').value = bounds.top;
- document.getElementById('upper_left_lon').value = bounds.left;
- document.getElementById('lower_right_lat').value = bounds.bottom;
- document.getElementById('lower_right_lon').value = bounds.right;
+ document.getElementById('upper_left_lat').value = bounds[1];
+ document.getElementById('upper_left_lon').value = bounds[0];
+ document.getElementById('lower_right_lat').value = bounds[3];
+ document.getElementById('lower_right_lon').value = bounds[2];
}
/* main initialisation function */
function init(map_edit){
map_edit = typeof map_edit !== 'undefined' ? map_edit : 'map_edit';
- area_map = new OpenLayers.Map (map_edit, {
- controls:[new OpenLayers.Control.Navigation(),
- new OpenLayers.Control.SimplePanZoom()],
+
+ var view_options = {
maxResolution: 156543.0399,
- units: 'm',
projection: epsg_projection,
- displayProjection: epsg_display_projection
- } );
- box_layer = new OpenLayers.Layer.Vector("Box layer");
- area_map.addLayers([map_layer, box_layer]);
+ center: centerLonLat,
+ zoom: 12
+ };
+ area_view = new ol.View(view_options);
+
+ controls = [
+ new ol.control.Attribution(),
+ new ol.control.ScaleLine(),
+ new ol.control.Zoom(),
+ new ol.control.FullScreen()
+ ];
+ var map_options = {
+ controls: controls,
+ view: area_view,
+ target: map_edit,
+ layers: [map_layer]
+ };
+
+ /* Create map object */
+ area_map = new ol.Map(map_options);
+
+ source_features = new ol.source.Vector({
+ features: features
+ });
+ vector_features = new ol.layer.Vector({
+ source: source_features
+ });
+
+ area_map.addLayer(vector_features);
+
+ geometryFunction = function(coordinates, geometry) {
+ if (!geometry) {
+ geometry = new ol.geom.Polygon(null);
+ }
+ var start = coordinates[0];
+ var end = coordinates[1];
+ geometry.setCoordinates([
+ [start, [start[0], end[1]], end, [end[0], start[1]], start]
+ ]);
+ var extent = geometry.getExtent();
+ extent = ol.proj.transformExtent(
+ [extent[0], extent[3], extent[2], extent[1]],
+ epsg_projection, epsg_display_projection);
+ updateForm(extent);
+ return geometry;
+ };
+
+ draw = new ol.interaction.Draw({
+ source: source_features,
+ type: 'LineString',
+ geometryFunction: geometryFunction,
+ maxPoints: 2
+ });
+ area_map.addInteraction(draw);
+
+
+ geometryModify = function(e) {
+ var start = old_geom[0];
+ var end = old_geom[2];
+ for (i in old_geom){
+ var x = old_geom[i][0];
+ var y = old_geom[i][1];
+ if(x < start[0]) start[0] = x;
+ if(x > end[0]) end[0] = x;
+ if(y < start[1]) start[1] = y;
+ if(y > end[1]) end[1] = y;
+ }
+
+ var geom = features.getArray()[0].getGeometry();
+ var coordinates = geom.getCoordinates()[0];
+ var changed = false;
+ for (i in coordinates){
+ if (!changed){
+ var x = coordinates[i][0];
+ var y = coordinates[i][1];
+ if (x != old_geom[i][0] ||
+ y != old_geom[i][1]){
+ if(old_geom[i][0] == start[0]) start[0] = x;
+ if(old_geom[i][0] == end[0]) end[0] = x;
+ if(old_geom[i][1] == start[1]) start[1] = y;
+ if(old_geom[i][1] == end[1]) end[1] = y;
+ changed = true;
+ }
+ }
+ }
+
+ geom = new ol.geom.Polygon([
+ [start, [start[0], end[1]], end, [end[0], start[1]], start]
+ ]);
+ old_geom = geom.clone();
+ features.pop();
+ var feature = new ol.Feature({
+ geometry: geom
+ })
+ features.push(feature);
+ var extent = geom.getExtent();
+ extent = ol.proj.transformExtent(
+ [extent[0], extent[3], extent[2], extent[1]],
+ epsg_projection, epsg_display_projection);
+ updateForm(extent);
+ };
+ modify = new ol.interaction.Modify({
+ features: features
+ });
+ modify.on("modifyend", geometryModify);
+
+ area_map.addInteraction(modify);
+ modify.setActive(false);
+
+ source_features.on('change', function(e) {
+ if (source_features.getState() == 'ready') {
+ if (features.getLength() > 0){
+ if (draw.getActive()){
+ draw.setActive(false);
+ }
+ if (!modify.getActive()){
+ modify.setActive(true);
+ old_geom = features.getArray()[0].getGeometry().getCoordinates()[0];
+ }
+ } else {
+ if (modify.getActive()){
+ modify.setActive(false);
+ }
+ if (!draw.getActive()){
+ draw.setActive(true);
+ }
+ }
+ }
+ });
+
+ /*
var selectControl = new OpenLayers.Control();
OpenLayers.Util.extend(selectControl, {
draw: function() {
@@ -84,8 +218,8 @@ function init(map_edit){
area_map.events.register('zoomend', area_map, updateForm);
area_map.events.register('moveend', area_map, updateForm);
- /* zoom to the appropriate extent */
+ // zoom to the appropriate extent
if (!zoomToCurrentExtent(area_map)){
- area_map.setCenter(centerLonLat, 12);
}
+ */
}
diff --git a/chimere/static/chimere/js/importer_interface.js b/chimere/static/chimere/js/importer_interface.js
index 03bb87b..7b5e567 100644
--- a/chimere/static/chimere/js/importer_interface.js
+++ b/chimere/static/chimere/js/importer_interface.js
@@ -9,7 +9,7 @@ django.jQuery(function($) {
'field-get_description', 'field-automatic_update',
'field-default_status'),
SHP:new Array('field-source', 'field-source_file', 'field-default_name',
- 'field-zipped', 'field-origin', 'field-srid',
+ 'field-filtr', 'field-zipped', 'field-origin', 'field-srid',
'field-license', 'field-categories', 'field-overwrite',
'field-automatic_update', 'field-default_status'),
RSS:new Array('field-source', 'field-default_name', 'field-origin',
diff --git a/chimere/static/chimere/js/jquery.chimere.js b/chimere/static/chimere/js/jquery.chimere.js
index 9e89920..8ab08ef 100644
--- a/chimere/static/chimere/js/jquery.chimere.js
+++ b/chimere/static/chimere/js/jquery.chimere.js
@@ -16,21 +16,122 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
See the file COPYING for details.
*/
-/* Add OpenLayers MapQuest layer management */
-OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
- name: "MapQuestOSM",
- sphericalMercator: true,
- url: ' http://otile1.mqcdn.com/tiles/1.0.0/osm/${z}/${x}/${y}.png',
- clone: function(obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.OSM(
- this.name, this.url, this.getOptions());
- }
- obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
- return obj;
- },
- CLASS_NAME: "OpenLayers.Layer.MapQuestOSM"
-});
+var extra_url;
+
+// Create a simple layer switcher in element div:
+var LayerSwitcher = function(options){
+ var o = this.options = options || {};
+ var map = this.map = options.map;
+
+ // element to render in:
+ var $div;
+ if(!o.div){
+ $div = $('<div class="LayerSwitcher">'); $(document.body).append($div);
+ o.div = $div[0];
+ } else {
+ var $div = typeof o.div == 'string' ? $('#'+o.div) : $(o.div);
+ $div.addClass("LayerSwitcher");
+ }
+ this.div = o.div;
+
+ var $baseDiv = $('<div class="BaseLayerDiv">');
+ var $overDiv = $('<div class="OverlayDiv">');
+ $div.append($baseDiv, $overDiv);
+
+
+ // array with layers:
+ var layers = map.getLayers().getArray();
+
+ // turn off other baselayers:
+ var otherBLoff = function(layer){
+ $.each(layers, function(i,l){
+ if(l!==layer && l.get('baselayer'))
+ { l.setVisible(false); }
+ });
+ };
+
+ // go through each layer, render control and set handlers:
+ $.each(layers, function(i,l){
+ var BL = l.get('baselayer');
+ var $li = $('<div class="check">');
+ l.getVisible() ? $li.addClass('checked') : $li.removeClass('checked') ;
+ BL ? $li.addClass('radiobutton') : $li.addClass('checkbox') ;
+ var $ll = $('<label>'+l.get('name')+'</label>');
+ var $ld = $('<div class="LayerClickDiv">').click(function(){
+ l.setVisible(!l.getVisible());
+ l.get('baselayer') ? otherBLoff(l) :0;
+ }); //toggle viz on click
+ $ld.append($li,$ll);
+ BL ? $baseDiv.append($ld) : $overDiv.append($ld) ;
+ // bind checkbox state to layer event:
+ l.on('change:visible', function(e){
+ this.getVisible() ? $li.addClass('checked') : $li.removeClass('checked') ;
+ }); // bind
+ }); // each
+ if($baseDiv.children()[0] && $overDiv.children()[0]){
+ $baseDiv.after('<div class="Separator">');
+ }
+
+}; // LayerSwitcher
+
+
+function _geoportail_layer(key, layer, name, max_zoom, image_format, style, baselayer){
+ var resolutions = [];
+ var matrixIds = [];
+ var proj3857 = ol.proj.get('EPSG:3857');
+ var maxResolution = ol.extent.getWidth(proj3857.getExtent()) / 256;
+ for (var i = 0; i < max_zoom; i++) {
+ matrixIds[i] = i.toString();
+ resolutions[i] = maxResolution / Math.pow(2, i);
+ }
+
+ var plan_tileGrid = new ol.tilegrid.WMTS({
+ origin: [-20037508, 20037508],
+ resolutions: resolutions,
+ matrixIds: matrixIds
+ });
+
+ var plan_ign_source = new ol.source.WMTS({
+ url: 'http://wxs.ign.fr/' + key + '/wmts',
+ layer: layer,
+ matrixSet: 'PM',
+ format: image_format,
+ projection: 'EPSG:3857',
+ tileGrid: plan_tileGrid,
+ style: style,
+ attributions: [new ol.Attribution({
+ html: '<a href="http://www.geoportail.fr/" target="_blank">' +
+ '<img src="http://api.ign.fr/geoportail/api/js/latest/' +
+ 'theme/geoportal/img/logo_gp.gif"></a>'
+ })]
+ });
+
+ return new ol.layer.Tile({
+ baselayer: baselayer,
+ name: name,
+ source: plan_ign_source
+ });
+}
+
+// Géoportail (IGN)
+// example: geoportail_layer('2mqbg0z6cx7ube8gsou10nrt', 'GEOGRAPHICALGRIDSYSTEMS.MAPS', 'Géoportail - Plan IGN', 18)
+function geoportail_layer(key, layer, name, max_zoom){
+ return _geoportail_layer(key, layer, name, max_zoom, 'image/jpeg', 'normal', true);
+}
+
+// geoportail_layer('2mqbg0z6cx7ube8gsou10nrt', 'Géoportail - Cadastre', 20, 'bdparcellaire_b')
+function geoportail_cadastre_layer(key, name, max_zoom, style){
+ return _geoportail_layer(key, 'CADASTRALPARCELS.PARCELS', name, max_zoom, 'image/png', style, false);
+}
+
+function transformExtent(extent) {
+ return ol.proj.transformExtent(
+ extent, EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
+}
+
+function transform(obj) {
+ return obj.transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
+}
/*
* Little hasattr helper
@@ -58,6 +159,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
map_layers: null,
selected_map_layer: null,
dynamic_categories: false,
+ reload_on_move: true,
display_submited: false,
display_feature: null,
display_route: null,
@@ -85,12 +187,13 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
// if leave to false every click on the map hide the pop-up
explicit_popup_hide: false,
controls:null,
- popupClass: OpenLayers.Popup.FramedCloud,
+ // OL3-deprecated popupClass: OpenLayers.Popup.FramedCloud,
+ popupClass: null,
popupContentFull: false, // if true the detail is inside the popup
category_accordion: true, // category opening behave like an accordion
maxResolution: 156543.0399,
units: 'm',
- projection: new OpenLayers.Projection('EPSG:4326'),
+ projection: new ol.proj.get('EPSG:900913'),
theme: null,
enable_clustering: false,
routing: false, // enable routing management
@@ -103,13 +206,16 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
current_category: null, // To store the current category clicked in list
current_routes_features: [], // To store the current routes find by routing
itinerary_step_number:0, // current step number
- icon_offset: new OpenLayers.Pixel(0, 0),
+ icon_offset: [0, 0],
edition: false, // edition mode
- edition_type_is_route: false, // route or POI edition
- default_icon: new OpenLayers.Icon(
+ edition_type: 'marker', // marker, route or polygon edition
+ //default_icon: new OpenLayers.Icon(
+ // 'http://www.openlayers.org/dev/img/marker-green.png',
+ // new OpenLayers.Size(21, 25),
+ // new OpenLayers.Pixel(-(21/2), -25)),
+ default_icon: (
'http://www.openlayers.org/dev/img/marker-green.png',
- new OpenLayers.Size(21, 25),
- new OpenLayers.Pixel(-(21/2), -25)),
+ (21, 25), (-(21/2), -25)),
cluster_icon: null,
marker_hover_id:'marker_hover',
marker_hover_content_id:'marker_hover_content',
@@ -130,6 +236,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
*/
init: function ( options ) {
/* Manage parameters */
+ /* OL3-deprecated-cluster
// not staticaly in default because of STATIC_URL init
if (defaults.cluster_icon == null && typeof STATIC_URL != 'undefined'){
defaults.cluster_icon = new OpenLayers.Icon(
@@ -137,6 +244,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
new OpenLayers.Size(36, 39),
new OpenLayers.Pixel(-(36/2), -(39/2)));
}
+ */
+ /* OL3-deprecated-routing
if (defaults.icon_start == null && typeof STATIC_URL != 'undefined'){
defaults.icon_start = new OpenLayers.Icon(
STATIC_URL + "chimere/img/flag-start.png",
@@ -155,9 +264,20 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
new OpenLayers.Size(32, 32),
new OpenLayers.Pixel(0, -32));
}
+ */
+ if (defaults.map_layers == null || ! defaults.map_layers.length){
+ defaults.map_layers = [
+ new ol.layer.Tile({
+ style: 'OSM',
+ name: 'OSM',
+ source: new ol.source.OSM()
+ })];
+ }
settings = $.extend({}, defaults);
if ( options ) $.extend(settings, options);
+
if (settings.controls == null){
+ /* OL3-deprecated-mobile
if (settings.mobile){
settings.controls = [new OpenLayers.Control.TouchNavigation({
dragPanOptions: {
@@ -166,33 +286,57 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}),
new OpenLayers.Control.Zoom()];
} else {
- settings.controls = [new OpenLayers.Control.Navigation(),
- new OpenLayers.Control.SimplePanZoom(),
- new OpenLayers.Control.ScaleLine()];
- }
+ */
+ settings.controls = [
+ new ol.control.Attribution(),
+ new ol.control.OverviewMap({
+ collapsed: false
+ }),
+ new ol.control.ScaleLine(),
+ new ol.control.Zoom(),
+ new ol.control.FullScreen()
+ ];
+ //}
}
- var map_element = $(this).get(0);
- var map_options = {
- controls: settings.controls,
+ var map_element = $(this).attr('id');
+
+ var view_options = {
maxResolution: settings.maxResolution,
- units: settings.units,
+ // OL3-deprecated: units: settings.units,
projection: settings.projection,
- theme: settings.theme
+ center: CENTER_LONLAT,
+ zoom: DEFAULT_ZOOM
};
+ /* OL3-deprecated
if (settings.restricted_extent){
settings.restricted_extent.transform(EPSG_DISPLAY_PROJECTION,
EPSG_PROJECTION);
map_options['restrictedExtent'] = settings.restricted_extent;
- }
+ }*/
+
+ settings.view = new ol.View(view_options);
+ var map_options = {
+ controls: settings.controls,
+ view: settings.view,
+ target: map_element,
+ layers: settings.map_layers
+ // OL3-deprecated: theme: settings.theme
+ };
settings.current_position = null;
/* Create map object */
- settings.map = map = new OpenLayers.Map(map_element, map_options);
+ settings.map = map = new ol.Map(map_options);
- map.addControl(new OpenLayers.Control.Attribution());
+ // only display the first layer
+ $.each(settings.map.getLayers().getArray(), function(i, layer){
+ if (i > 0){
+ layer.setVisible(false);
+ }
+ });
/* Manage permalink */
+ /* OL3-deprecated permalink
if (!settings.edition){
if (settings.permalink == null && !settings.edition) {
var permalink_options = {};
@@ -203,8 +347,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.permalink = new OpenLayers.Control.Permalink(
permalink_options);
}
- /* HACK new permalink createParams method
- FIXME when facilities are given to personalize the permalink */
+ // HACK new permalink createParams method
+ // FIXME when facilities are given to personalize the permalink
var oldCreateParams = settings.permalink.createParams
var _createParams = function(center, zoom, layers) {
// Call normal method
@@ -251,24 +395,28 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.permalink.div.childNodes[0].textContent = settings.permalink_label;
}
}
- /* Add Layers */
- settings.map.addLayers(settings.map_layers);
+ */
+ /* OL3-deprecated
if (settings.map_layers.length > 1){
settings.map.addControl(new OpenLayers.Control.LayerSwitcher(
{roundedCorner:false}));
}
- /* select the default map layer */
+ // select the default map layer
if (!settings.selected_map_layer){
settings.selected_map_layer = 0;
}
settings.map.setBaseLayer(
settings.map_layers[settings.selected_map_layer]);
+ */
- /* manage the context menu */
+ /* OL3-deprecated context menu
+ // manage the context menu
$('#map_menu_zoomin').bind("click", methods.zoomIn);
$('#map_menu_zoomout').bind("click", methods.zoomOut);
$('#map_menu_center').bind("click", methods.mapCenter);
- /* manage the routing */
+ */
+ /* OL3-deprecated routing
+ // manage the routing
if (settings.routing){
settings.routing_start = null;
settings.routing_steps = new Array();
@@ -283,17 +431,211 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
'Route markers');
settings.map.addLayer(settings.layerRouteMarker);
}
+ */
+
+ settings.layerSwitcher = new LayerSwitcher({
+ map: settings.map,
+ div: 'layerSwitcher'
+ });
+
+ /* marker layer */
+ settings.iconStyles = new Object();
+ settings.dbFeatures = new ol.Collection();
+
+ settings.sourceDbFeatures = new ol.source.Vector({
+ features: settings.dbFeatures
+ });
+
+ settings.layerDbFeatures = new ol.layer.Vector({
+ source: settings.sourceDbFeatures
+ });
+ /*
+ settings.layerDbFeatures = new ol.layer.Image({
+ source: new ol.source.ImageVector({
+ source: settings.sourceDbFeatures,
+
+ style: function(feature, resolution){
+ if (feature.getGeometry().getType() == "Polygon"){
+ return [new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: 'rgba(255, 255, 255, 0.6)'
+ }),
+ stroke: new ol.style.Stroke({
+ color: '#319FD3',
+ width: 1
+ })
+ })]
+ }
+ }
+ })
+ });
+ */
+ settings.map.addLayer(settings.layerDbFeatures);
+
+ // popup management
+ settings.popup_item = document.getElementById('popup');
+ settings.popup = new ol.Overlay({
+ element: settings.popup_item,
+ positioning: 'bottom-left',
+ stopEvent: false/*,
+ autoPan: true,
+ autoPanAnimation: {
+ duration: 250
+ }*/
+ });
+ settings.map.addOverlay(settings.popup);
+
+ // display marker on click
+ settings.map.on('click', function(evt) {
+ var feature = settings.map.forEachFeatureAtPixel(
+ evt.pixel,
+ function(feature, layer) {
+ return feature;
+ }
+ );
+ settings.current_feature = feature;
+ if (!settings.edition){
+ if (feature) {
+ $(settings.popup_item).popover('destroy');
+
+ // zoom on aggregated
+ var key = feature.get('key');
+ if (key.length > 3 && key.substring(0, 3) == 'agg' &&
+ settings._zoom_need_reload){
+ var current_zoom = settings.map.getView().getZoom();
+ if (current_zoom < settings._zoom_need_reload){
+ settings.map.getView().setZoom(settings._zoom_need_reload);
+ settings.map.getView().setCenter(evt.coordinate);
+ }
+ return
+ }
+
+ var geom = feature.getGeometry();
+ if (geom.getType() == 'Point'){
+ settings.popup.setPosition(geom.getCoordinates());
+ settings.popup.setOffset([feature.get('popup_offset_x'),
+ -feature.get('popup_offset_y')]);
+ } else if (geom.getType() == 'Polygon'){
+ settings.popup.setPosition(geom.getInteriorPoint().getCoordinates());
+ settings.popup.setOffset([0, 0]);
+ } else if (geom.getType() == 'LineString'){
+ settings.popup.setPosition(geom.getCoordinatesAt(0.5));
+ settings.popup.setOffset([0, 0]);
+ } else if (geom.getType() == 'MultipleLineString'){
+ settings.popup.setPosition(geom.getLineString(0).getCoordinatesAt(0.5));
+ settings.popup.setOffset([0, 0]);
+ }
+ $(settings.popup_item).popover({
+ 'placement': 'top',
+ 'html': true,
+ 'content': feature.get('name')
+ });
+ $(settings.popup_item).popover('show');
+ methods.display_feature_detail(key);
+ } else {
+ $(settings.popup_item).popover('destroy');
+ }
+ }
+ });
+
+ map.on('pointermove', function(e) {
+ var pixel = map.getEventPixel(e.originalEvent);
+ var hit = map.hasFeatureAtPixel(pixel);
+ var target = map.getTarget();
+ target = typeof target === "string" ?
+ document.getElementById(target) : target;
+ target.style.cursor = hit ? 'pointer' : '';
+ });
+
+ settings.WKT = new ol.format.WKT();
+
/* Vectors layer */
- settings.layerVectors = new OpenLayers.Layer.Vector("Vector Layer");
+ settings.vectors = new ol.Collection();
+
+ settings.sourceVectors = new ol.source.Vector({
+ features: settings.vectors
+ });
+
+ settings.layerVectors = new ol.layer.Vector({
+ source: settings.sourceVectors
+ });
settings.map.addLayer(settings.layerVectors);
- settings.layerVectors.setOpacity(0.8);
+ if (settings.edition){ //&& (settings.edition_type == 'polygon'
+ // || settings.edition_type == 'route')){
+
+ settings.features = new ol.Collection();
+
+ settings.editionSource = new ol.source.Vector(
+ {features: settings.features});
+
+ settings.editionSource.on(
+ 'changefeature',
+ function(changed) {
+ if (changed) methods.updateInput();
+ });
+
+ settings.editionSource.on(
+ 'addfeature',
+ function(changed) {
+ if (changed) methods.updateInput();
+ });
+
+ settings.editionVector = new ol.layer.Vector({
+ source: settings.editionSource,
+ style: new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: 'rgba(180, 180, 180, 0.3)'
+ }),
+ stroke: new ol.style.Stroke({
+ color: '#ffcc33',
+ width: 2
+ }),
+ image: new ol.style.Circle({
+ radius: 7,
+ fill: new ol.style.Fill({
+ color: '#ffcc33'
+ })
+ })
+ })
+ });
+
+ settings.map.addLayer(settings.editionVector);
+
+ var edition_type = 'Point';
+ if (settings.edition_type == 'route') edition_type = 'LineString';
+ if (settings.edition_type == 'polygon') edition_type = 'Polygon';
+
+ settings.draw = new ol.interaction.Draw({
+ source: settings.editionSource,
+ type: (edition_type),
+ });
+ settings.draw_activated = false;
+
+ settings.draw.on("drawend", function() {
+ settings.map.removeInteraction(settings.draw);
+ settings.draw_activated = false;
+ });
+
+ settings.modify = new ol.interaction.Modify({
+ features: settings.features,
+ deleteCondition: function(event) {
+ return ol.events.condition.shiftKeyOnly(event) &&
+ ol.events.condition.singleClick(event);
+ }
+ });
+ settings.modify_activated = false;
+ }
+ // OL3-deprecated settings.layerVectors.setOpacity(0.8);
+ /* OL3-deprecated-routing
if (settings.edition_type_is_route){
settings.map.addControl(new OpenLayers.Control.DrawFeature(
settings.layerVectors, OpenLayers.Handler.Path));
settings.map.addControl(new OpenLayers.Control.ModifyFeature(
settings.layerVectors, {clickout:false, toggle:false}));
}
+ */
+ /* OL3-deprecated-cluster
if (settings.enable_clustering){
var style = new OpenLayers.Style({
graphicTitle: "${name}",
@@ -341,7 +683,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}});
- /* Cluster layer */
+ // Cluster layer
settings.clustering = new OpenLayers.Strategy.Cluster({
distance: 10,
threshold: 2});
@@ -377,61 +719,86 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
highlightCtrl.activate();
selectCtrl.activate();
}
+ */
/* Markers layer */
- settings.layerMarkers = new OpenLayers.Layer.Markers('POIs');
- settings.map.addLayer(settings.layerMarkers);
+ settings.icons = [];
+ settings.layerIcons = new ol.source.Vector({
+ features: settings.icons
+ });
+ settings.layerDbFeatures = new ol.layer.Vector({
+ source: settings.layerIcons
+ });
+
+ settings.map.addLayer(settings.layerDbFeatures);
+ /* OL3-deprecated
if (settings.dynamic_categories){
settings.map.events.register('moveend', settings.map,
methods.loadCategories);
}
- /* TODO make a function */
+ */
+
+ /* OL3-deprecated
+ // TODO make a function
if (settings.display_submited) {
document.getElementById('display_submited_check').checked = true;
}
+ */
+
/* if we have some zoom and lon/lat from the init options */
if (settings.zoom && settings.lon && settings.lat) {
- var centerLonLat = new OpenLayers.LonLat(settings.lon,
- settings.lat);
- settings.map.setCenter(centerLonLat, settings.zoom);
+ var centerLonLat = [settings.lon, settings.lat];
+ settings.view.setCenter(centerLonLat);
+ settings.view.setZoom(settings.zoom);
}
/* if not zoom to the extent in cookies */
else if (!methods.zoomToCurrentExtent(settings.map)){
/* if no extent in cookies zoom to default */
if(CENTER_LONLAT && DEFAULT_ZOOM){
- settings.map.setCenter(CENTER_LONLAT, DEFAULT_ZOOM);
+ settings.view.setCenter(CENTER_LONLAT);
+ settings.view.setZoom(DEFAULT_ZOOM);
}
}
+ /// OL3-TODO
if (!settings.edition){
if (settings.enable_clustering){
+ /// OL3-TODO
settings.map.events.register('zoomend', null,
methods.cleanCluster);
}
methods.loadCategories();
methods.loadGeoObjects();
- methods.activateContextMenu()
+ /// OL3-TODO
+ // methods.activateContextMenu()
} else {
- if (!settings.edition_type_is_route){
- methods.activateMarkerEdit();
- } else {
+ /// OL3-TODO
+ if (settings.edition_type == 'route'){
methods.activateRouteEdit();
+ } else if (settings.edition_type == 'polygon'){
+ methods.activatePolygonEdit();
+ } else {
+ methods.activateMarkerEdit();
}
}
+ return;
if (settings.routing_start_lon && settings.routing_start_lat){
+ /// OL3-TODO
settings.current_position = new OpenLayers.LonLat(
settings.routing_start_lon, settings.routing_start_lat
).transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
methods.routingFrom();
}
if (settings.routing_end_lon && settings.routing_end_lat){
+ /// OL3-TODO
settings.current_position = new OpenLayers.LonLat(
settings.routing_end_lon, settings.routing_end_lat
).transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
methods.routingTo();
}
if (settings.routing_steps_lonlat){
+ /// OL3-TODO
for (var i = 0; i < settings.routing_steps_lonlat.length/2; i++) {
lon = settings.routing_steps_lonlat[i*2];
lat = settings.routing_steps_lonlat[i*2+1];
@@ -443,9 +810,10 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
// verify that the initial display_feature is displayed
if (settings.display_feature){
+ /// OL3-TODO
var is_displayed = false;
- for(j=0; j<settings.layerMarkers.markers.length;j++){
- var c_marker = settings.layerMarkers.markers[j];
+ for(j=0; j<settings.layerDbFeatures.markers.length;j++){
+ var c_marker = settings.layerDbFeatures.markers[j];
if(c_marker.pk == settings.display_feature){
is_displayed = true;
}
@@ -454,7 +822,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
methods.loadMarker(settings.display_feature);
}
}
- methods.update_permalink_activation();
+ /// OL3-TODO
+ //methods.update_permalink_activation();
methods.preload_images();
}, // end of init
@@ -470,6 +839,40 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
$("#permalink a").attr("disabled", "disabled");
}
},
+ register_reload_on_move: function(){
+ var reload_on_move = function(evnt){
+ var map = settings.map;
+ var current_extent = ol.proj.transformExtent(
+ map.getView().calculateExtent(map.getSize()),
+ EPSG_PROJECTION, EPSG_DISPLAY_PROJECTION
+ );
+ var current_zoom = settings.map.getView().getZoom();
+
+ var init;
+ if (!settings._cache_boundingbox) init = true;
+
+ if (init ||
+ !ol.extent.containsCoordinate(settings._cache_boundingbox,
+ current_extent) ||
+ (settings._zoom_need_reload &&
+ current_zoom >= settings._zoom_need_reload)
+ ){
+ // enlarge current extent to cache values
+ x_extent = Math.abs(current_extent[2] - current_extent[0]);
+ y_extent = Math.abs(current_extent[3] - current_extent[1]);
+ current_extent[0] = current_extent[0] - x_extent;
+ current_extent[1] = current_extent[1] - y_extent;
+ current_extent[2] = current_extent[2] + x_extent;
+ current_extent[3] = current_extent[3] + y_extent;
+ settings._cache_boundingbox = current_extent;
+ settings._cache_zoom = current_zoom;
+
+ if(!init) methods.loadGeoObjects();
+ }
+ };
+ settings.map.on('moveend', reload_on_move);
+ reload_on_move();
+ },
/* Preload icons */
preload_images: function(){
if (typeof extra_url == 'undefined') return;
@@ -494,17 +897,23 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
activateContextMenu: function(){
settings.edition_type_is_route = false;
- settings.map.events.unregister('click', settings.map,
- methods.setMarker);
- settings.map.events.register('click', settings.map,
- methods.displayMapMenu);
+ // settings.map.events.unregister('click', settings.map,
+ // methods.setMarker);
+ // settings.map.events.register('click', settings.map,
+ // methods.displayMapMenu);
},
+ activatePolygonEdit: function(){
+ // TODO OL3
+ return;
+ },
activateRouteEdit: function(){
+ // TODO OL3
+ return;
settings.edition_type_is_route = true;
methods.cleanMarker();
- settings.map.events.unregister('click', settings.map,
- methods.setMarker);
+ // settings.map.events.unregister('click', settings.map,
+ // methods.setMarker);
if (settings.routing){
settings.map.events.register('click', settings.map,
methods.displayMapMenu);
@@ -524,10 +933,10 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
if (settings.current_popup != null) {
settings.current_popup.hide();
}
- settings.map.events.unregister('click', settings.map,
- methods.displayMapMenu);
- settings.map.events.register('click', settings.map,
- methods.setMarker);
+ // settings.map.events.unregister('click', settings.map,
+ // methods.displayMapMenu);
+ //settings.map.events.register('click', settings.map,
+ // methods.setMarker);
},
// change map_layer
changeMapLayer: function(map_idx){
@@ -564,6 +973,9 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
setCurrentPosition: function(lonlat){
settings.current_position = lonlat;
},
+ addLayer: function(layer){
+ settings.map.addLayer(layer);
+ },
zoomOnCluster: function(feature){
if(!feature.cluster) // if not cluster
{
@@ -636,23 +1048,50 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
if (!ids) ids = '0';
var uri = extra_url + "getGeoObjects/" + ids;
if (settings.display_submited) uri += "/A_S";
+
+ if (settings.reload_on_move && !settings._cache_boundingbox){
+ methods.register_reload_on_move();
+ }
+
+ var data = {};
+ if (settings._cache_boundingbox){
+ data = {
+ 'min_lon': settings._cache_boundingbox[0],
+ 'min_lat': settings._cache_boundingbox[1],
+ 'max_lon': settings._cache_boundingbox[2],
+ 'max_lat': settings._cache_boundingbox[3],
+ 'zoom_level': settings._cache_zoom
+ };
+ }
$.ajax({url: uri,
dataType: "json",
+ data: data,
success: function (data) {
- settings.layerMarkers.clearMarkers();
- settings.layerVectors.removeAllFeatures();
+ //var start = new Date().getTime();
+ settings.dbFeatures.clear();
+ settings.vectors.clear();
+ /// OL3-TODO
+ // settings.layerVectors.removeAllFeatures();
if (settings.enable_clustering){
settings.cluster_array = [];
settings.layerCluster.removeAllFeatures();
}
+ if (!data.features) return;
+ if (data.zoom_need_reload){
+ settings._zoom_need_reload = data.zoom_need_reload;
+ }
for (var i = 0; i < data.features.length; i++) {
var feature = data.features[i];
if (feature.geometry.type == 'Point'){
methods.addMarker(feature);
+ } else if (feature.geometry.type == 'Polygon') {
+ methods.addPolygon(feature);
+ } else if (feature.geometry.type == 'MultiPolygon') {
+ methods.addPolygon(feature);
} else if (feature.geometry.type == 'LineString') {
- methods.addRoute(feature);
+ //OL3 methods.addRoute(feature);
} else if (feature.geometry.type == 'MultiLineString') {
- methods.addMultiLine(feature);
+ //OL3 methods.addMultiLine(feature);
}
}
if (settings.enable_clustering){
@@ -660,14 +1099,21 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.cluster_array);
methods.cleanCluster();
}
- settings.map.resetLayersZIndex();
+ // var extent = settings.sourceDbFeatures.getExtent();
+ // settings.map.getView().fit(extent, settings.map.getSize());
+ // settings.map.resetLayersZIndex();
+ // var end = new Date().getTime();
+ // var time = end - start;
+ //alert('Execution time: ' + time);
},
error: function (data, textStatus, errorThrown) {
- settings.layerMarkers.clearMarkers();
- settings.layerVectors.removeAllFeatures();
- if (settings.enable_clustering){
- settings.layerCluster.removeAllFeatures();
- }
+ settings.dbFeatures.clear();
+ settings.vectors.clear();
+ /// OL3-TODO
+ //settings.layerVectors.removeAllFeatures();
+ //if (settings.enable_clustering){
+ // settings.layerCluster.removeAllFeatures();
+ //}
},
complete: function () {
if($('#waiting').length){$('#waiting').hide();}
@@ -678,8 +1124,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
razMap: function() {
methods.hidePopup();
methods.uncheckCategories();
- settings.layerMarkers.clearMarkers();
- settings.layerVectors.removeAllFeatures();
+ settings.dbFeatures.clear();
+ settings.vectors.clear();
if (settings.enable_clustering){
settings.layerCluster.removeAllFeatures();
settings.cluster_array = [];
@@ -691,10 +1137,13 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
* Update the categories div in ajax
*/
loadCategories: function () {
- var current_extent = settings.map.getExtent().transform(
- settings.map.getProjectionObject(),
+ var current_extent = settings.view.calculateExtent(
+ settings.map.getSize());
+ current_extent = ol.proj.transformExtent(
+ current_extent,
+ EPSG_PROJECTION,
EPSG_DISPLAY_PROJECTION);
- current_extent = current_extent.toArray().join('_')
+ current_extent = current_extent.join('_')
current_extent = current_extent.replace(/\./g, 'D');
current_extent = current_extent.replace(/-/g, 'M');
var uri = extra_url
@@ -766,14 +1215,15 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
methods.subcategory_detail(c_name);
}
var par = $(this).parent();
- if ($(this).attr('checked')){
+ if ($(this).prop('checked')){
par.addClass('selected');
} else {
par.removeClass('selected');
}
methods.loadGeoObjects();
_toggle_categories($(this));
- settings.permalink.updateLink();
+ // OL-3 permalink
+ // settings.permalink.updateLink();
if ($('#layer_cat_'+c_name).length){
$('#layer_cat_'+c_name).prop("checked",
this.checked);
@@ -854,14 +1304,34 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
}
}
- for(j=0; j<settings.layerMarkers.markers.length;j++){
- if(hidden_feature_idx.indexOf(settings.layerMarkers.markers[j].pk) > -1){
- settings.layerMarkers.markers[j].display(false);
+ for(j=0; j<settings.layerDbFeatures.markers.length;j++){
+ if(hidden_feature_idx.indexOf(settings.layerDbFeatures.markers[j].pk) > -1){
+ settings.layerDbFeatures.markers[j].display(false);
} else {
- settings.layerMarkers.markers[j].display(true);
+ settings.layerDbFeatures.markers[j].display(true);
}
}
},
+ activateDraw: function (){
+ settings.map.addInteraction(settings.draw);
+ settings.map.addInteraction(settings.modify);
+ settings.draw_activated = true;
+ settings.modify_activated = true;
+ },
+ activateModify: function (){
+ settings.map.addInteraction(settings.modify);
+ settings.modify_activated = true;
+ },
+ deactivateDraw: function (){
+ if (settings.draw_activated){
+ settings.map.removeInteraction(settings.draw);
+ settings.draw_activated = false;
+ }
+ if (settings.modify_activated){
+ settings.map.removeInteraction(settings.modify);
+ settings.modify_activated = false;
+ }
+ },
/*
* Put a marker on the map
*/
@@ -872,21 +1342,51 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
*/
var lat = mark.geometry.coordinates[1];
var lon = mark.geometry.coordinates[0];
- var size = new OpenLayers.Size(mark.properties.icon_width,
- mark.properties.icon_height);
- var icon_url = MEDIA_URL + mark.properties.icon_path;
+
+ var iconFeature = new ol.Feature({
+ geometry: transform(new ol.geom.Point([lon, lat])),
+ name: mark.properties.name,
+ pk: mark.properties.pk,
+ key: mark.properties.key,
+ popup_offset_x: mark.properties.icon_popup_offset_x,
+ popup_offset_y: mark.properties.icon_popup_offset_y
+ });
+
+ var iconStyle;
+ for (var i in settings.iconStyles){
+ if (i == mark.properties.icon_path){
+ iconStyle = settings.iconStyles[i];
+ }
+ }
+ if (!iconStyle){
+ var icon_url = MEDIA_URL + mark.properties.icon_path;
+ var size = [mark.properties.icon_width, mark.properties.icon_height];
+ var anchor = [mark.properties.icon_offset_x,
+ mark.properties.icon_offset_y];
+ iconStyle = new ol.style.Style({
+ image: new ol.style.Icon({
+ anchor: anchor,
+ anchorXUnits: 'pixels',
+ anchorYUnits: 'pixels',
+ src: icon_url,
+ size: size
+ })
+ });
+ settings.iconStyles[mark.properties.icon_path] = iconStyle;
+ }
+
+ iconFeature.setStyle(iconStyle);
+ settings.dbFeatures.push(iconFeature);
+
+ return;
+
+ //OL3 hover
+ /*
var icon_hover_url = '';
if (mark.properties.icon_hover_path){
var icon_hover_url = MEDIA_URL + mark.properties.icon_hover_path;
}
- var iconclone = new OpenLayers.Icon(icon_url, size,
- settings.icon_offset);
- var feature = new OpenLayers.Feature(settings.layerMarkers,
- new OpenLayers.LonLat(lon, lat).transform(
- EPSG_DISPLAY_PROJECTION,
- EPSG_PROJECTION),
- {icon:iconclone});
feature.pk = mark.properties.pk;
feature.popupClass = settings.popupClass;
feature.data.popupContentHTML = "<div class='cloud'>";
@@ -901,12 +1401,12 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
marker.icon_url = icon_url;
marker.icon_hover_url = icon_hover_url;
marker.category_name = mark.properties.category_name;
- /* manage markers events */
+ // manage markers events
var _popup = function() {
if (!feature.pk){
return;
}
- /* show the popup */
+ // show the popup
if (settings.current_popup != null) {
settings.current_popup.hide();
}
@@ -917,7 +1417,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
feature.popup.toggle();
}
settings.current_popup = feature.popup;
- /* hide on click on the cloud */
+ // hide on click on the cloud
if (!settings.explicit_popup_hide){
settings.current_popup.groupDiv.onclick = methods.hidePopup;
}
@@ -925,7 +1425,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
methods.update_permalink_activation();
}
var _repan_popup = function(){
- /* re-pan manually */
+ // re-pan manually
// no clean way to detect if all the element are ready
// lack of better...
@@ -1024,8 +1524,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
marker.events.register('touchstart', feature, markerClick);
marker.events.register('mouseover', feature, markerOver);
marker.events.register('mouseout', feature, markerOut);
- settings.layerMarkers.addMarker(marker);
- /* show the item when designed in the permalink */
+ settings.layerDbFeatures.addMarker(marker);
+ // show the item when designed in the permalink
if (settings.display_feature == feature.pk){
settings.current_feature = feature;
_popup(feature);
@@ -1051,6 +1551,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
return feature;
+ */
},
//LIB iOS
@@ -1132,6 +1633,30 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.map.getProjectionObject());
settings.layerVectors.addFeatures(feats);
},
+ // Put a polygon on the map
+ addPolygon: function(feature) {
+ var feat = new ol.format.GeoJSON().readFeatures(feature)[0];
+ feat.setGeometry(transform(feat.getGeometry()));
+ feat.setStyle(new ol.style.Style({
+ fill: new ol.style.Fill({ color: feature.properties.inner_color }),
+ stroke: new ol.style.Stroke({
+ color: feature.properties.color, width: 2
+ })
+ }));
+ settings.dbFeatures.push(feat);
+ return;
+ var gformat = new OpenLayers.Format.GeoJSON();
+ var feats = gformat.read(feature);
+ var style = OpenLayers.Util.extend({},
+ OpenLayers.Feature.Vector.style['default']);
+ style.strokeColor = feature.properties.color;
+ style.strokeWidth = 2;
+ feats[0].style = style;
+ feats[0].geometry = feats[0].geometry.transform(
+ EPSG_DISPLAY_PROJECTION,
+ settings.map.getProjectionObject());
+ settings.layerVectors.addFeatures(feats);
+ },
routingInputChange: function(nominatim_id){
$('#map_menu_clear').show();
switch(nominatim_id){
@@ -1573,13 +2098,13 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.layerRoute.addFeatures([current_route]);
return current_route;
},
- display_feature_detail: function (pk) {
+ display_feature_detail: function (key) {
/*
* update current detail panel with an AJAX request
*/
var uri = extra_url
if (settings.area_id) uri += settings.area_id + "/"
- uri += "getDetail/" + pk;
+ uri += "getDetail/" + key;
var params = {}
if (settings.simple) { params["simple"] = 1; }
$.ajax({url: uri,
@@ -1698,6 +2223,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
/* zoom to current extent */
var current_extent = helpers.getSavedExtent();
var extent;
+ return;
+ //////// OL3-deprecated
if (OpenLayers && current_extent && current_extent.length == 4){
extent = new OpenLayers.Bounds(
current_extent[0], current_extent[1],
@@ -1717,48 +2244,44 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
},
zoomToMarkerExtent: function(){
settings.map.zoomToExtent(
- settings.layerMarkers.getDataExtent());
+ settings.layerDbFeatures.getDataExtent());
},
// methods for edition
- setMarker: function (event){
- event = event || window.event;
- var lonlat = settings.map.getLonLatFromViewPortPx(event.xy);
- methods.putEditMarker(lonlat, false);
- OpenLayers.Event.stop(event);
- },
cleanMarker: function(){
if (settings.current_edit_feature) {
- settings.layerMarkers.removeMarker(settings.current_edit_feature);
+ settings.layerDbFeatures.removeMarker(settings.current_edit_feature);
}
},
/* put the marker on the map and update latitude and longitude fields */
putEditMarker: function (lonlat, zoom){
- methods.cleanMarker();
- settings.current_edit_feature = new OpenLayers.Marker(lonlat.clone(),
- settings.default_icon);
- settings.layerMarkers.addMarker(settings.current_edit_feature);
- methods.updateMarkerInput();
+ if (settings.features.getLength()) settings.features.pop();
+ // console.log(lonlat);
+ var point = new ol.geom.Point(lonlat);
+ point.transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
+ var feature = new ol.Feature({
+ geometry: point
+ });
+
+ settings.features.push(feature);
+ methods.updateGenInput();
/* zoom to the point */
if (zoom){
- var bounds = settings.layerMarkers.getDataExtent();
- if (bounds) settings.map.zoomToExtent(bounds);
+ var view = settings.map.getView();
+ view.fit(settings.editionSource.getExtent(), settings.map.getSize());
+ view.setZoom(view.getZoom() - 11);
}
return;
},
- updateMarkerInput: function(){
- if (!settings.current_edit_feature) {
- return;
+ updateInput: function(){
+ if (settings.edition_type == 'linestring'){
+ methods.updateRoutingInput();
}
- lonlat = settings.current_edit_feature.lonlat.clone().transform(
- settings.map.getProjectionObject(),
- EPSG_DISPLAY_PROJECTION);
- $('#'+settings.input_id).val(
- 'POINT(' + lonlat.lon + ' ' + lonlat.lat + ')');
- if($('#live_latitude').length){
- $('#live_latitude').val(lonlat.lat);
- $('#live_longitude').val(lonlat.lon);
+ if (settings.edition_type == 'polygon'){
+ methods.updateGenInput('polygon');
}
-
+ if (settings.edition_type == 'marker'){
+ methods.updateGenInput('marker');
+ };
},
updateRoutingInput: function(){
if (!settings.current_routes_features) {
@@ -1781,6 +2304,27 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
var linestring = new OpenLayers.Geometry.LineString(point_array);
jQuery('#id_route').val(String(linestring));
},
+ updateGenInput: function(){
+ var features = settings.editionSource.getFeatures();
+ var input_id = '#';
+ if (settings.edition_type == 'marker') input_id += settings.input_id;
+ if (settings.edition_type == 'polygon') input_id += 'id_polygon';
+
+ if (!features.length) {
+ jQuery(input_id).val('');
+ return;
+ }
+ var wkt = settings.WKT.writeFeature(features[0], {
+ dataProjection: EPSG_DISPLAY_PROJECTION,
+ featureProjection: EPSG_PROJECTION});
+ jQuery(input_id).val(String(wkt));
+ if(settings.edition_type == 'marker' && $('#live_latitude').length){
+ coords = features[0].getGeometry().clone().transform(
+ EPSG_PROJECTION, EPSG_DISPLAY_PROJECTION).getCoordinates();
+ $('#live_latitude').val(coords[1]);
+ $('#live_longitude').val(coords[0]);
+ }
+ },
activateCurrentControl: function(){
if (settings.current_control){
settings.current_control.activate();
@@ -1802,18 +2346,18 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.current_control.deactivate();
}
},
- initFeature: function(json_geometry){
- var json = new OpenLayers.Format.JSON();
- var polyline = json.read(json_geometry);
- var point_array = new Array();
- for (i=0; i<polyline.coordinates.length; i++){
- var point = new OpenLayers.Geometry.Point(
- polyline.coordinates[i][0],
- polyline.coordinates[i][1]);
- point_array.push(point);
+ initFeature: function(wkt_geometry){
+ feature = settings.WKT.readFeature(wkt_geometry, {
+ dataProjection: EPSG_DISPLAY_PROJECTION,
+ featureProjection: EPSG_PROJECTION});
+ if (settings.draw_activated){
+ settings.map.removeInteraction(settings.draw);
+ settings.draw_activated = false;
}
- var linestring = new OpenLayers.Geometry.LineString(point_array);
- methods.initFeatureFromGeometry(linestring);
+ settings.map.getView().fit(feature.getGeometry(),
+ settings.map.getSize());
+ settings.editionSource.addFeature(feature);
+ methods.updateInput();
},
initFeatureFromWkt: function(wkt_geometry){
var linestring = OpenLayers.Geometry.fromWKT(wkt_geometry);
@@ -1836,8 +2380,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
if (bounds) settings.map.zoomToExtent(bounds);
},
showPopup: function (feature_pk) {
- for(j=0; j<settings.layerMarkers.markers.length;j++){
- var c_marker = settings.layerMarkers.markers[j];
+ for(j=0; j<settings.layerDbFeatures.markers.length;j++){
+ var c_marker = settings.layerDbFeatures.markers[j];
if(c_marker.pk == feature_pk){
c_marker.events.triggerEvent('click');
return true
@@ -1916,7 +2460,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.checked_categories = [];
settings.display_submited = false;
}
- if ($(this).attr('checked') == 'checked' || $(this).attr('checked') == true){
+ if ($(this).prop('checked') == 'checked' || $(this).prop('checked') == true){
cat_id = $(this).attr('id').split('_').pop();
settings.checked_categories.push(parseInt(cat_id));
}
@@ -1959,13 +2503,12 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
},
zoom_to_area: function (coords) {
/* zoom to an area */
- var left = coords[0];
- var bottom = coords[1];
- var right = coords[2];
- var top = coords[3];
- var bounds = new OpenLayers.Bounds(left, bottom, right, top);
- bounds.transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
- settings.map.zoomToExtent(bounds, true);
+ var left = Math.round(coords[0] * 1000) / 1000;
+ var bottom = Math.round(coords[1] * 1000) / 1000;
+ var right = Math.round(coords[2] * 1000) / 1000;
+ var top = Math.round(coords[3] * 1000) / 1000;
+ settings.view.fit(transformExtent([left, top, right, bottom]),
+ settings.map.getSize());
if (settings.dynamic_categories) {
methods.loadCategories();
}
diff --git a/chimere/static/ol3/ol-debug.js b/chimere/static/ol3/ol-debug.js
new file mode 100644
index 0000000..d875197
--- /dev/null
+++ b/chimere/static/ol3/ol-debug.js
@@ -0,0 +1,107541 @@
+// OpenLayers 3. See http://openlayers.org/
+// License: https://raw.githubusercontent.com/openlayers/ol3/master/LICENSE.md
+// Version: v3.17.1
+
+(function (root, factory) {
+ if (typeof exports === "object") {
+ module.exports = factory();
+ } else if (typeof define === "function" && define.amd) {
+ define([], factory);
+ } else {
+ root.ol = factory();
+ }
+}(this, function () {
+ var OPENLAYERS = {};
+ var goog = this.goog = {};
+this.CLOSURE_NO_DEPS = true;
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Bootstrap for the Google JS Library (Closure).
+ *
+ * In uncompiled mode base.js will write out Closure's deps file, unless the
+ * global <code>CLOSURE_NO_DEPS</code> is set to true. This allows projects to
+ * include their own deps file(s) from different locations.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ *
+ * @provideGoog
+ */
+
+
+/**
+ * @define {boolean} Overridden to true by the compiler when
+ * --process_closure_primitives is specified.
+ */
+var COMPILED = false;
+
+
+/**
+ * Base namespace for the Closure library. Checks to see goog is already
+ * defined in the current scope before assigning to prevent clobbering if
+ * base.js is loaded more than once.
+ *
+ * @const
+ */
+var goog = goog || {};
+
+
+/**
+ * Reference to the global context. In most cases this will be 'window'.
+ */
+goog.global = this;
+
+
+/**
+ * A hook for overriding the define values in uncompiled mode.
+ *
+ * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before
+ * loading base.js. If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES},
+ * {@code goog.define} will use the value instead of the default value. This
+ * allows flags to be overwritten without compilation (this is normally
+ * accomplished with the compiler's "define" flag).
+ *
+ * Example:
+ * <pre>
+ * var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false};
+ * </pre>
+ *
+ * @type {Object<string, (string|number|boolean)>|undefined}
+ */
+goog.global.CLOSURE_UNCOMPILED_DEFINES;
+
+
+/**
+ * A hook for overriding the define values in uncompiled or compiled mode,
+ * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code. In
+ * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence.
+ *
+ * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or
+ * string literals or the compiler will emit an error.
+ *
+ * While any @define value may be set, only those set with goog.define will be
+ * effective for uncompiled code.
+ *
+ * Example:
+ * <pre>
+ * var CLOSURE_DEFINES = {'goog.DEBUG': false} ;
+ * </pre>
+ *
+ * @type {Object<string, (string|number|boolean)>|undefined}
+ */
+goog.global.CLOSURE_DEFINES;
+
+
+/**
+ * Returns true if the specified value is not undefined.
+ * WARNING: Do not use this to test if an object has a property. Use the in
+ * operator instead.
+ *
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is defined.
+ */
+goog.isDef = function(val) {
+ // void 0 always evaluates to undefined and hence we do not need to depend on
+ // the definition of the global variable named 'undefined'.
+ return val !== void 0;
+};
+
+
+/**
+ * Builds an object structure for the provided namespace path, ensuring that
+ * names that already exist are not overwritten. For example:
+ * "a.b.c" -> a = {};a.b={};a.b.c={};
+ * Used by goog.provide and goog.exportSymbol.
+ * @param {string} name name of the object that this file defines.
+ * @param {*=} opt_object the object to expose at the end of the path.
+ * @param {Object=} opt_objectToExportTo The object to add the path to; default
+ * is |goog.global|.
+ * @private
+ */
+goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) {
+ var parts = name.split('.');
+ var cur = opt_objectToExportTo || goog.global;
+
+ // Internet Explorer exhibits strange behavior when throwing errors from
+ // methods externed in this manner. See the testExportSymbolExceptions in
+ // base_test.html for an example.
+ if (!(parts[0] in cur) && cur.execScript) {
+ cur.execScript('var ' + parts[0]);
+ }
+
+ // Certain browsers cannot parse code in the form for((a in b); c;);
+ // This pattern is produced by the JSCompiler when it collapses the
+ // statement above into the conditional loop below. To prevent this from
+ // happening, use a for-loop and reserve the init logic as below.
+
+ // Parentheses added to eliminate strict JS warning in Firefox.
+ for (var part; parts.length && (part = parts.shift());) {
+ if (!parts.length && goog.isDef(opt_object)) {
+ // last part and we have an object; use it
+ cur[part] = opt_object;
+ } else if (cur[part]) {
+ cur = cur[part];
+ } else {
+ cur = cur[part] = {};
+ }
+ }
+};
+
+
+/**
+ * Defines a named value. In uncompiled mode, the value is retrieved from
+ * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and
+ * has the property specified, and otherwise used the defined defaultValue.
+ * When compiled the default can be overridden using the compiler
+ * options or the value set in the CLOSURE_DEFINES object.
+ *
+ * @param {string} name The distinguished name to provide.
+ * @param {string|number|boolean} defaultValue
+ */
+goog.define = function(name, defaultValue) {
+ var value = defaultValue;
+ if (!COMPILED) {
+ if (goog.global.CLOSURE_UNCOMPILED_DEFINES &&
+ Object.prototype.hasOwnProperty.call(
+ goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) {
+ value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name];
+ } else if (
+ goog.global.CLOSURE_DEFINES &&
+ Object.prototype.hasOwnProperty.call(
+ goog.global.CLOSURE_DEFINES, name)) {
+ value = goog.global.CLOSURE_DEFINES[name];
+ }
+ }
+ goog.exportPath_(name, value);
+};
+
+
+/**
+ * @define {boolean} DEBUG is provided as a convenience so that debugging code
+ * that should not be included in a production js_binary can be easily stripped
+ * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most
+ * toString() methods should be declared inside an "if (goog.DEBUG)" conditional
+ * because they are generally used for debugging purposes and it is difficult
+ * for the JSCompiler to statically determine whether they are used.
+ */
+goog.define('goog.DEBUG', true);
+
+
+/**
+ * @define {string} LOCALE defines the locale being used for compilation. It is
+ * used to select locale specific data to be compiled in js binary. BUILD rule
+ * can specify this value by "--define goog.LOCALE=<locale_name>" as JSCompiler
+ * option.
+ *
+ * Take into account that the locale code format is important. You should use
+ * the canonical Unicode format with hyphen as a delimiter. Language must be
+ * lowercase, Language Script - Capitalized, Region - UPPERCASE.
+ * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN.
+ *
+ * See more info about locale codes here:
+ * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers
+ *
+ * For language codes you should use values defined by ISO 693-1. See it here
+ * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from
+ * this rule: the Hebrew language. For legacy reasons the old code (iw) should
+ * be used instead of the new code (he), see http://wiki/Main/IIISynonyms.
+ */
+goog.define('goog.LOCALE', 'en'); // default to en
+
+
+/**
+ * @define {boolean} Whether this code is running on trusted sites.
+ *
+ * On untrusted sites, several native functions can be defined or overridden by
+ * external libraries like Prototype, Datejs, and JQuery and setting this flag
+ * to false forces closure to use its own implementations when possible.
+ *
+ * If your JavaScript can be loaded by a third party site and you are wary about
+ * relying on non-standard implementations, specify
+ * "--define goog.TRUSTED_SITE=false" to the JSCompiler.
+ */
+goog.define('goog.TRUSTED_SITE', true);
+
+
+/**
+ * @define {boolean} Whether a project is expected to be running in strict mode.
+ *
+ * This define can be used to trigger alternate implementations compatible with
+ * running in EcmaScript Strict mode or warn about unavailable functionality.
+ * @see https://goo.gl/PudQ4y
+ *
+ */
+goog.define('goog.STRICT_MODE_COMPATIBLE', false);
+
+
+/**
+ * @define {boolean} Whether code that calls {@link goog.setTestOnly} should
+ * be disallowed in the compilation unit.
+ */
+goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG);
+
+
+/**
+ * @define {boolean} Whether to use a Chrome app CSP-compliant method for
+ * loading scripts via goog.require. @see appendScriptSrcNode_.
+ */
+goog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false);
+
+
+/**
+ * Defines a namespace in Closure.
+ *
+ * A namespace may only be defined once in a codebase. It may be defined using
+ * goog.provide() or goog.module().
+ *
+ * The presence of one or more goog.provide() calls in a file indicates
+ * that the file defines the given objects/namespaces.
+ * Provided symbols must not be null or undefined.
+ *
+ * In addition, goog.provide() creates the object stubs for a namespace
+ * (for example, goog.provide("goog.foo.bar") will create the object
+ * goog.foo.bar if it does not already exist).
+ *
+ * Build tools also scan for provide/require/module statements
+ * to discern dependencies, build dependency files (see deps.js), etc.
+ *
+ * @see goog.require
+ * @see goog.module
+ * @param {string} name Namespace provided by this file in the form
+ * "goog.package.part".
+ */
+goog.provide = function(name) {
+ if (goog.isInModuleLoader_()) {
+ throw Error('goog.provide can not be used within a goog.module.');
+ }
+ if (!COMPILED) {
+ // Ensure that the same namespace isn't provided twice.
+ // A goog.module/goog.provide maps a goog.require to a specific file
+ if (goog.isProvided_(name)) {
+ throw Error('Namespace "' + name + '" already declared.');
+ }
+ }
+
+ goog.constructNamespace_(name);
+};
+
+
+/**
+ * @param {string} name Namespace provided by this file in the form
+ * "goog.package.part".
+ * @param {Object=} opt_obj The object to embed in the namespace.
+ * @private
+ */
+goog.constructNamespace_ = function(name, opt_obj) {
+ if (!COMPILED) {
+ delete goog.implicitNamespaces_[name];
+
+ var namespace = name;
+ while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) {
+ if (goog.getObjectByName(namespace)) {
+ break;
+ }
+ goog.implicitNamespaces_[namespace] = true;
+ }
+ }
+
+ goog.exportPath_(name, opt_obj);
+};
+
+
+/**
+ * Module identifier validation regexp.
+ * Note: This is a conservative check, it is very possible to be more lenient,
+ * the primary exclusion here is "/" and "\" and a leading ".", these
+ * restrictions are intended to leave the door open for using goog.require
+ * with relative file paths rather than module identifiers.
+ * @private
+ */
+goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/;
+
+
+/**
+ * Defines a module in Closure.
+ *
+ * Marks that this file must be loaded as a module and claims the namespace.
+ *
+ * A namespace may only be defined once in a codebase. It may be defined using
+ * goog.provide() or goog.module().
+ *
+ * goog.module() has three requirements:
+ * - goog.module may not be used in the same file as goog.provide.
+ * - goog.module must be the first statement in the file.
+ * - only one goog.module is allowed per file.
+ *
+ * When a goog.module annotated file is loaded, it is enclosed in
+ * a strict function closure. This means that:
+ * - any variables declared in a goog.module file are private to the file
+ * (not global), though the compiler is expected to inline the module.
+ * - The code must obey all the rules of "strict" JavaScript.
+ * - the file will be marked as "use strict"
+ *
+ * NOTE: unlike goog.provide, goog.module does not declare any symbols by
+ * itself. If declared symbols are desired, use
+ * goog.module.declareLegacyNamespace().
+ *
+ *
+ * See the public goog.module proposal: http://goo.gl/Va1hin
+ *
+ * @param {string} name Namespace provided by this file in the form
+ * "goog.package.part", is expected but not required.
+ */
+goog.module = function(name) {
+ if (!goog.isString(name) || !name ||
+ name.search(goog.VALID_MODULE_RE_) == -1) {
+ throw Error('Invalid module identifier');
+ }
+ if (!goog.isInModuleLoader_()) {
+ throw Error('Module ' + name + ' has been loaded incorrectly.');
+ }
+ if (goog.moduleLoaderState_.moduleName) {
+ throw Error('goog.module may only be called once per module.');
+ }
+
+ // Store the module name for the loader.
+ goog.moduleLoaderState_.moduleName = name;
+ if (!COMPILED) {
+ // Ensure that the same namespace isn't provided twice.
+ // A goog.module/goog.provide maps a goog.require to a specific file
+ if (goog.isProvided_(name)) {
+ throw Error('Namespace "' + name + '" already declared.');
+ }
+ delete goog.implicitNamespaces_[name];
+ }
+};
+
+
+/**
+ * @param {string} name The module identifier.
+ * @return {?} The module exports for an already loaded module or null.
+ *
+ * Note: This is not an alternative to goog.require, it does not
+ * indicate a hard dependency, instead it is used to indicate
+ * an optional dependency or to access the exports of a module
+ * that has already been loaded.
+ * @suppress {missingProvide}
+ */
+goog.module.get = function(name) {
+ return goog.module.getInternal_(name);
+};
+
+
+/**
+ * @param {string} name The module identifier.
+ * @return {?} The module exports for an already loaded module or null.
+ * @private
+ */
+goog.module.getInternal_ = function(name) {
+ if (!COMPILED) {
+ if (goog.isProvided_(name)) {
+ // goog.require only return a value with-in goog.module files.
+ return name in goog.loadedModules_ ? goog.loadedModules_[name] :
+ goog.getObjectByName(name);
+ } else {
+ return null;
+ }
+ }
+};
+
+
+/**
+ * @private {?{moduleName: (string|undefined), declareLegacyNamespace:boolean}}
+ */
+goog.moduleLoaderState_ = null;
+
+
+/**
+ * @private
+ * @return {boolean} Whether a goog.module is currently being initialized.
+ */
+goog.isInModuleLoader_ = function() {
+ return goog.moduleLoaderState_ != null;
+};
+
+
+/**
+ * Provide the module's exports as a globally accessible object under the
+ * module's declared name. This is intended to ease migration to goog.module
+ * for files that have existing usages.
+ * @suppress {missingProvide}
+ */
+goog.module.declareLegacyNamespace = function() {
+ if (!COMPILED && !goog.isInModuleLoader_()) {
+ throw new Error(
+ 'goog.module.declareLegacyNamespace must be called from ' +
+ 'within a goog.module');
+ }
+ if (!COMPILED && !goog.moduleLoaderState_.moduleName) {
+ throw Error(
+ 'goog.module must be called prior to ' +
+ 'goog.module.declareLegacyNamespace.');
+ }
+ goog.moduleLoaderState_.declareLegacyNamespace = true;
+};
+
+
+/**
+ * Marks that the current file should only be used for testing, and never for
+ * live code in production.
+ *
+ * In the case of unit tests, the message may optionally be an exact namespace
+ * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra
+ * provide (if not explicitly defined in the code).
+ *
+ * @param {string=} opt_message Optional message to add to the error that's
+ * raised when used in production code.
+ */
+goog.setTestOnly = function(opt_message) {
+ if (goog.DISALLOW_TEST_ONLY_CODE) {
+ opt_message = opt_message || '';
+ throw Error(
+ 'Importing test-only code into non-debug environment' +
+ (opt_message ? ': ' + opt_message : '.'));
+ }
+};
+
+
+/**
+ * Forward declares a symbol. This is an indication to the compiler that the
+ * symbol may be used in the source yet is not required and may not be provided
+ * in compilation.
+ *
+ * The most common usage of forward declaration is code that takes a type as a
+ * function parameter but does not need to require it. By forward declaring
+ * instead of requiring, no hard dependency is made, and (if not required
+ * elsewhere) the namespace may never be required and thus, not be pulled
+ * into the JavaScript binary. If it is required elsewhere, it will be type
+ * checked as normal.
+ *
+ *
+ * @param {string} name The namespace to forward declare in the form of
+ * "goog.package.part".
+ */
+goog.forwardDeclare = function(name) {};
+
+
+/**
+ * Forward declare type information. Used to assign types to goog.global
+ * referenced object that would otherwise result in unknown type references
+ * and thus block property disambiguation.
+ */
+goog.forwardDeclare('Document');
+goog.forwardDeclare('HTMLScriptElement');
+goog.forwardDeclare('XMLHttpRequest');
+
+
+if (!COMPILED) {
+ /**
+ * Check if the given name has been goog.provided. This will return false for
+ * names that are available only as implicit namespaces.
+ * @param {string} name name of the object to look for.
+ * @return {boolean} Whether the name has been provided.
+ * @private
+ */
+ goog.isProvided_ = function(name) {
+ return (name in goog.loadedModules_) ||
+ (!goog.implicitNamespaces_[name] &&
+ goog.isDefAndNotNull(goog.getObjectByName(name)));
+ };
+
+ /**
+ * Namespaces implicitly defined by goog.provide. For example,
+ * goog.provide('goog.events.Event') implicitly declares that 'goog' and
+ * 'goog.events' must be namespaces.
+ *
+ * @type {!Object<string, (boolean|undefined)>}
+ * @private
+ */
+ goog.implicitNamespaces_ = {'goog.module': true};
+
+ // NOTE: We add goog.module as an implicit namespace as goog.module is defined
+ // here and because the existing module package has not been moved yet out of
+ // the goog.module namespace. This satisifies both the debug loader and
+ // ahead-of-time dependency management.
+}
+
+
+/**
+ * Returns an object based on its fully qualified external name. The object
+ * is not found if null or undefined. If you are using a compilation pass that
+ * renames property names beware that using this function will not find renamed
+ * properties.
+ *
+ * @param {string} name The fully qualified name.
+ * @param {Object=} opt_obj The object within which to look; default is
+ * |goog.global|.
+ * @return {?} The value (object or primitive) or, if not found, null.
+ */
+goog.getObjectByName = function(name, opt_obj) {
+ var parts = name.split('.');
+ var cur = opt_obj || goog.global;
+ for (var part; part = parts.shift();) {
+ if (goog.isDefAndNotNull(cur[part])) {
+ cur = cur[part];
+ } else {
+ return null;
+ }
+ }
+ return cur;
+};
+
+
+/**
+ * Globalizes a whole namespace, such as goog or goog.lang.
+ *
+ * @param {!Object} obj The namespace to globalize.
+ * @param {Object=} opt_global The object to add the properties to.
+ * @deprecated Properties may be explicitly exported to the global scope, but
+ * this should no longer be done in bulk.
+ */
+goog.globalize = function(obj, opt_global) {
+ var global = opt_global || goog.global;
+ for (var x in obj) {
+ global[x] = obj[x];
+ }
+};
+
+
+/**
+ * Adds a dependency from a file to the files it requires.
+ * @param {string} relPath The path to the js file.
+ * @param {!Array<string>} provides An array of strings with
+ * the names of the objects this file provides.
+ * @param {!Array<string>} requires An array of strings with
+ * the names of the objects this file requires.
+ * @param {boolean|!Object<string>=} opt_loadFlags Parameters indicating
+ * how the file must be loaded. The boolean 'true' is equivalent
+ * to {'module': 'goog'} for backwards-compatibility. Valid properties
+ * and values include {'module': 'goog'} and {'lang': 'es6'}.
+ */
+goog.addDependency = function(relPath, provides, requires, opt_loadFlags) {
+ if (goog.DEPENDENCIES_ENABLED) {
+ var provide, require;
+ var path = relPath.replace(/\\/g, '/');
+ var deps = goog.dependencies_;
+ if (!opt_loadFlags || typeof opt_loadFlags === 'boolean') {
+ opt_loadFlags = opt_loadFlags ? {'module': 'goog'} : {};
+ }
+ for (var i = 0; provide = provides[i]; i++) {
+ deps.nameToPath[provide] = path;
+ deps.loadFlags[path] = opt_loadFlags;
+ }
+ for (var j = 0; require = requires[j]; j++) {
+ if (!(path in deps.requires)) {
+ deps.requires[path] = {};
+ }
+ deps.requires[path][require] = true;
+ }
+ }
+};
+
+
+
+
+// NOTE(nnaze): The debug DOM loader was included in base.js as an original way
+// to do "debug-mode" development. The dependency system can sometimes be
+// confusing, as can the debug DOM loader's asynchronous nature.
+//
+// With the DOM loader, a call to goog.require() is not blocking -- the script
+// will not load until some point after the current script. If a namespace is
+// needed at runtime, it needs to be defined in a previous script, or loaded via
+// require() with its registered dependencies.
+//
+// User-defined namespaces may need their own deps file. For a reference on
+// creating a deps file, see:
+// Externally: https://developers.google.com/closure/library/docs/depswriter
+//
+// Because of legacy clients, the DOM loader can't be easily removed from
+// base.js. Work is being done to make it disableable or replaceable for
+// different environments (DOM-less JavaScript interpreters like Rhino or V8,
+// for example). See bootstrap/ for more information.
+
+
+/**
+ * @define {boolean} Whether to enable the debug loader.
+ *
+ * If enabled, a call to goog.require() will attempt to load the namespace by
+ * appending a script tag to the DOM (if the namespace has been registered).
+ *
+ * If disabled, goog.require() will simply assert that the namespace has been
+ * provided (and depend on the fact that some outside tool correctly ordered
+ * the script).
+ */
+goog.define('goog.ENABLE_DEBUG_LOADER', true);
+
+
+/**
+ * @param {string} msg
+ * @private
+ */
+goog.logToConsole_ = function(msg) {
+ if (goog.global.console) {
+ goog.global.console['error'](msg);
+ }
+};
+
+
+/**
+ * Implements a system for the dynamic resolution of dependencies that works in
+ * parallel with the BUILD system. Note that all calls to goog.require will be
+ * stripped by the JSCompiler when the --process_closure_primitives option is
+ * used.
+ * @see goog.provide
+ * @param {string} name Namespace to include (as was given in goog.provide()) in
+ * the form "goog.package.part".
+ * @return {?} If called within a goog.module file, the associated namespace or
+ * module otherwise null.
+ */
+goog.require = function(name) {
+ // If the object already exists we do not need do do anything.
+ if (!COMPILED) {
+ if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) {
+ goog.maybeProcessDeferredDep_(name);
+ }
+
+ if (goog.isProvided_(name)) {
+ if (goog.isInModuleLoader_()) {
+ return goog.module.getInternal_(name);
+ } else {
+ return null;
+ }
+ }
+
+ if (goog.ENABLE_DEBUG_LOADER) {
+ var path = goog.getPathFromDeps_(name);
+ if (path) {
+ goog.writeScripts_(path);
+ return null;
+ }
+ }
+
+ var errorMessage = 'goog.require could not find: ' + name;
+ goog.logToConsole_(errorMessage);
+
+ throw Error(errorMessage);
+ }
+};
+
+
+/**
+ * Path for included scripts.
+ * @type {string}
+ */
+goog.basePath = '';
+
+
+/**
+ * A hook for overriding the base path.
+ * @type {string|undefined}
+ */
+goog.global.CLOSURE_BASE_PATH;
+
+
+/**
+ * Whether to write out Closure's deps file. By default, the deps are written.
+ * @type {boolean|undefined}
+ */
+goog.global.CLOSURE_NO_DEPS;
+
+
+/**
+ * A function to import a single script. This is meant to be overridden when
+ * Closure is being run in non-HTML contexts, such as web workers. It's defined
+ * in the global scope so that it can be set before base.js is loaded, which
+ * allows deps.js to be imported properly.
+ *
+ * The function is passed the script source, which is a relative URI. It should
+ * return true if the script was imported, false otherwise.
+ * @type {(function(string): boolean)|undefined}
+ */
+goog.global.CLOSURE_IMPORT_SCRIPT;
+
+
+/**
+ * Null function used for default values of callbacks, etc.
+ * @return {void} Nothing.
+ */
+goog.nullFunction = function() {};
+
+
+/**
+ * When defining a class Foo with an abstract method bar(), you can do:
+ * Foo.prototype.bar = goog.abstractMethod
+ *
+ * Now if a subclass of Foo fails to override bar(), an error will be thrown
+ * when bar() is invoked.
+ *
+ * Note: This does not take the name of the function to override as an argument
+ * because that would make it more difficult to obfuscate our JavaScript code.
+ *
+ * @type {!Function}
+ * @throws {Error} when invoked to indicate the method should be overridden.
+ */
+goog.abstractMethod = function() {
+ throw Error('unimplemented abstract method');
+};
+
+
+/**
+ * Adds a {@code getInstance} static method that always returns the same
+ * instance object.
+ * @param {!Function} ctor The constructor for the class to add the static
+ * method to.
+ */
+goog.addSingletonGetter = function(ctor) {
+ ctor.getInstance = function() {
+ if (ctor.instance_) {
+ return ctor.instance_;
+ }
+ if (goog.DEBUG) {
+ // NOTE: JSCompiler can't optimize away Array#push.
+ goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor;
+ }
+ return ctor.instance_ = new ctor;
+ };
+};
+
+
+/**
+ * All singleton classes that have been instantiated, for testing. Don't read
+ * it directly, use the {@code goog.testing.singleton} module. The compiler
+ * removes this variable if unused.
+ * @type {!Array<!Function>}
+ * @private
+ */
+goog.instantiatedSingletons_ = [];
+
+
+/**
+ * @define {boolean} Whether to load goog.modules using {@code eval} when using
+ * the debug loader. This provides a better debugging experience as the
+ * source is unmodified and can be edited using Chrome Workspaces or similar.
+ * However in some environments the use of {@code eval} is banned
+ * so we provide an alternative.
+ */
+goog.define('goog.LOAD_MODULE_USING_EVAL', true);
+
+
+/**
+ * @define {boolean} Whether the exports of goog.modules should be sealed when
+ * possible.
+ */
+goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG);
+
+
+/**
+ * The registry of initialized modules:
+ * the module identifier to module exports map.
+ * @private @const {!Object<string, ?>}
+ */
+goog.loadedModules_ = {};
+
+
+/**
+ * True if goog.dependencies_ is available.
+ * @const {boolean}
+ */
+goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER;
+
+
+/**
+ * @define {string} How to decide whether to transpile. Valid values
+ * are 'always', 'never', and 'detect'. The default ('detect') is to
+ * use feature detection to determine which language levels need
+ * transpilation.
+ */
+// NOTE(user): we could expand this to accept a language level to bypass
+// detection: e.g. goog.TRANSPILE == 'es5' would transpile ES6 files but
+// would leave ES3 and ES5 files alone.
+goog.define('goog.TRANSPILE', 'detect');
+
+
+/**
+ * @define {string} Path to the transpiler. Executing the script at this
+ * path (relative to base.js) should define a function $jscomp.transpile.
+ */
+goog.define('goog.TRANSPILER', 'transpile.js');
+
+
+if (goog.DEPENDENCIES_ENABLED) {
+ /**
+ * This object is used to keep track of dependencies and other data that is
+ * used for loading scripts.
+ * @private
+ * @type {{
+ * loadFlags: !Object<string, !Object<string, string>>,
+ * nameToPath: !Object<string, string>,
+ * requires: !Object<string, !Object<string, boolean>>,
+ * visited: !Object<string, boolean>,
+ * written: !Object<string, boolean>,
+ * deferred: !Object<string, string>
+ * }}
+ */
+ goog.dependencies_ = {
+ loadFlags: {}, // 1 to 1
+
+ nameToPath: {}, // 1 to 1
+
+ requires: {}, // 1 to many
+
+ // Used when resolving dependencies to prevent us from visiting file twice.
+ visited: {},
+
+ written: {}, // Used to keep track of script files we have written.
+
+ deferred: {} // Used to track deferred module evaluations in old IEs
+ };
+
+
+ /**
+ * Tries to detect whether is in the context of an HTML document.
+ * @return {boolean} True if it looks like HTML document.
+ * @private
+ */
+ goog.inHtmlDocument_ = function() {
+ /** @type {Document} */
+ var doc = goog.global.document;
+ return doc != null && 'write' in doc; // XULDocument misses write.
+ };
+
+
+ /**
+ * Tries to detect the base path of base.js script that bootstraps Closure.
+ * @private
+ */
+ goog.findBasePath_ = function() {
+ if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) {
+ goog.basePath = goog.global.CLOSURE_BASE_PATH;
+ return;
+ } else if (!goog.inHtmlDocument_()) {
+ return;
+ }
+ /** @type {Document} */
+ var doc = goog.global.document;
+ var scripts = doc.getElementsByTagName('SCRIPT');
+ // Search backwards since the current script is in almost all cases the one
+ // that has base.js.
+ for (var i = scripts.length - 1; i >= 0; --i) {
+ var script = /** @type {!HTMLScriptElement} */ (scripts[i]);
+ var src = script.src;
+ var qmark = src.lastIndexOf('?');
+ var l = qmark == -1 ? src.length : qmark;
+ if (src.substr(l - 7, 7) == 'base.js') {
+ goog.basePath = src.substr(0, l - 7);
+ return;
+ }
+ }
+ };
+
+
+ /**
+ * Imports a script if, and only if, that script hasn't already been imported.
+ * (Must be called at execution time)
+ * @param {string} src Script source.
+ * @param {string=} opt_sourceText The optionally source text to evaluate
+ * @private
+ */
+ goog.importScript_ = function(src, opt_sourceText) {
+ var importScript =
+ goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_;
+ if (importScript(src, opt_sourceText)) {
+ goog.dependencies_.written[src] = true;
+ }
+ };
+
+
+ /**
+ * Whether the browser is IE9 or earlier, which needs special handling
+ * for deferred modules.
+ * @const @private {boolean}
+ */
+ goog.IS_OLD_IE_ =
+ !!(!goog.global.atob && goog.global.document && goog.global.document.all);
+
+
+ /**
+ * Given a URL initiate retrieval and execution of a script that needs
+ * pre-processing.
+ * @param {string} src Script source URL.
+ * @param {boolean} isModule Whether this is a goog.module.
+ * @param {boolean} needsTranspile Whether this source needs transpilation.
+ * @private
+ */
+ goog.importProcessedScript_ = function(src, isModule, needsTranspile) {
+ // In an attempt to keep browsers from timing out loading scripts using
+ // synchronous XHRs, put each load in its own script block.
+ var bootstrap = 'goog.retrieveAndExec_("' + src + '", ' + isModule + ', ' +
+ needsTranspile + ');';
+
+ goog.importScript_('', bootstrap);
+ };
+
+
+ /** @private {!Array<string>} */
+ goog.queuedModules_ = [];
+
+
+ /**
+ * Return an appropriate module text. Suitable to insert into
+ * a script tag (that is unescaped).
+ * @param {string} srcUrl
+ * @param {string} scriptText
+ * @return {string}
+ * @private
+ */
+ goog.wrapModule_ = function(srcUrl, scriptText) {
+ if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) {
+ return '' +
+ 'goog.loadModule(function(exports) {' +
+ '"use strict";' + scriptText +
+ '\n' + // terminate any trailing single line comment.
+ ';return exports' +
+ '});' +
+ '\n//# sourceURL=' + srcUrl + '\n';
+ } else {
+ return '' +
+ 'goog.loadModule(' +
+ goog.global.JSON.stringify(
+ scriptText + '\n//# sourceURL=' + srcUrl + '\n') +
+ ');';
+ }
+ };
+
+ // On IE9 and earlier, it is necessary to handle
+ // deferred module loads. In later browsers, the
+ // code to be evaluated is simply inserted as a script
+ // block in the correct order. To eval deferred
+ // code at the right time, we piggy back on goog.require to call
+ // goog.maybeProcessDeferredDep_.
+ //
+ // The goog.requires are used both to bootstrap
+ // the loading process (when no deps are available) and
+ // declare that they should be available.
+ //
+ // Here we eval the sources, if all the deps are available
+ // either already eval'd or goog.require'd. This will
+ // be the case when all the dependencies have already
+ // been loaded, and the dependent module is loaded.
+ //
+ // But this alone isn't sufficient because it is also
+ // necessary to handle the case where there is no root
+ // that is not deferred. For that there we register for an event
+ // and trigger goog.loadQueuedModules_ handle any remaining deferred
+ // evaluations.
+
+ /**
+ * Handle any remaining deferred goog.module evals.
+ * @private
+ */
+ goog.loadQueuedModules_ = function() {
+ var count = goog.queuedModules_.length;
+ if (count > 0) {
+ var queue = goog.queuedModules_;
+ goog.queuedModules_ = [];
+ for (var i = 0; i < count; i++) {
+ var path = queue[i];
+ goog.maybeProcessDeferredPath_(path);
+ }
+ }
+ };
+
+
+ /**
+ * Eval the named module if its dependencies are
+ * available.
+ * @param {string} name The module to load.
+ * @private
+ */
+ goog.maybeProcessDeferredDep_ = function(name) {
+ if (goog.isDeferredModule_(name) && goog.allDepsAreAvailable_(name)) {
+ var path = goog.getPathFromDeps_(name);
+ goog.maybeProcessDeferredPath_(goog.basePath + path);
+ }
+ };
+
+ /**
+ * @param {string} name The module to check.
+ * @return {boolean} Whether the name represents a
+ * module whose evaluation has been deferred.
+ * @private
+ */
+ goog.isDeferredModule_ = function(name) {
+ var path = goog.getPathFromDeps_(name);
+ var loadFlags = path && goog.dependencies_.loadFlags[path] || {};
+ if (path && (loadFlags['module'] == 'goog' ||
+ goog.needsTranspile_(loadFlags['lang']))) {
+ var abspath = goog.basePath + path;
+ return (abspath) in goog.dependencies_.deferred;
+ }
+ return false;
+ };
+
+ /**
+ * @param {string} name The module to check.
+ * @return {boolean} Whether the name represents a
+ * module whose declared dependencies have all been loaded
+ * (eval'd or a deferred module load)
+ * @private
+ */
+ goog.allDepsAreAvailable_ = function(name) {
+ var path = goog.getPathFromDeps_(name);
+ if (path && (path in goog.dependencies_.requires)) {
+ for (var requireName in goog.dependencies_.requires[path]) {
+ if (!goog.isProvided_(requireName) &&
+ !goog.isDeferredModule_(requireName)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+
+
+ /**
+ * @param {string} abspath
+ * @private
+ */
+ goog.maybeProcessDeferredPath_ = function(abspath) {
+ if (abspath in goog.dependencies_.deferred) {
+ var src = goog.dependencies_.deferred[abspath];
+ delete goog.dependencies_.deferred[abspath];
+ goog.globalEval(src);
+ }
+ };
+
+
+ /**
+ * Load a goog.module from the provided URL. This is not a general purpose
+ * code loader and does not support late loading code, that is it should only
+ * be used during page load. This method exists to support unit tests and
+ * "debug" loaders that would otherwise have inserted script tags. Under the
+ * hood this needs to use a synchronous XHR and is not recommeneded for
+ * production code.
+ *
+ * The module's goog.requires must have already been satisified; an exception
+ * will be thrown if this is not the case. This assumption is that no
+ * "deps.js" file exists, so there is no way to discover and locate the
+ * module-to-be-loaded's dependencies and no attempt is made to do so.
+ *
+ * There should only be one attempt to load a module. If
+ * "goog.loadModuleFromUrl" is called for an already loaded module, an
+ * exception will be throw.
+ *
+ * @param {string} url The URL from which to attempt to load the goog.module.
+ */
+ goog.loadModuleFromUrl = function(url) {
+ // Because this executes synchronously, we don't need to do any additional
+ // bookkeeping. When "goog.loadModule" the namespace will be marked as
+ // having been provided which is sufficient.
+ goog.retrieveAndExec_(url, true, false);
+ };
+
+
+ /**
+ * Writes a new script pointing to {@code src} directly into the DOM.
+ *
+ * NOTE: This method is not CSP-compliant. @see goog.appendScriptSrcNode_ for
+ * the fallback mechanism.
+ *
+ * @param {string} src The script URL.
+ * @private
+ */
+ goog.writeScriptSrcNode_ = function(src) {
+ goog.global.document.write(
+ '<script type="text/javascript" src="' + src + '"></' +
+ 'script>');
+ };
+
+
+ /**
+ * Appends a new script node to the DOM using a CSP-compliant mechanism. This
+ * method exists as a fallback for document.write (which is not allowed in a
+ * strict CSP context, e.g., Chrome apps).
+ *
+ * NOTE: This method is not analogous to using document.write to insert a
+ * <script> tag; specifically, the user agent will execute a script added by
+ * document.write immediately after the current script block finishes
+ * executing, whereas the DOM-appended script node will not be executed until
+ * the entire document is parsed and executed. That is to say, this script is
+ * added to the end of the script execution queue.
+ *
+ * The page must not attempt to call goog.required entities until after the
+ * document has loaded, e.g., in or after the window.onload callback.
+ *
+ * @param {string} src The script URL.
+ * @private
+ */
+ goog.appendScriptSrcNode_ = function(src) {
+ /** @type {Document} */
+ var doc = goog.global.document;
+ var scriptEl =
+ /** @type {HTMLScriptElement} */ (doc.createElement('script'));
+ scriptEl.type = 'text/javascript';
+ scriptEl.src = src;
+ scriptEl.defer = false;
+ scriptEl.async = false;
+ doc.head.appendChild(scriptEl);
+ };
+
+
+ /**
+ * The default implementation of the import function. Writes a script tag to
+ * import the script.
+ *
+ * @param {string} src The script url.
+ * @param {string=} opt_sourceText The optionally source text to evaluate
+ * @return {boolean} True if the script was imported, false otherwise.
+ * @private
+ */
+ goog.writeScriptTag_ = function(src, opt_sourceText) {
+ if (goog.inHtmlDocument_()) {
+ /** @type {!HTMLDocument} */
+ var doc = goog.global.document;
+
+ // If the user tries to require a new symbol after document load,
+ // something has gone terribly wrong. Doing a document.write would
+ // wipe out the page. This does not apply to the CSP-compliant method
+ // of writing script tags.
+ if (!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING &&
+ doc.readyState == 'complete') {
+ // Certain test frameworks load base.js multiple times, which tries
+ // to write deps.js each time. If that happens, just fail silently.
+ // These frameworks wipe the page between each load of base.js, so this
+ // is OK.
+ var isDeps = /\bdeps.js$/.test(src);
+ if (isDeps) {
+ return false;
+ } else {
+ throw Error('Cannot write "' + src + '" after document load');
+ }
+ }
+
+ if (opt_sourceText === undefined) {
+ if (!goog.IS_OLD_IE_) {
+ if (goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING) {
+ goog.appendScriptSrcNode_(src);
+ } else {
+ goog.writeScriptSrcNode_(src);
+ }
+ } else {
+ var state = " onreadystatechange='goog.onScriptLoad_(this, " +
+ ++goog.lastNonModuleScriptIndex_ + ")' ";
+ doc.write(
+ '<script type="text/javascript" src="' + src + '"' + state +
+ '></' +
+ 'script>');
+ }
+ } else {
+ doc.write(
+ '<script type="text/javascript">' + opt_sourceText + '</' +
+ 'script>');
+ }
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+
+ /**
+ * Determines whether the given language needs to be transpiled.
+ * @param {string} lang
+ * @return {boolean}
+ * @private
+ */
+ goog.needsTranspile_ = function(lang) {
+ if (goog.TRANSPILE == 'always') {
+ return true;
+ } else if (goog.TRANSPILE == 'never') {
+ return false;
+ } else if (!goog.transpiledLanguages_) {
+ goog.transpiledLanguages_ = {'es5': true, 'es6': true, 'es6-impl': true};
+ /** @preserveTry */
+ try {
+ // Perform some quick conformance checks, to distinguish
+ // between browsers that support es5, es6-impl, or es6.
+
+ // Identify ES3-only browsers by their incorrect treatment of commas.
+ goog.transpiledLanguages_['es5'] = eval('[1,].length!=1');
+
+ // As browsers mature, features will be moved from the full test
+ // into the impl test. This must happen before the corresponding
+ // features are changed in the Closure Compiler's FeatureSet object.
+
+ // Test 1: es6-impl [FF49, Edge 13, Chrome 49]
+ // (a) let/const keyword, (b) class expressions, (c) Map object,
+ // (d) iterable arguments, (e) spread operator
+ var es6implTest =
+ 'let a={};const X=class{constructor(){}x(z){return new Map([' +
+ '...arguments]).get(z[0])==3}};return new X().x([a,3])';
+
+ // Test 2: es6 [FF50 (?), Edge 14 (?), Chrome 50]
+ // (a) default params (specifically shadowing locals),
+ // (b) destructuring, (c) block-scoped functions,
+ // (d) for-of (const), (e) new.target/Reflect.construct
+ var es6fullTest =
+ 'class X{constructor(){if(new.target!=String)throw 1;this.x=42}}' +
+ 'let q=Reflect.construct(X,[],String);if(q.x!=42||!(q instanceof ' +
+ 'String))throw 1;for(const a of[2,3]){if(a==2)continue;function ' +
+ 'f(z={a}){let a=0;return z.a}{function f(){return 0;}}return f()' +
+ '==3}';
+
+ if (eval('(()=>{"use strict";' + es6implTest + '})()')) {
+ goog.transpiledLanguages_['es6-impl'] = false;
+ }
+ if (eval('(()=>{"use strict";' + es6fullTest + '})()')) {
+ goog.transpiledLanguages_['es6'] = false;
+ }
+ } catch (err) {
+ }
+ }
+ return !!goog.transpiledLanguages_[lang];
+ };
+
+
+ /** @private {?Object<string, boolean>} */
+ goog.transpiledLanguages_ = null;
+
+
+ /** @private {number} */
+ goog.lastNonModuleScriptIndex_ = 0;
+
+
+ /**
+ * A readystatechange handler for legacy IE
+ * @param {!HTMLScriptElement} script
+ * @param {number} scriptIndex
+ * @return {boolean}
+ * @private
+ */
+ goog.onScriptLoad_ = function(script, scriptIndex) {
+ // for now load the modules when we reach the last script,
+ // later allow more inter-mingling.
+ if (script.readyState == 'complete' &&
+ goog.lastNonModuleScriptIndex_ == scriptIndex) {
+ goog.loadQueuedModules_();
+ }
+ return true;
+ };
+
+ /**
+ * Resolves dependencies based on the dependencies added using addDependency
+ * and calls importScript_ in the correct order.
+ * @param {string} pathToLoad The path from which to start discovering
+ * dependencies.
+ * @private
+ */
+ goog.writeScripts_ = function(pathToLoad) {
+ /** @type {!Array<string>} The scripts we need to write this time. */
+ var scripts = [];
+ var seenScript = {};
+ var deps = goog.dependencies_;
+
+ /** @param {string} path */
+ function visitNode(path) {
+ if (path in deps.written) {
+ return;
+ }
+
+ // We have already visited this one. We can get here if we have cyclic
+ // dependencies.
+ if (path in deps.visited) {
+ return;
+ }
+
+ deps.visited[path] = true;
+
+ if (path in deps.requires) {
+ for (var requireName in deps.requires[path]) {
+ // If the required name is defined, we assume that it was already
+ // bootstrapped by other means.
+ if (!goog.isProvided_(requireName)) {
+ if (requireName in deps.nameToPath) {
+ visitNode(deps.nameToPath[requireName]);
+ } else {
+ throw Error('Undefined nameToPath for ' + requireName);
+ }
+ }
+ }
+ }
+
+ if (!(path in seenScript)) {
+ seenScript[path] = true;
+ scripts.push(path);
+ }
+ }
+
+ visitNode(pathToLoad);
+
+ // record that we are going to load all these scripts.
+ for (var i = 0; i < scripts.length; i++) {
+ var path = scripts[i];
+ goog.dependencies_.written[path] = true;
+ }
+
+ // If a module is loaded synchronously then we need to
+ // clear the current inModuleLoader value, and restore it when we are
+ // done loading the current "requires".
+ var moduleState = goog.moduleLoaderState_;
+ goog.moduleLoaderState_ = null;
+
+ for (var i = 0; i < scripts.length; i++) {
+ var path = scripts[i];
+ if (path) {
+ var loadFlags = deps.loadFlags[path] || {};
+ var needsTranspile = goog.needsTranspile_(loadFlags['lang']);
+ if (loadFlags['module'] == 'goog' || needsTranspile) {
+ goog.importProcessedScript_(
+ goog.basePath + path, loadFlags['module'] == 'goog',
+ needsTranspile);
+ } else {
+ goog.importScript_(goog.basePath + path);
+ }
+ } else {
+ goog.moduleLoaderState_ = moduleState;
+ throw Error('Undefined script input');
+ }
+ }
+
+ // restore the current "module loading state"
+ goog.moduleLoaderState_ = moduleState;
+ };
+
+
+ /**
+ * Looks at the dependency rules and tries to determine the script file that
+ * fulfills a particular rule.
+ * @param {string} rule In the form goog.namespace.Class or project.script.
+ * @return {?string} Url corresponding to the rule, or null.
+ * @private
+ */
+ goog.getPathFromDeps_ = function(rule) {
+ if (rule in goog.dependencies_.nameToPath) {
+ return goog.dependencies_.nameToPath[rule];
+ } else {
+ return null;
+ }
+ };
+
+ goog.findBasePath_();
+
+ // Allow projects to manage the deps files themselves.
+ if (!goog.global.CLOSURE_NO_DEPS) {
+ goog.importScript_(goog.basePath + 'deps.js');
+ }
+}
+
+
+/**
+ * @param {function(?):?|string} moduleDef The module definition.
+ */
+goog.loadModule = function(moduleDef) {
+ // NOTE: we allow function definitions to be either in the from
+ // of a string to eval (which keeps the original source intact) or
+ // in a eval forbidden environment (CSP) we allow a function definition
+ // which in its body must call {@code goog.module}, and return the exports
+ // of the module.
+ var previousState = goog.moduleLoaderState_;
+ try {
+ goog.moduleLoaderState_ = {
+ moduleName: undefined,
+ declareLegacyNamespace: false
+ };
+ var exports;
+ if (goog.isFunction(moduleDef)) {
+ exports = moduleDef.call(undefined, {});
+ } else if (goog.isString(moduleDef)) {
+ exports = goog.loadModuleFromSource_.call(undefined, moduleDef);
+ } else {
+ throw Error('Invalid module definition');
+ }
+
+ var moduleName = goog.moduleLoaderState_.moduleName;
+ if (!goog.isString(moduleName) || !moduleName) {
+ throw Error('Invalid module name \"' + moduleName + '\"');
+ }
+
+ // Don't seal legacy namespaces as they may be uses as a parent of
+ // another namespace
+ if (goog.moduleLoaderState_.declareLegacyNamespace) {
+ goog.constructNamespace_(moduleName, exports);
+ } else if (goog.SEAL_MODULE_EXPORTS && Object.seal) {
+ Object.seal(exports);
+ }
+
+ goog.loadedModules_[moduleName] = exports;
+ } finally {
+ goog.moduleLoaderState_ = previousState;
+ }
+};
+
+
+/**
+ * @private @const {function(string):?}
+ *
+ * The new type inference warns because this function has no formal
+ * parameters, but its jsdoc says that it takes one argument.
+ * (The argument is used via arguments[0], but NTI does not detect this.)
+ * @suppress {newCheckTypes}
+ */
+goog.loadModuleFromSource_ = function() {
+ // NOTE: we avoid declaring parameters or local variables here to avoid
+ // masking globals or leaking values into the module definition.
+ 'use strict';
+ var exports = {};
+ eval(arguments[0]);
+ return exports;
+};
+
+
+/**
+ * Normalize a file path by removing redundant ".." and extraneous "." file
+ * path components.
+ * @param {string} path
+ * @return {string}
+ * @private
+ */
+goog.normalizePath_ = function(path) {
+ var components = path.split('/');
+ var i = 0;
+ while (i < components.length) {
+ if (components[i] == '.') {
+ components.splice(i, 1);
+ } else if (
+ i && components[i] == '..' && components[i - 1] &&
+ components[i - 1] != '..') {
+ components.splice(--i, 2);
+ } else {
+ i++;
+ }
+ }
+ return components.join('/');
+};
+
+
+/**
+ * Loads file by synchronous XHR. Should not be used in production environments.
+ * @param {string} src Source URL.
+ * @return {?string} File contents, or null if load failed.
+ * @private
+ */
+goog.loadFileSync_ = function(src) {
+ if (goog.global.CLOSURE_LOAD_FILE_SYNC) {
+ return goog.global.CLOSURE_LOAD_FILE_SYNC(src);
+ } else {
+ try {
+ /** @type {XMLHttpRequest} */
+ var xhr = new goog.global['XMLHttpRequest']();
+ xhr.open('get', src, false);
+ xhr.send();
+ // NOTE: Successful http: requests have a status of 200, but successful
+ // file: requests may have a status of zero. Any other status, or a
+ // thrown exception (particularly in case of file: requests) indicates
+ // some sort of error, which we treat as a missing or unavailable file.
+ return xhr.status == 0 || xhr.status == 200 ? xhr.responseText : null;
+ } catch (err) {
+ // No need to rethrow or log, since errors should show up on their own.
+ return null;
+ }
+ }
+};
+
+
+/**
+ * Retrieve and execute a script that needs some sort of wrapping.
+ * @param {string} src Script source URL.
+ * @param {boolean} isModule Whether to load as a module.
+ * @param {boolean} needsTranspile Whether to transpile down to ES3.
+ * @private
+ */
+goog.retrieveAndExec_ = function(src, isModule, needsTranspile) {
+ if (!COMPILED) {
+ // The full but non-canonicalized URL for later use.
+ var originalPath = src;
+ // Canonicalize the path, removing any /./ or /../ since Chrome's debugging
+ // console doesn't auto-canonicalize XHR loads as it does <script> srcs.
+ src = goog.normalizePath_(src);
+
+ var importScript =
+ goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_;
+
+ var scriptText = goog.loadFileSync_(src);
+ if (scriptText == null) {
+ throw new Error('Load of "' + src + '" failed');
+ }
+
+ if (needsTranspile) {
+ scriptText = goog.transpile_.call(goog.global, scriptText, src);
+ }
+
+ if (isModule) {
+ scriptText = goog.wrapModule_(src, scriptText);
+ } else {
+ scriptText += '\n//# sourceURL=' + src;
+ }
+ var isOldIE = goog.IS_OLD_IE_;
+ if (isOldIE) {
+ goog.dependencies_.deferred[originalPath] = scriptText;
+ goog.queuedModules_.push(originalPath);
+ } else {
+ importScript(src, scriptText);
+ }
+ }
+};
+
+
+/**
+ * Lazily retrieves the transpiler and applies it to the source.
+ * @param {string} code JS code.
+ * @param {string} path Path to the code.
+ * @return {string} The transpiled code.
+ * @private
+ */
+goog.transpile_ = function(code, path) {
+ var jscomp = goog.global['$jscomp'];
+ if (!jscomp) {
+ goog.global['$jscomp'] = jscomp = {};
+ }
+ var transpile = jscomp.transpile;
+ if (!transpile) {
+ var transpilerPath = goog.basePath + goog.TRANSPILER;
+ var transpilerCode = goog.loadFileSync_(transpilerPath);
+ if (transpilerCode) {
+ // This must be executed synchronously, since by the time we know we
+ // need it, we're about to load and write the ES6 code synchronously,
+ // so a normal script-tag load will be too slow.
+ eval(transpilerCode + '\n//# sourceURL=' + transpilerPath);
+ // Note: transpile.js reassigns goog.global['$jscomp'] so pull it again.
+ jscomp = goog.global['$jscomp'];
+ transpile = jscomp.transpile;
+ }
+ }
+ if (!transpile) {
+ // The transpiler is an optional component. If it's not available then
+ // replace it with a pass-through function that simply logs.
+ var suffix = ' requires transpilation but no transpiler was found.';
+ transpile = jscomp.transpile = function(code, path) {
+ // TODO(user): figure out some way to get this error to show up
+ // in test results, noting that the failure may occur in many
+ // different ways, including in loadModule() before the test
+ // runner even comes up.
+ goog.logToConsole_(path + suffix);
+ return code;
+ };
+ }
+ // Note: any transpilation errors/warnings will be logged to the console.
+ return transpile(code, path);
+};
+
+
+//==============================================================================
+// Language Enhancements
+//==============================================================================
+
+
+/**
+ * This is a "fixed" version of the typeof operator. It differs from the typeof
+ * operator in such a way that null returns 'null' and arrays return 'array'.
+ * @param {?} value The value to get the type of.
+ * @return {string} The name of the type.
+ */
+goog.typeOf = function(value) {
+ var s = typeof value;
+ if (s == 'object') {
+ if (value) {
+ // Check these first, so we can avoid calling Object.prototype.toString if
+ // possible.
+ //
+ // IE improperly marshals typeof across execution contexts, but a
+ // cross-context object will still return false for "instanceof Object".
+ if (value instanceof Array) {
+ return 'array';
+ } else if (value instanceof Object) {
+ return s;
+ }
+
+ // HACK: In order to use an Object prototype method on the arbitrary
+ // value, the compiler requires the value be cast to type Object,
+ // even though the ECMA spec explicitly allows it.
+ var className = Object.prototype.toString.call(
+ /** @type {!Object} */ (value));
+ // In Firefox 3.6, attempting to access iframe window objects' length
+ // property throws an NS_ERROR_FAILURE, so we need to special-case it
+ // here.
+ if (className == '[object Window]') {
+ return 'object';
+ }
+
+ // We cannot always use constructor == Array or instanceof Array because
+ // different frames have different Array objects. In IE6, if the iframe
+ // where the array was created is destroyed, the array loses its
+ // prototype. Then dereferencing val.splice here throws an exception, so
+ // we can't use goog.isFunction. Calling typeof directly returns 'unknown'
+ // so that will work. In this case, this function will return false and
+ // most array functions will still work because the array is still
+ // array-like (supports length and []) even though it has lost its
+ // prototype.
+ // Mark Miller noticed that Object.prototype.toString
+ // allows access to the unforgeable [[Class]] property.
+ // 15.2.4.2 Object.prototype.toString ( )
+ // When the toString method is called, the following steps are taken:
+ // 1. Get the [[Class]] property of this object.
+ // 2. Compute a string value by concatenating the three strings
+ // "[object ", Result(1), and "]".
+ // 3. Return Result(2).
+ // and this behavior survives the destruction of the execution context.
+ if ((className == '[object Array]' ||
+ // In IE all non value types are wrapped as objects across window
+ // boundaries (not iframe though) so we have to do object detection
+ // for this edge case.
+ typeof value.length == 'number' &&
+ typeof value.splice != 'undefined' &&
+ typeof value.propertyIsEnumerable != 'undefined' &&
+ !value.propertyIsEnumerable('splice')
+
+ )) {
+ return 'array';
+ }
+ // HACK: There is still an array case that fails.
+ // function ArrayImpostor() {}
+ // ArrayImpostor.prototype = [];
+ // var impostor = new ArrayImpostor;
+ // this can be fixed by getting rid of the fast path
+ // (value instanceof Array) and solely relying on
+ // (value && Object.prototype.toString.vall(value) === '[object Array]')
+ // but that would require many more function calls and is not warranted
+ // unless closure code is receiving objects from untrusted sources.
+
+ // IE in cross-window calls does not correctly marshal the function type
+ // (it appears just as an object) so we cannot use just typeof val ==
+ // 'function'. However, if the object has a call property, it is a
+ // function.
+ if ((className == '[object Function]' ||
+ typeof value.call != 'undefined' &&
+ typeof value.propertyIsEnumerable != 'undefined' &&
+ !value.propertyIsEnumerable('call'))) {
+ return 'function';
+ }
+
+ } else {
+ return 'null';
+ }
+
+ } else if (s == 'function' && typeof value.call == 'undefined') {
+ // In Safari typeof nodeList returns 'function', and on Firefox typeof
+ // behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We
+ // would like to return object for those and we can detect an invalid
+ // function by making sure that the function object has a call method.
+ return 'object';
+ }
+ return s;
+};
+
+
+/**
+ * Returns true if the specified value is null.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is null.
+ */
+goog.isNull = function(val) {
+ return val === null;
+};
+
+
+/**
+ * Returns true if the specified value is defined and not null.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is defined and not null.
+ */
+goog.isDefAndNotNull = function(val) {
+ // Note that undefined == null.
+ return val != null;
+};
+
+
+/**
+ * Returns true if the specified value is an array.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is an array.
+ */
+goog.isArray = function(val) {
+ return goog.typeOf(val) == 'array';
+};
+
+
+/**
+ * Returns true if the object looks like an array. To qualify as array like
+ * the value needs to be either a NodeList or an object with a Number length
+ * property. As a special case, a function value is not array like, because its
+ * length property is fixed to correspond to the number of expected arguments.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is an array.
+ */
+goog.isArrayLike = function(val) {
+ var type = goog.typeOf(val);
+ // We do not use goog.isObject here in order to exclude function values.
+ return type == 'array' || type == 'object' && typeof val.length == 'number';
+};
+
+
+/**
+ * Returns true if the object looks like a Date. To qualify as Date-like the
+ * value needs to be an object and have a getFullYear() function.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a like a Date.
+ */
+goog.isDateLike = function(val) {
+ return goog.isObject(val) && typeof val.getFullYear == 'function';
+};
+
+
+/**
+ * Returns true if the specified value is a string.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a string.
+ */
+goog.isString = function(val) {
+ return typeof val == 'string';
+};
+
+
+/**
+ * Returns true if the specified value is a boolean.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is boolean.
+ */
+goog.isBoolean = function(val) {
+ return typeof val == 'boolean';
+};
+
+
+/**
+ * Returns true if the specified value is a number.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a number.
+ */
+goog.isNumber = function(val) {
+ return typeof val == 'number';
+};
+
+
+/**
+ * Returns true if the specified value is a function.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a function.
+ */
+goog.isFunction = function(val) {
+ return goog.typeOf(val) == 'function';
+};
+
+
+/**
+ * Returns true if the specified value is an object. This includes arrays and
+ * functions.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is an object.
+ */
+goog.isObject = function(val) {
+ var type = typeof val;
+ return type == 'object' && val != null || type == 'function';
+ // return Object(val) === val also works, but is slower, especially if val is
+ // not an object.
+};
+
+
+/**
+ * Gets a unique ID for an object. This mutates the object so that further calls
+ * with the same object as a parameter returns the same value. The unique ID is
+ * guaranteed to be unique across the current session amongst objects that are
+ * passed into {@code getUid}. There is no guarantee that the ID is unique or
+ * consistent across sessions. It is unsafe to generate unique ID for function
+ * prototypes.
+ *
+ * @param {Object} obj The object to get the unique ID for.
+ * @return {number} The unique ID for the object.
+ */
+goog.getUid = function(obj) {
+ // TODO(arv): Make the type stricter, do not accept null.
+
+ // In Opera window.hasOwnProperty exists but always returns false so we avoid
+ // using it. As a consequence the unique ID generated for BaseClass.prototype
+ // and SubClass.prototype will be the same.
+ return obj[goog.UID_PROPERTY_] ||
+ (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_);
+};
+
+
+/**
+ * Whether the given object is already assigned a unique ID.
+ *
+ * This does not modify the object.
+ *
+ * @param {!Object} obj The object to check.
+ * @return {boolean} Whether there is an assigned unique id for the object.
+ */
+goog.hasUid = function(obj) {
+ return !!obj[goog.UID_PROPERTY_];
+};
+
+
+/**
+ * Removes the unique ID from an object. This is useful if the object was
+ * previously mutated using {@code goog.getUid} in which case the mutation is
+ * undone.
+ * @param {Object} obj The object to remove the unique ID field from.
+ */
+goog.removeUid = function(obj) {
+ // TODO(arv): Make the type stricter, do not accept null.
+
+ // In IE, DOM nodes are not instances of Object and throw an exception if we
+ // try to delete. Instead we try to use removeAttribute.
+ if (obj !== null && 'removeAttribute' in obj) {
+ obj.removeAttribute(goog.UID_PROPERTY_);
+ }
+ /** @preserveTry */
+ try {
+ delete obj[goog.UID_PROPERTY_];
+ } catch (ex) {
+ }
+};
+
+
+/**
+ * Name for unique ID property. Initialized in a way to help avoid collisions
+ * with other closure JavaScript on the same page.
+ * @type {string}
+ * @private
+ */
+goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0);
+
+
+/**
+ * Counter for UID.
+ * @type {number}
+ * @private
+ */
+goog.uidCounter_ = 0;
+
+
+/**
+ * Adds a hash code field to an object. The hash code is unique for the
+ * given object.
+ * @param {Object} obj The object to get the hash code for.
+ * @return {number} The hash code for the object.
+ * @deprecated Use goog.getUid instead.
+ */
+goog.getHashCode = goog.getUid;
+
+
+/**
+ * Removes the hash code field from an object.
+ * @param {Object} obj The object to remove the field from.
+ * @deprecated Use goog.removeUid instead.
+ */
+goog.removeHashCode = goog.removeUid;
+
+
+/**
+ * Clones a value. The input may be an Object, Array, or basic type. Objects and
+ * arrays will be cloned recursively.
+ *
+ * WARNINGS:
+ * <code>goog.cloneObject</code> does not detect reference loops. Objects that
+ * refer to themselves will cause infinite recursion.
+ *
+ * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies
+ * UIDs created by <code>getUid</code> into cloned results.
+ *
+ * @param {*} obj The value to clone.
+ * @return {*} A clone of the input value.
+ * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods.
+ */
+goog.cloneObject = function(obj) {
+ var type = goog.typeOf(obj);
+ if (type == 'object' || type == 'array') {
+ if (obj.clone) {
+ return obj.clone();
+ }
+ var clone = type == 'array' ? [] : {};
+ for (var key in obj) {
+ clone[key] = goog.cloneObject(obj[key]);
+ }
+ return clone;
+ }
+
+ return obj;
+};
+
+
+/**
+ * A native implementation of goog.bind.
+ * @param {Function} fn A function to partially apply.
+ * @param {Object|undefined} selfObj Specifies the object which this should
+ * point to when the function is run.
+ * @param {...*} var_args Additional arguments that are partially applied to the
+ * function.
+ * @return {!Function} A partially-applied form of the function bind() was
+ * invoked as a method of.
+ * @private
+ * @suppress {deprecated} The compiler thinks that Function.prototype.bind is
+ * deprecated because some people have declared a pure-JS version.
+ * Only the pure-JS version is truly deprecated.
+ */
+goog.bindNative_ = function(fn, selfObj, var_args) {
+ return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments));
+};
+
+
+/**
+ * A pure-JS implementation of goog.bind.
+ * @param {Function} fn A function to partially apply.
+ * @param {Object|undefined} selfObj Specifies the object which this should
+ * point to when the function is run.
+ * @param {...*} var_args Additional arguments that are partially applied to the
+ * function.
+ * @return {!Function} A partially-applied form of the function bind() was
+ * invoked as a method of.
+ * @private
+ */
+goog.bindJs_ = function(fn, selfObj, var_args) {
+ if (!fn) {
+ throw new Error();
+ }
+
+ if (arguments.length > 2) {
+ var boundArgs = Array.prototype.slice.call(arguments, 2);
+ return function() {
+ // Prepend the bound arguments to the current arguments.
+ var newArgs = Array.prototype.slice.call(arguments);
+ Array.prototype.unshift.apply(newArgs, boundArgs);
+ return fn.apply(selfObj, newArgs);
+ };
+
+ } else {
+ return function() { return fn.apply(selfObj, arguments); };
+ }
+};
+
+
+/**
+ * Partially applies this function to a particular 'this object' and zero or
+ * more arguments. The result is a new function with some arguments of the first
+ * function pre-filled and the value of this 'pre-specified'.
+ *
+ * Remaining arguments specified at call-time are appended to the pre-specified
+ * ones.
+ *
+ * Also see: {@link #partial}.
+ *
+ * Usage:
+ * <pre>var barMethBound = goog.bind(myFunction, myObj, 'arg1', 'arg2');
+ * barMethBound('arg3', 'arg4');</pre>
+ *
+ * @param {?function(this:T, ...)} fn A function to partially apply.
+ * @param {T} selfObj Specifies the object which this should point to when the
+ * function is run.
+ * @param {...*} var_args Additional arguments that are partially applied to the
+ * function.
+ * @return {!Function} A partially-applied form of the function goog.bind() was
+ * invoked as a method of.
+ * @template T
+ * @suppress {deprecated} See above.
+ */
+goog.bind = function(fn, selfObj, var_args) {
+ // TODO(nicksantos): narrow the type signature.
+ if (Function.prototype.bind &&
+ // NOTE(nicksantos): Somebody pulled base.js into the default Chrome
+ // extension environment. This means that for Chrome extensions, they get
+ // the implementation of Function.prototype.bind that calls goog.bind
+ // instead of the native one. Even worse, we don't want to introduce a
+ // circular dependency between goog.bind and Function.prototype.bind, so
+ // we have to hack this to make sure it works correctly.
+ Function.prototype.bind.toString().indexOf('native code') != -1) {
+ goog.bind = goog.bindNative_;
+ } else {
+ goog.bind = goog.bindJs_;
+ }
+ return goog.bind.apply(null, arguments);
+};
+
+
+/**
+ * Like goog.bind(), except that a 'this object' is not required. Useful when
+ * the target function is already bound.
+ *
+ * Usage:
+ * var g = goog.partial(f, arg1, arg2);
+ * g(arg3, arg4);
+ *
+ * @param {Function} fn A function to partially apply.
+ * @param {...*} var_args Additional arguments that are partially applied to fn.
+ * @return {!Function} A partially-applied form of the function goog.partial()
+ * was invoked as a method of.
+ */
+goog.partial = function(fn, var_args) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return function() {
+ // Clone the array (with slice()) and append additional arguments
+ // to the existing arguments.
+ var newArgs = args.slice();
+ newArgs.push.apply(newArgs, arguments);
+ return fn.apply(this, newArgs);
+ };
+};
+
+
+/**
+ * Copies all the members of a source object to a target object. This method
+ * does not work on all browsers for all objects that contain keys such as
+ * toString or hasOwnProperty. Use goog.object.extend for this purpose.
+ * @param {Object} target Target.
+ * @param {Object} source Source.
+ */
+goog.mixin = function(target, source) {
+ for (var x in source) {
+ target[x] = source[x];
+ }
+
+ // For IE7 or lower, the for-in-loop does not contain any properties that are
+ // not enumerable on the prototype object (for example, isPrototypeOf from
+ // Object.prototype) but also it will not include 'replace' on objects that
+ // extend String and change 'replace' (not that it is common for anyone to
+ // extend anything except Object).
+};
+
+
+/**
+ * @return {number} An integer value representing the number of milliseconds
+ * between midnight, January 1, 1970 and the current time.
+ */
+goog.now = (goog.TRUSTED_SITE && Date.now) || (function() {
+ // Unary plus operator converts its operand to a number which in
+ // the case of
+ // a date is done by calling getTime().
+ return +new Date();
+ });
+
+
+/**
+ * Evals JavaScript in the global scope. In IE this uses execScript, other
+ * browsers use goog.global.eval. If goog.global.eval does not evaluate in the
+ * global scope (for example, in Safari), appends a script tag instead.
+ * Throws an exception if neither execScript or eval is defined.
+ * @param {string} script JavaScript string.
+ */
+goog.globalEval = function(script) {
+ if (goog.global.execScript) {
+ goog.global.execScript(script, 'JavaScript');
+ } else if (goog.global.eval) {
+ // Test to see if eval works
+ if (goog.evalWorksForGlobals_ == null) {
+ goog.global.eval('var _evalTest_ = 1;');
+ if (typeof goog.global['_evalTest_'] != 'undefined') {
+ try {
+ delete goog.global['_evalTest_'];
+ } catch (ignore) {
+ // Microsoft edge fails the deletion above in strict mode.
+ }
+ goog.evalWorksForGlobals_ = true;
+ } else {
+ goog.evalWorksForGlobals_ = false;
+ }
+ }
+
+ if (goog.evalWorksForGlobals_) {
+ goog.global.eval(script);
+ } else {
+ /** @type {Document} */
+ var doc = goog.global.document;
+ var scriptElt =
+ /** @type {!HTMLScriptElement} */ (doc.createElement('SCRIPT'));
+ scriptElt.type = 'text/javascript';
+ scriptElt.defer = false;
+ // Note(user): can't use .innerHTML since "t('<test>')" will fail and
+ // .text doesn't work in Safari 2. Therefore we append a text node.
+ scriptElt.appendChild(doc.createTextNode(script));
+ doc.body.appendChild(scriptElt);
+ doc.body.removeChild(scriptElt);
+ }
+ } else {
+ throw Error('goog.globalEval not available');
+ }
+};
+
+
+/**
+ * Indicates whether or not we can call 'eval' directly to eval code in the
+ * global scope. Set to a Boolean by the first call to goog.globalEval (which
+ * empirically tests whether eval works for globals). @see goog.globalEval
+ * @type {?boolean}
+ * @private
+ */
+goog.evalWorksForGlobals_ = null;
+
+
+/**
+ * Optional map of CSS class names to obfuscated names used with
+ * goog.getCssName().
+ * @private {!Object<string, string>|undefined}
+ * @see goog.setCssNameMapping
+ */
+goog.cssNameMapping_;
+
+
+/**
+ * Optional obfuscation style for CSS class names. Should be set to either
+ * 'BY_WHOLE' or 'BY_PART' if defined.
+ * @type {string|undefined}
+ * @private
+ * @see goog.setCssNameMapping
+ */
+goog.cssNameMappingStyle_;
+
+
+/**
+ * Handles strings that are intended to be used as CSS class names.
+ *
+ * This function works in tandem with @see goog.setCssNameMapping.
+ *
+ * Without any mapping set, the arguments are simple joined with a hyphen and
+ * passed through unaltered.
+ *
+ * When there is a mapping, there are two possible styles in which these
+ * mappings are used. In the BY_PART style, each part (i.e. in between hyphens)
+ * of the passed in css name is rewritten according to the map. In the BY_WHOLE
+ * style, the full css name is looked up in the map directly. If a rewrite is
+ * not specified by the map, the compiler will output a warning.
+ *
+ * When the mapping is passed to the compiler, it will replace calls to
+ * goog.getCssName with the strings from the mapping, e.g.
+ * var x = goog.getCssName('foo');
+ * var y = goog.getCssName(this.baseClass, 'active');
+ * becomes:
+ * var x = 'foo';
+ * var y = this.baseClass + '-active';
+ *
+ * If one argument is passed it will be processed, if two are passed only the
+ * modifier will be processed, as it is assumed the first argument was generated
+ * as a result of calling goog.getCssName.
+ *
+ * @param {string} className The class name.
+ * @param {string=} opt_modifier A modifier to be appended to the class name.
+ * @return {string} The class name or the concatenation of the class name and
+ * the modifier.
+ */
+goog.getCssName = function(className, opt_modifier) {
+ var getMapping = function(cssName) {
+ return goog.cssNameMapping_[cssName] || cssName;
+ };
+
+ var renameByParts = function(cssName) {
+ // Remap all the parts individually.
+ var parts = cssName.split('-');
+ var mapped = [];
+ for (var i = 0; i < parts.length; i++) {
+ mapped.push(getMapping(parts[i]));
+ }
+ return mapped.join('-');
+ };
+
+ var rename;
+ if (goog.cssNameMapping_) {
+ rename =
+ goog.cssNameMappingStyle_ == 'BY_WHOLE' ? getMapping : renameByParts;
+ } else {
+ rename = function(a) { return a; };
+ }
+
+ if (opt_modifier) {
+ return className + '-' + rename(opt_modifier);
+ } else {
+ return rename(className);
+ }
+};
+
+
+/**
+ * Sets the map to check when returning a value from goog.getCssName(). Example:
+ * <pre>
+ * goog.setCssNameMapping({
+ * "goog": "a",
+ * "disabled": "b",
+ * });
+ *
+ * var x = goog.getCssName('goog');
+ * // The following evaluates to: "a a-b".
+ * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled')
+ * </pre>
+ * When declared as a map of string literals to string literals, the JSCompiler
+ * will replace all calls to goog.getCssName() using the supplied map if the
+ * --process_closure_primitives flag is set.
+ *
+ * @param {!Object} mapping A map of strings to strings where keys are possible
+ * arguments to goog.getCssName() and values are the corresponding values
+ * that should be returned.
+ * @param {string=} opt_style The style of css name mapping. There are two valid
+ * options: 'BY_PART', and 'BY_WHOLE'.
+ * @see goog.getCssName for a description.
+ */
+goog.setCssNameMapping = function(mapping, opt_style) {
+ goog.cssNameMapping_ = mapping;
+ goog.cssNameMappingStyle_ = opt_style;
+};
+
+
+/**
+ * To use CSS renaming in compiled mode, one of the input files should have a
+ * call to goog.setCssNameMapping() with an object literal that the JSCompiler
+ * can extract and use to replace all calls to goog.getCssName(). In uncompiled
+ * mode, JavaScript code should be loaded before this base.js file that declares
+ * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is
+ * to ensure that the mapping is loaded before any calls to goog.getCssName()
+ * are made in uncompiled mode.
+ *
+ * A hook for overriding the CSS name mapping.
+ * @type {!Object<string, string>|undefined}
+ */
+goog.global.CLOSURE_CSS_NAME_MAPPING;
+
+
+if (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) {
+ // This does not call goog.setCssNameMapping() because the JSCompiler
+ // requires that goog.setCssNameMapping() be called with an object literal.
+ goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING;
+}
+
+
+/**
+ * Gets a localized message.
+ *
+ * This function is a compiler primitive. If you give the compiler a localized
+ * message bundle, it will replace the string at compile-time with a localized
+ * version, and expand goog.getMsg call to a concatenated string.
+ *
+ * Messages must be initialized in the form:
+ * <code>
+ * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'});
+ * </code>
+ *
+ * This function produces a string which should be treated as plain text. Use
+ * {@link goog.html.SafeHtmlFormatter} in conjunction with goog.getMsg to
+ * produce SafeHtml.
+ *
+ * @param {string} str Translatable string, places holders in the form {$foo}.
+ * @param {Object<string, string>=} opt_values Maps place holder name to value.
+ * @return {string} message with placeholders filled.
+ */
+goog.getMsg = function(str, opt_values) {
+ if (opt_values) {
+ str = str.replace(/\{\$([^}]+)}/g, function(match, key) {
+ return (opt_values != null && key in opt_values) ? opt_values[key] :
+ match;
+ });
+ }
+ return str;
+};
+
+
+/**
+ * Gets a localized message. If the message does not have a translation, gives a
+ * fallback message.
+ *
+ * This is useful when introducing a new message that has not yet been
+ * translated into all languages.
+ *
+ * This function is a compiler primitive. Must be used in the form:
+ * <code>var x = goog.getMsgWithFallback(MSG_A, MSG_B);</code>
+ * where MSG_A and MSG_B were initialized with goog.getMsg.
+ *
+ * @param {string} a The preferred message.
+ * @param {string} b The fallback message.
+ * @return {string} The best translated message.
+ */
+goog.getMsgWithFallback = function(a, b) {
+ return a;
+};
+
+
+/**
+ * Exposes an unobfuscated global namespace path for the given object.
+ * Note that fields of the exported object *will* be obfuscated, unless they are
+ * exported in turn via this function or goog.exportProperty.
+ *
+ * Also handy for making public items that are defined in anonymous closures.
+ *
+ * ex. goog.exportSymbol('public.path.Foo', Foo);
+ *
+ * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction);
+ * public.path.Foo.staticFunction();
+ *
+ * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod',
+ * Foo.prototype.myMethod);
+ * new public.path.Foo().myMethod();
+ *
+ * @param {string} publicPath Unobfuscated name to export.
+ * @param {*} object Object the name should point to.
+ * @param {Object=} opt_objectToExportTo The object to add the path to; default
+ * is goog.global.
+ */
+goog.exportSymbol = function(publicPath, object, opt_objectToExportTo) {
+ goog.exportPath_(publicPath, object, opt_objectToExportTo);
+};
+
+
+/**
+ * Exports a property unobfuscated into the object's namespace.
+ * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction);
+ * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod);
+ * @param {Object} object Object whose static property is being exported.
+ * @param {string} publicName Unobfuscated name to export.
+ * @param {*} symbol Object the name should point to.
+ */
+goog.exportProperty = function(object, publicName, symbol) {
+ object[publicName] = symbol;
+};
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * Usage:
+ * <pre>
+ * function ParentClass(a, b) { }
+ * ParentClass.prototype.foo = function(a) { };
+ *
+ * function ChildClass(a, b, c) {
+ * ChildClass.base(this, 'constructor', a, b);
+ * }
+ * goog.inherits(ChildClass, ParentClass);
+ *
+ * var child = new ChildClass('a', 'b', 'see');
+ * child.foo(); // This works.
+ * </pre>
+ *
+ * @param {!Function} childCtor Child class.
+ * @param {!Function} parentCtor Parent class.
+ */
+goog.inherits = function(childCtor, parentCtor) {
+ /** @constructor */
+ function tempCtor() {}
+ tempCtor.prototype = parentCtor.prototype;
+ childCtor.superClass_ = parentCtor.prototype;
+ childCtor.prototype = new tempCtor();
+ /** @override */
+ childCtor.prototype.constructor = childCtor;
+
+ /**
+ * Calls superclass constructor/method.
+ *
+ * This function is only available if you use goog.inherits to
+ * express inheritance relationships between classes.
+ *
+ * NOTE: This is a replacement for goog.base and for superClass_
+ * property defined in childCtor.
+ *
+ * @param {!Object} me Should always be "this".
+ * @param {string} methodName The method name to call. Calling
+ * superclass constructor can be done with the special string
+ * 'constructor'.
+ * @param {...*} var_args The arguments to pass to superclass
+ * method/constructor.
+ * @return {*} The return value of the superclass method/constructor.
+ */
+ childCtor.base = function(me, methodName, var_args) {
+ // Copying using loop to avoid deop due to passing arguments object to
+ // function. This is faster in many JS engines as of late 2014.
+ var args = new Array(arguments.length - 2);
+ for (var i = 2; i < arguments.length; i++) {
+ args[i - 2] = arguments[i];
+ }
+ return parentCtor.prototype[methodName].apply(me, args);
+ };
+};
+
+
+/**
+ * Call up to the superclass.
+ *
+ * If this is called from a constructor, then this calls the superclass
+ * constructor with arguments 1-N.
+ *
+ * If this is called from a prototype method, then you must pass the name of the
+ * method as the second argument to this function. If you do not, you will get a
+ * runtime error. This calls the superclass' method with arguments 2-N.
+ *
+ * This function only works if you use goog.inherits to express inheritance
+ * relationships between your classes.
+ *
+ * This function is a compiler primitive. At compile-time, the compiler will do
+ * macro expansion to remove a lot of the extra overhead that this function
+ * introduces. The compiler will also enforce a lot of the assumptions that this
+ * function makes, and treat it as a compiler error if you break them.
+ *
+ * @param {!Object} me Should always be "this".
+ * @param {*=} opt_methodName The method name if calling a super method.
+ * @param {...*} var_args The rest of the arguments.
+ * @return {*} The return value of the superclass method.
+ * @suppress {es5Strict} This method can not be used in strict mode, but
+ * all Closure Library consumers must depend on this file.
+ */
+goog.base = function(me, opt_methodName, var_args) {
+ var caller = arguments.callee.caller;
+
+ if (goog.STRICT_MODE_COMPATIBLE || (goog.DEBUG && !caller)) {
+ throw Error(
+ 'arguments.caller not defined. goog.base() cannot be used ' +
+ 'with strict mode code. See ' +
+ 'http://www.ecma-international.org/ecma-262/5.1/#sec-C');
+ }
+
+ if (caller.superClass_) {
+ // Copying using loop to avoid deop due to passing arguments object to
+ // function. This is faster in many JS engines as of late 2014.
+ var ctorArgs = new Array(arguments.length - 1);
+ for (var i = 1; i < arguments.length; i++) {
+ ctorArgs[i - 1] = arguments[i];
+ }
+ // This is a constructor. Call the superclass constructor.
+ return caller.superClass_.constructor.apply(me, ctorArgs);
+ }
+
+ // Copying using loop to avoid deop due to passing arguments object to
+ // function. This is faster in many JS engines as of late 2014.
+ var args = new Array(arguments.length - 2);
+ for (var i = 2; i < arguments.length; i++) {
+ args[i - 2] = arguments[i];
+ }
+ var foundCaller = false;
+ for (var ctor = me.constructor; ctor;
+ ctor = ctor.superClass_ && ctor.superClass_.constructor) {
+ if (ctor.prototype[opt_methodName] === caller) {
+ foundCaller = true;
+ } else if (foundCaller) {
+ return ctor.prototype[opt_methodName].apply(me, args);
+ }
+ }
+
+ // If we did not find the caller in the prototype chain, then one of two
+ // things happened:
+ // 1) The caller is an instance method.
+ // 2) This method was not called by the right caller.
+ if (me[opt_methodName] === caller) {
+ return me.constructor.prototype[opt_methodName].apply(me, args);
+ } else {
+ throw Error(
+ 'goog.base called from a method of one name ' +
+ 'to a method of a different name');
+ }
+};
+
+
+/**
+ * Allow for aliasing within scope functions. This function exists for
+ * uncompiled code - in compiled code the calls will be inlined and the aliases
+ * applied. In uncompiled code the function is simply run since the aliases as
+ * written are valid JavaScript.
+ *
+ *
+ * @param {function()} fn Function to call. This function can contain aliases
+ * to namespaces (e.g. "var dom = goog.dom") or classes
+ * (e.g. "var Timer = goog.Timer").
+ */
+goog.scope = function(fn) {
+ if (goog.isInModuleLoader_()) {
+ throw Error('goog.scope is not supported within a goog.module.');
+ }
+ fn.call(goog.global);
+};
+
+
+/*
+ * To support uncompiled, strict mode bundles that use eval to divide source
+ * like so:
+ * eval('someSource;//# sourceUrl sourcefile.js');
+ * We need to export the globally defined symbols "goog" and "COMPILED".
+ * Exporting "goog" breaks the compiler optimizations, so we required that
+ * be defined externally.
+ * NOTE: We don't use goog.exportSymbol here because we don't want to trigger
+ * extern generation when that compiler option is enabled.
+ */
+if (!COMPILED) {
+ goog.global['COMPILED'] = COMPILED;
+}
+
+
+//==============================================================================
+// goog.defineClass implementation
+//==============================================================================
+
+
+/**
+ * Creates a restricted form of a Closure "class":
+ * - from the compiler's perspective, the instance returned from the
+ * constructor is sealed (no new properties may be added). This enables
+ * better checks.
+ * - the compiler will rewrite this definition to a form that is optimal
+ * for type checking and optimization (initially this will be a more
+ * traditional form).
+ *
+ * @param {Function} superClass The superclass, Object or null.
+ * @param {goog.defineClass.ClassDescriptor} def
+ * An object literal describing
+ * the class. It may have the following properties:
+ * "constructor": the constructor function
+ * "statics": an object literal containing methods to add to the constructor
+ * as "static" methods or a function that will receive the constructor
+ * function as its only parameter to which static properties can
+ * be added.
+ * all other properties are added to the prototype.
+ * @return {!Function} The class constructor.
+ */
+goog.defineClass = function(superClass, def) {
+ // TODO(johnlenz): consider making the superClass an optional parameter.
+ var constructor = def.constructor;
+ var statics = def.statics;
+ // Wrap the constructor prior to setting up the prototype and static methods.
+ if (!constructor || constructor == Object.prototype.constructor) {
+ constructor = function() {
+ throw Error('cannot instantiate an interface (no constructor defined).');
+ };
+ }
+
+ var cls = goog.defineClass.createSealingConstructor_(constructor, superClass);
+ if (superClass) {
+ goog.inherits(cls, superClass);
+ }
+
+ // Remove all the properties that should not be copied to the prototype.
+ delete def.constructor;
+ delete def.statics;
+
+ goog.defineClass.applyProperties_(cls.prototype, def);
+ if (statics != null) {
+ if (statics instanceof Function) {
+ statics(cls);
+ } else {
+ goog.defineClass.applyProperties_(cls, statics);
+ }
+ }
+
+ return cls;
+};
+
+
+/**
+ * @typedef {{
+ * constructor: (!Function|undefined),
+ * statics: (Object|undefined|function(Function):void)
+ * }}
+ * @suppress {missingProvide}
+ */
+goog.defineClass.ClassDescriptor;
+
+
+/**
+ * @define {boolean} Whether the instances returned by goog.defineClass should
+ * be sealed when possible.
+ *
+ * When sealing is disabled the constructor function will not be wrapped by
+ * goog.defineClass, making it incompatible with ES6 class methods.
+ */
+goog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG);
+
+
+/**
+ * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is
+ * defined, this function will wrap the constructor in a function that seals the
+ * results of the provided constructor function.
+ *
+ * @param {!Function} ctr The constructor whose results maybe be sealed.
+ * @param {Function} superClass The superclass constructor.
+ * @return {!Function} The replacement constructor.
+ * @private
+ */
+goog.defineClass.createSealingConstructor_ = function(ctr, superClass) {
+ if (!goog.defineClass.SEAL_CLASS_INSTANCES) {
+ // Do now wrap the constructor when sealing is disabled. Angular code
+ // depends on this for injection to work properly.
+ return ctr;
+ }
+
+ // Compute whether the constructor is sealable at definition time, rather
+ // than when the instance is being constructed.
+ var superclassSealable = !goog.defineClass.isUnsealable_(superClass);
+
+ /**
+ * @this {Object}
+ * @return {?}
+ */
+ var wrappedCtr = function() {
+ // Don't seal an instance of a subclass when it calls the constructor of
+ // its super class as there is most likely still setup to do.
+ var instance = ctr.apply(this, arguments) || this;
+ instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_];
+
+ if (this.constructor === wrappedCtr && superclassSealable &&
+ Object.seal instanceof Function) {
+ Object.seal(instance);
+ }
+ return instance;
+ };
+
+ return wrappedCtr;
+};
+
+
+/**
+ * @param {Function} ctr The constructor to test.
+ * @returns {boolean} Whether the constructor has been tagged as unsealable
+ * using goog.tagUnsealableClass.
+ * @private
+ */
+goog.defineClass.isUnsealable_ = function(ctr) {
+ return ctr && ctr.prototype &&
+ ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_];
+};
+
+
+// TODO(johnlenz): share these values with the goog.object
+/**
+ * The names of the fields that are defined on Object.prototype.
+ * @type {!Array<string>}
+ * @private
+ * @const
+ */
+goog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [
+ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
+ 'toLocaleString', 'toString', 'valueOf'
+];
+
+
+// TODO(johnlenz): share this function with the goog.object
+/**
+ * @param {!Object} target The object to add properties to.
+ * @param {!Object} source The object to copy properties from.
+ * @private
+ */
+goog.defineClass.applyProperties_ = function(target, source) {
+ // TODO(johnlenz): update this to support ES5 getters/setters
+
+ var key;
+ for (key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+
+ // For IE the for-in-loop does not contain any properties that are not
+ // enumerable on the prototype object (for example isPrototypeOf from
+ // Object.prototype) and it will also not include 'replace' on objects that
+ // extend String and change 'replace' (not that it is common for anyone to
+ // extend anything except Object).
+ for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) {
+ key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i];
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+};
+
+
+/**
+ * Sealing classes breaks the older idiom of assigning properties on the
+ * prototype rather than in the constructor. As such, goog.defineClass
+ * must not seal subclasses of these old-style classes until they are fixed.
+ * Until then, this marks a class as "broken", instructing defineClass
+ * not to seal subclasses.
+ * @param {!Function} ctr The legacy constructor to tag as unsealable.
+ */
+goog.tagUnsealableClass = function(ctr) {
+ if (!COMPILED && goog.defineClass.SEAL_CLASS_INSTANCES) {
+ ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_] = true;
+ }
+};
+
+
+/**
+ * Name for unsealable tag property.
+ * @const @private {string}
+ */
+goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable';
+
+goog.provide('ol');
+
+
+/**
+ * Constants defined with the define tag cannot be changed in application
+ * code, but can be set at compile time.
+ * Some reduce the size of the build in advanced compile mode.
+ */
+
+
+/**
+ * @define {boolean} Assume touch. Default is `false`.
+ */
+ol.ASSUME_TOUCH = false;
+
+
+/**
+ * TODO: rename this to something having to do with tile grids
+ * see https://github.com/openlayers/ol3/issues/2076
+ * @define {number} Default maximum zoom for default tile grids.
+ */
+ol.DEFAULT_MAX_ZOOM = 42;
+
+
+/**
+ * @define {number} Default min zoom level for the map view. Default is `0`.
+ */
+ol.DEFAULT_MIN_ZOOM = 0;
+
+
+/**
+ * @define {number} Default maximum allowed threshold (in pixels) for
+ * reprojection triangulation. Default is `0.5`.
+ */
+ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD = 0.5;
+
+
+/**
+ * @define {number} Default tile size.
+ */
+ol.DEFAULT_TILE_SIZE = 256;
+
+
+/**
+ * @define {string} Default WMS version.
+ */
+ol.DEFAULT_WMS_VERSION = '1.3.0';
+
+
+/**
+ * @define {number} Hysteresis pixels.
+ */
+ol.DRAG_BOX_HYSTERESIS_PIXELS = 8;
+
+
+/**
+ * @define {boolean} Enable the Canvas renderer. Default is `true`. Setting
+ * this to false at compile time in advanced mode removes all code
+ * supporting the Canvas renderer from the build.
+ */
+ol.ENABLE_CANVAS = true;
+
+
+/**
+ * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is
+ * not available). Default is `true`. Setting this to false at compile time
+ * in advanced mode removes all code supporting the DOM renderer from the
+ * build.
+ */
+ol.ENABLE_DOM = true;
+
+
+/**
+ * @define {boolean} Enable rendering of ol.layer.Image based layers. Default
+ * is `true`. Setting this to false at compile time in advanced mode removes
+ * all code supporting Image layers from the build.
+ */
+ol.ENABLE_IMAGE = true;
+
+
+/**
+ * @define {boolean} Enable Closure named colors (`goog.color.names`).
+ * Enabling these colors adds about 3KB uncompressed / 1.5KB compressed to
+ * the final build size. Default is `false`. This setting has no effect
+ * with Canvas renderer, which uses its own names, whether this is true or
+ * false.
+ */
+ol.ENABLE_NAMED_COLORS = false;
+
+
+/**
+ * @define {boolean} Enable integration with the Proj4js library. Default is
+ * `true`.
+ */
+ol.ENABLE_PROJ4JS = true;
+
+
+/**
+ * @define {boolean} Enable automatic reprojection of raster sources. Default is
+ * `true`.
+ */
+ol.ENABLE_RASTER_REPROJECTION = true;
+
+
+/**
+ * @define {boolean} Enable rendering of ol.layer.Tile based layers. Default is
+ * `true`. Setting this to false at compile time in advanced mode removes
+ * all code supporting Tile layers from the build.
+ */
+ol.ENABLE_TILE = true;
+
+
+/**
+ * @define {boolean} Enable rendering of ol.layer.Vector based layers. Default
+ * is `true`. Setting this to false at compile time in advanced mode removes
+ * all code supporting Vector layers from the build.
+ */
+ol.ENABLE_VECTOR = true;
+
+
+/**
+ * @define {boolean} Enable rendering of ol.layer.VectorTile based layers.
+ * Default is `true`. Setting this to false at compile time in advanced mode
+ * removes all code supporting VectorTile layers from the build.
+ */
+ol.ENABLE_VECTOR_TILE = true;
+
+
+/**
+ * @define {boolean} Enable the WebGL renderer. Default is `true`. Setting
+ * this to false at compile time in advanced mode removes all code
+ * supporting the WebGL renderer from the build.
+ */
+ol.ENABLE_WEBGL = true;
+
+
+/**
+ * @define {number} The size in pixels of the first atlas image. Default is
+ * `256`.
+ */
+ol.INITIAL_ATLAS_SIZE = 256;
+
+
+/**
+ * @define {number} The maximum size in pixels of atlas images. Default is
+ * `-1`, meaning it is not used (and `ol.WEBGL_MAX_TEXTURE_SIZE` is
+ * used instead).
+ */
+ol.MAX_ATLAS_SIZE = -1;
+
+
+/**
+ * @define {number} Maximum mouse wheel delta.
+ */
+ol.MOUSEWHEELZOOM_MAXDELTA = 1;
+
+
+/**
+ * @define {number} Mouse wheel timeout duration.
+ */
+ol.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80;
+
+
+/**
+ * @define {number} Maximum width and/or height extent ratio that determines
+ * when the overview map should be zoomed out.
+ */
+ol.OVERVIEWMAP_MAX_RATIO = 0.75;
+
+
+/**
+ * @define {number} Minimum width and/or height extent ratio that determines
+ * when the overview map should be zoomed in.
+ */
+ol.OVERVIEWMAP_MIN_RATIO = 0.1;
+
+
+/**
+ * @define {number} Maximum number of source tiles for raster reprojection of
+ * a single tile.
+ * If too many source tiles are determined to be loaded to create a single
+ * reprojected tile the browser can become unresponsive or even crash.
+ * This can happen if the developer defines projections improperly and/or
+ * with unlimited extents.
+ * If too many tiles are required, no tiles are loaded and
+ * `ol.TileState.ERROR` state is set. Default is `100`.
+ */
+ol.RASTER_REPROJECTION_MAX_SOURCE_TILES = 100;
+
+
+/**
+ * @define {number} Maximum number of subdivision steps during raster
+ * reprojection triangulation. Prevents high memory usage and large
+ * number of proj4 calls (for certain transformations and areas).
+ * At most `2*(2^this)` triangles are created for each triangulated
+ * extent (tile/image). Default is `10`.
+ */
+ol.RASTER_REPROJECTION_MAX_SUBDIVISION = 10;
+
+
+/**
+ * @define {number} Maximum allowed size of triangle relative to world width.
+ * When transforming corners of world extent between certain projections,
+ * the resulting triangulation seems to have zero error and no subdivision
+ * is performed.
+ * If the triangle width is more than this (relative to world width; 0-1),
+ * subdivison is forced (up to `ol.RASTER_REPROJECTION_MAX_SUBDIVISION`).
+ * Default is `0.25`.
+ */
+ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH = 0.25;
+
+
+/**
+ * @define {number} Tolerance for geometry simplification in device pixels.
+ */
+ol.SIMPLIFY_TOLERANCE = 0.5;
+
+
+/**
+ * @define {number} Texture cache high water mark.
+ */
+ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024;
+
+
+/**
+ * The maximum supported WebGL texture size in pixels. If WebGL is not
+ * supported, the value is set to `undefined`.
+ * @const
+ * @type {number|undefined}
+ */
+ol.WEBGL_MAX_TEXTURE_SIZE; // value is set in `ol.has`
+
+
+/**
+ * List of supported WebGL extensions.
+ * @const
+ * @type {Array.<string>}
+ */
+ol.WEBGL_EXTENSIONS; // value is set in `ol.has`
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * Usage:
+ *
+ * function ParentClass(a, b) { }
+ * ParentClass.prototype.foo = function(a) { }
+ *
+ * function ChildClass(a, b, c) {
+ * // Call parent constructor
+ * ParentClass.call(this, a, b);
+ * }
+ * ol.inherits(ChildClass, ParentClass);
+ *
+ * var child = new ChildClass('a', 'b', 'see');
+ * child.foo(); // This works.
+ *
+ * @param {!Function} childCtor Child constructor.
+ * @param {!Function} parentCtor Parent constructor.
+ * @function
+ * @api
+ */
+ol.inherits = function(childCtor, parentCtor) {
+ childCtor.prototype = Object.create(parentCtor.prototype);
+ childCtor.prototype.constructor = childCtor;
+};
+
+
+/**
+ * A reusable function, used e.g. as a default for callbacks.
+ *
+ * @return {undefined} Nothing.
+ */
+ol.nullFunction = function() {};
+
+
+ol.global = Function('return this')();
+
+// Copyright 2009 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Provides a base class for custom Error objects such that the
+ * stack is correctly maintained.
+ *
+ * You should never need to throw goog.debug.Error(msg) directly, Error(msg) is
+ * sufficient.
+ *
+ */
+
+goog.provide('goog.debug.Error');
+
+
+
+/**
+ * Base class for custom error objects.
+ * @param {*=} opt_msg The message associated with the error.
+ * @constructor
+ * @extends {Error}
+ */
+goog.debug.Error = function(opt_msg) {
+
+ // Attempt to ensure there is a stack trace.
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, goog.debug.Error);
+ } else {
+ var stack = new Error().stack;
+ if (stack) {
+ this.stack = stack;
+ }
+ }
+
+ if (opt_msg) {
+ this.message = String(opt_msg);
+ }
+
+ /**
+ * Whether to report this error to the server. Setting this to false will
+ * cause the error reporter to not report the error back to the server,
+ * which can be useful if the client knows that the error has already been
+ * logged on the server.
+ * @type {boolean}
+ */
+ this.reportErrorToServer = true;
+};
+goog.inherits(goog.debug.Error, Error);
+
+
+/** @override */
+goog.debug.Error.prototype.name = 'CustomError';
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Definition of goog.dom.NodeType.
+ */
+
+goog.provide('goog.dom.NodeType');
+
+
+/**
+ * Constants for the nodeType attribute in the Node interface.
+ *
+ * These constants match those specified in the Node interface. These are
+ * usually present on the Node object in recent browsers, but not in older
+ * browsers (specifically, early IEs) and thus are given here.
+ *
+ * In some browsers (early IEs), these are not defined on the Node object,
+ * so they are provided here.
+ *
+ * See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247
+ * @enum {number}
+ */
+goog.dom.NodeType = {
+ ELEMENT: 1,
+ ATTRIBUTE: 2,
+ TEXT: 3,
+ CDATA_SECTION: 4,
+ ENTITY_REFERENCE: 5,
+ ENTITY: 6,
+ PROCESSING_INSTRUCTION: 7,
+ COMMENT: 8,
+ DOCUMENT: 9,
+ DOCUMENT_TYPE: 10,
+ DOCUMENT_FRAGMENT: 11,
+ NOTATION: 12
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities for string manipulation.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+/**
+ * Namespace for string utilities
+ */
+goog.provide('goog.string');
+goog.provide('goog.string.Unicode');
+
+
+/**
+ * @define {boolean} Enables HTML escaping of lowercase letter "e" which helps
+ * with detection of double-escaping as this letter is frequently used.
+ */
+goog.define('goog.string.DETECT_DOUBLE_ESCAPING', false);
+
+
+/**
+ * @define {boolean} Whether to force non-dom html unescaping.
+ */
+goog.define('goog.string.FORCE_NON_DOM_HTML_UNESCAPING', false);
+
+
+/**
+ * Common Unicode string characters.
+ * @enum {string}
+ */
+goog.string.Unicode = {
+ NBSP: '\xa0'
+};
+
+
+/**
+ * Fast prefix-checker.
+ * @param {string} str The string to check.
+ * @param {string} prefix A string to look for at the start of {@code str}.
+ * @return {boolean} True if {@code str} begins with {@code prefix}.
+ */
+goog.string.startsWith = function(str, prefix) {
+ return str.lastIndexOf(prefix, 0) == 0;
+};
+
+
+/**
+ * Fast suffix-checker.
+ * @param {string} str The string to check.
+ * @param {string} suffix A string to look for at the end of {@code str}.
+ * @return {boolean} True if {@code str} ends with {@code suffix}.
+ */
+goog.string.endsWith = function(str, suffix) {
+ var l = str.length - suffix.length;
+ return l >= 0 && str.indexOf(suffix, l) == l;
+};
+
+
+/**
+ * Case-insensitive prefix-checker.
+ * @param {string} str The string to check.
+ * @param {string} prefix A string to look for at the end of {@code str}.
+ * @return {boolean} True if {@code str} begins with {@code prefix} (ignoring
+ * case).
+ */
+goog.string.caseInsensitiveStartsWith = function(str, prefix) {
+ return goog.string.caseInsensitiveCompare(
+ prefix, str.substr(0, prefix.length)) == 0;
+};
+
+
+/**
+ * Case-insensitive suffix-checker.
+ * @param {string} str The string to check.
+ * @param {string} suffix A string to look for at the end of {@code str}.
+ * @return {boolean} True if {@code str} ends with {@code suffix} (ignoring
+ * case).
+ */
+goog.string.caseInsensitiveEndsWith = function(str, suffix) {
+ return goog.string.caseInsensitiveCompare(
+ suffix, str.substr(str.length - suffix.length, suffix.length)) ==
+ 0;
+};
+
+
+/**
+ * Case-insensitive equality checker.
+ * @param {string} str1 First string to check.
+ * @param {string} str2 Second string to check.
+ * @return {boolean} True if {@code str1} and {@code str2} are the same string,
+ * ignoring case.
+ */
+goog.string.caseInsensitiveEquals = function(str1, str2) {
+ return str1.toLowerCase() == str2.toLowerCase();
+};
+
+
+/**
+ * Does simple python-style string substitution.
+ * subs("foo%s hot%s", "bar", "dog") becomes "foobar hotdog".
+ * @param {string} str The string containing the pattern.
+ * @param {...*} var_args The items to substitute into the pattern.
+ * @return {string} A copy of {@code str} in which each occurrence of
+ * {@code %s} has been replaced an argument from {@code var_args}.
+ */
+goog.string.subs = function(str, var_args) {
+ var splitParts = str.split('%s');
+ var returnString = '';
+
+ var subsArguments = Array.prototype.slice.call(arguments, 1);
+ while (subsArguments.length &&
+ // Replace up to the last split part. We are inserting in the
+ // positions between split parts.
+ splitParts.length > 1) {
+ returnString += splitParts.shift() + subsArguments.shift();
+ }
+
+ return returnString + splitParts.join('%s'); // Join unused '%s'
+};
+
+
+/**
+ * Converts multiple whitespace chars (spaces, non-breaking-spaces, new lines
+ * and tabs) to a single space, and strips leading and trailing whitespace.
+ * @param {string} str Input string.
+ * @return {string} A copy of {@code str} with collapsed whitespace.
+ */
+goog.string.collapseWhitespace = function(str) {
+ // Since IE doesn't include non-breaking-space (0xa0) in their \s character
+ // class (as required by section 7.2 of the ECMAScript spec), we explicitly
+ // include it in the regexp to enforce consistent cross-browser behavior.
+ return str.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, '');
+};
+
+
+/**
+ * Checks if a string is empty or contains only whitespaces.
+ * @param {string} str The string to check.
+ * @return {boolean} Whether {@code str} is empty or whitespace only.
+ */
+goog.string.isEmptyOrWhitespace = function(str) {
+ // testing length == 0 first is actually slower in all browsers (about the
+ // same in Opera).
+ // Since IE doesn't include non-breaking-space (0xa0) in their \s character
+ // class (as required by section 7.2 of the ECMAScript spec), we explicitly
+ // include it in the regexp to enforce consistent cross-browser behavior.
+ return /^[\s\xa0]*$/.test(str);
+};
+
+
+/**
+ * Checks if a string is empty.
+ * @param {string} str The string to check.
+ * @return {boolean} Whether {@code str} is empty.
+ */
+goog.string.isEmptyString = function(str) {
+ return str.length == 0;
+};
+
+
+/**
+ * Checks if a string is empty or contains only whitespaces.
+ *
+ * TODO(user): Deprecate this when clients have been switched over to
+ * goog.string.isEmptyOrWhitespace.
+ *
+ * @param {string} str The string to check.
+ * @return {boolean} Whether {@code str} is empty or whitespace only.
+ */
+goog.string.isEmpty = goog.string.isEmptyOrWhitespace;
+
+
+/**
+ * Checks if a string is null, undefined, empty or contains only whitespaces.
+ * @param {*} str The string to check.
+ * @return {boolean} Whether {@code str} is null, undefined, empty, or
+ * whitespace only.
+ * @deprecated Use goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str))
+ * instead.
+ */
+goog.string.isEmptyOrWhitespaceSafe = function(str) {
+ return goog.string.isEmptyOrWhitespace(goog.string.makeSafe(str));
+};
+
+
+/**
+ * Checks if a string is null, undefined, empty or contains only whitespaces.
+ *
+ * TODO(user): Deprecate this when clients have been switched over to
+ * goog.string.isEmptyOrWhitespaceSafe.
+ *
+ * @param {*} str The string to check.
+ * @return {boolean} Whether {@code str} is null, undefined, empty, or
+ * whitespace only.
+ */
+goog.string.isEmptySafe = goog.string.isEmptyOrWhitespaceSafe;
+
+
+/**
+ * Checks if a string is all breaking whitespace.
+ * @param {string} str The string to check.
+ * @return {boolean} Whether the string is all breaking whitespace.
+ */
+goog.string.isBreakingWhitespace = function(str) {
+ return !/[^\t\n\r ]/.test(str);
+};
+
+
+/**
+ * Checks if a string contains all letters.
+ * @param {string} str string to check.
+ * @return {boolean} True if {@code str} consists entirely of letters.
+ */
+goog.string.isAlpha = function(str) {
+ return !/[^a-zA-Z]/.test(str);
+};
+
+
+/**
+ * Checks if a string contains only numbers.
+ * @param {*} str string to check. If not a string, it will be
+ * casted to one.
+ * @return {boolean} True if {@code str} is numeric.
+ */
+goog.string.isNumeric = function(str) {
+ return !/[^0-9]/.test(str);
+};
+
+
+/**
+ * Checks if a string contains only numbers or letters.
+ * @param {string} str string to check.
+ * @return {boolean} True if {@code str} is alphanumeric.
+ */
+goog.string.isAlphaNumeric = function(str) {
+ return !/[^a-zA-Z0-9]/.test(str);
+};
+
+
+/**
+ * Checks if a character is a space character.
+ * @param {string} ch Character to check.
+ * @return {boolean} True if {@code ch} is a space.
+ */
+goog.string.isSpace = function(ch) {
+ return ch == ' ';
+};
+
+
+/**
+ * Checks if a character is a valid unicode character.
+ * @param {string} ch Character to check.
+ * @return {boolean} True if {@code ch} is a valid unicode character.
+ */
+goog.string.isUnicodeChar = function(ch) {
+ return ch.length == 1 && ch >= ' ' && ch <= '~' ||
+ ch >= '\u0080' && ch <= '\uFFFD';
+};
+
+
+/**
+ * Takes a string and replaces newlines with a space. Multiple lines are
+ * replaced with a single space.
+ * @param {string} str The string from which to strip newlines.
+ * @return {string} A copy of {@code str} stripped of newlines.
+ */
+goog.string.stripNewlines = function(str) {
+ return str.replace(/(\r\n|\r|\n)+/g, ' ');
+};
+
+
+/**
+ * Replaces Windows and Mac new lines with unix style: \r or \r\n with \n.
+ * @param {string} str The string to in which to canonicalize newlines.
+ * @return {string} {@code str} A copy of {@code} with canonicalized newlines.
+ */
+goog.string.canonicalizeNewlines = function(str) {
+ return str.replace(/(\r\n|\r|\n)/g, '\n');
+};
+
+
+/**
+ * Normalizes whitespace in a string, replacing all whitespace chars with
+ * a space.
+ * @param {string} str The string in which to normalize whitespace.
+ * @return {string} A copy of {@code str} with all whitespace normalized.
+ */
+goog.string.normalizeWhitespace = function(str) {
+ return str.replace(/\xa0|\s/g, ' ');
+};
+
+
+/**
+ * Normalizes spaces in a string, replacing all consecutive spaces and tabs
+ * with a single space. Replaces non-breaking space with a space.
+ * @param {string} str The string in which to normalize spaces.
+ * @return {string} A copy of {@code str} with all consecutive spaces and tabs
+ * replaced with a single space.
+ */
+goog.string.normalizeSpaces = function(str) {
+ return str.replace(/\xa0|[ \t]+/g, ' ');
+};
+
+
+/**
+ * Removes the breaking spaces from the left and right of the string and
+ * collapses the sequences of breaking spaces in the middle into single spaces.
+ * The original and the result strings render the same way in HTML.
+ * @param {string} str A string in which to collapse spaces.
+ * @return {string} Copy of the string with normalized breaking spaces.
+ */
+goog.string.collapseBreakingSpaces = function(str) {
+ return str.replace(/[\t\r\n ]+/g, ' ')
+ .replace(/^[\t\r\n ]+|[\t\r\n ]+$/g, '');
+};
+
+
+/**
+ * Trims white spaces to the left and right of a string.
+ * @param {string} str The string to trim.
+ * @return {string} A trimmed copy of {@code str}.
+ */
+goog.string.trim =
+ (goog.TRUSTED_SITE && String.prototype.trim) ? function(str) {
+ return str.trim();
+ } : function(str) {
+ // Since IE doesn't include non-breaking-space (0xa0) in their \s
+ // character class (as required by section 7.2 of the ECMAScript spec),
+ // we explicitly include it in the regexp to enforce consistent
+ // cross-browser behavior.
+ return str.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
+ };
+
+
+/**
+ * Trims whitespaces at the left end of a string.
+ * @param {string} str The string to left trim.
+ * @return {string} A trimmed copy of {@code str}.
+ */
+goog.string.trimLeft = function(str) {
+ // Since IE doesn't include non-breaking-space (0xa0) in their \s character
+ // class (as required by section 7.2 of the ECMAScript spec), we explicitly
+ // include it in the regexp to enforce consistent cross-browser behavior.
+ return str.replace(/^[\s\xa0]+/, '');
+};
+
+
+/**
+ * Trims whitespaces at the right end of a string.
+ * @param {string} str The string to right trim.
+ * @return {string} A trimmed copy of {@code str}.
+ */
+goog.string.trimRight = function(str) {
+ // Since IE doesn't include non-breaking-space (0xa0) in their \s character
+ // class (as required by section 7.2 of the ECMAScript spec), we explicitly
+ // include it in the regexp to enforce consistent cross-browser behavior.
+ return str.replace(/[\s\xa0]+$/, '');
+};
+
+
+/**
+ * A string comparator that ignores case.
+ * -1 = str1 less than str2
+ * 0 = str1 equals str2
+ * 1 = str1 greater than str2
+ *
+ * @param {string} str1 The string to compare.
+ * @param {string} str2 The string to compare {@code str1} to.
+ * @return {number} The comparator result, as described above.
+ */
+goog.string.caseInsensitiveCompare = function(str1, str2) {
+ var test1 = String(str1).toLowerCase();
+ var test2 = String(str2).toLowerCase();
+
+ if (test1 < test2) {
+ return -1;
+ } else if (test1 == test2) {
+ return 0;
+ } else {
+ return 1;
+ }
+};
+
+
+/**
+ * Compares two strings interpreting their numeric substrings as numbers.
+ *
+ * @param {string} str1 First string.
+ * @param {string} str2 Second string.
+ * @param {!RegExp} tokenizerRegExp Splits a string into substrings of
+ * non-negative integers, non-numeric characters and optionally fractional
+ * numbers starting with a decimal point.
+ * @return {number} Negative if str1 < str2, 0 is str1 == str2, positive if
+ * str1 > str2.
+ * @private
+ */
+goog.string.numberAwareCompare_ = function(str1, str2, tokenizerRegExp) {
+ if (str1 == str2) {
+ return 0;
+ }
+ if (!str1) {
+ return -1;
+ }
+ if (!str2) {
+ return 1;
+ }
+
+ // Using match to split the entire string ahead of time turns out to be faster
+ // for most inputs than using RegExp.exec or iterating over each character.
+ var tokens1 = str1.toLowerCase().match(tokenizerRegExp);
+ var tokens2 = str2.toLowerCase().match(tokenizerRegExp);
+
+ var count = Math.min(tokens1.length, tokens2.length);
+
+ for (var i = 0; i < count; i++) {
+ var a = tokens1[i];
+ var b = tokens2[i];
+
+ // Compare pairs of tokens, returning if one token sorts before the other.
+ if (a != b) {
+ // Only if both tokens are integers is a special comparison required.
+ // Decimal numbers are sorted as strings (e.g., '.09' < '.1').
+ var num1 = parseInt(a, 10);
+ if (!isNaN(num1)) {
+ var num2 = parseInt(b, 10);
+ if (!isNaN(num2) && num1 - num2) {
+ return num1 - num2;
+ }
+ }
+ return a < b ? -1 : 1;
+ }
+ }
+
+ // If one string is a substring of the other, the shorter string sorts first.
+ if (tokens1.length != tokens2.length) {
+ return tokens1.length - tokens2.length;
+ }
+
+ // The two strings must be equivalent except for case (perfect equality is
+ // tested at the head of the function.) Revert to default ASCII string
+ // comparison to stabilize the sort.
+ return str1 < str2 ? -1 : 1;
+};
+
+
+/**
+ * String comparison function that handles non-negative integer numbers in a
+ * way humans might expect. Using this function, the string 'File 2.jpg' sorts
+ * before 'File 10.jpg', and 'Version 1.9' before 'Version 1.10'. The comparison
+ * is mostly case-insensitive, though strings that are identical except for case
+ * are sorted with the upper-case strings before lower-case.
+ *
+ * This comparison function is up to 50x slower than either the default or the
+ * case-insensitive compare. It should not be used in time-critical code, but
+ * should be fast enough to sort several hundred short strings (like filenames)
+ * with a reasonable delay.
+ *
+ * @param {string} str1 The string to compare in a numerically sensitive way.
+ * @param {string} str2 The string to compare {@code str1} to.
+ * @return {number} less than 0 if str1 < str2, 0 if str1 == str2, greater than
+ * 0 if str1 > str2.
+ */
+goog.string.intAwareCompare = function(str1, str2) {
+ return goog.string.numberAwareCompare_(str1, str2, /\d+|\D+/g);
+};
+
+
+/**
+ * String comparison function that handles non-negative integer and fractional
+ * numbers in a way humans might expect. Using this function, the string
+ * 'File 2.jpg' sorts before 'File 10.jpg', and '3.14' before '3.2'. Equivalent
+ * to {@link goog.string.intAwareCompare} apart from the way how it interprets
+ * dots.
+ *
+ * @param {string} str1 The string to compare in a numerically sensitive way.
+ * @param {string} str2 The string to compare {@code str1} to.
+ * @return {number} less than 0 if str1 < str2, 0 if str1 == str2, greater than
+ * 0 if str1 > str2.
+ */
+goog.string.floatAwareCompare = function(str1, str2) {
+ return goog.string.numberAwareCompare_(str1, str2, /\d+|\.\d+|\D+/g);
+};
+
+
+/**
+ * Alias for {@link goog.string.floatAwareCompare}.
+ *
+ * @param {string} str1
+ * @param {string} str2
+ * @return {number}
+ */
+goog.string.numerateCompare = goog.string.floatAwareCompare;
+
+
+/**
+ * URL-encodes a string
+ * @param {*} str The string to url-encode.
+ * @return {string} An encoded copy of {@code str} that is safe for urls.
+ * Note that '#', ':', and other characters used to delimit portions
+ * of URLs *will* be encoded.
+ */
+goog.string.urlEncode = function(str) {
+ return encodeURIComponent(String(str));
+};
+
+
+/**
+ * URL-decodes the string. We need to specially handle '+'s because
+ * the javascript library doesn't convert them to spaces.
+ * @param {string} str The string to url decode.
+ * @return {string} The decoded {@code str}.
+ */
+goog.string.urlDecode = function(str) {
+ return decodeURIComponent(str.replace(/\+/g, ' '));
+};
+
+
+/**
+ * Converts \n to <br>s or <br />s.
+ * @param {string} str The string in which to convert newlines.
+ * @param {boolean=} opt_xml Whether to use XML compatible tags.
+ * @return {string} A copy of {@code str} with converted newlines.
+ */
+goog.string.newLineToBr = function(str, opt_xml) {
+ return str.replace(/(\r\n|\r|\n)/g, opt_xml ? '<br />' : '<br>');
+};
+
+
+/**
+ * Escapes double quote '"' and single quote '\'' characters in addition to
+ * '&', '<', and '>' so that a string can be included in an HTML tag attribute
+ * value within double or single quotes.
+ *
+ * It should be noted that > doesn't need to be escaped for the HTML or XML to
+ * be valid, but it has been decided to escape it for consistency with other
+ * implementations.
+ *
+ * With goog.string.DETECT_DOUBLE_ESCAPING, this function escapes also the
+ * lowercase letter "e".
+ *
+ * NOTE(user):
+ * HtmlEscape is often called during the generation of large blocks of HTML.
+ * Using statics for the regular expressions and strings is an optimization
+ * that can more than half the amount of time IE spends in this function for
+ * large apps, since strings and regexes both contribute to GC allocations.
+ *
+ * Testing for the presence of a character before escaping increases the number
+ * of function calls, but actually provides a speed increase for the average
+ * case -- since the average case often doesn't require the escaping of all 4
+ * characters and indexOf() is much cheaper than replace().
+ * The worst case does suffer slightly from the additional calls, therefore the
+ * opt_isLikelyToContainHtmlChars option has been included for situations
+ * where all 4 HTML entities are very likely to be present and need escaping.
+ *
+ * Some benchmarks (times tended to fluctuate +-0.05ms):
+ * FireFox IE6
+ * (no chars / average (mix of cases) / all 4 chars)
+ * no checks 0.13 / 0.22 / 0.22 0.23 / 0.53 / 0.80
+ * indexOf 0.08 / 0.17 / 0.26 0.22 / 0.54 / 0.84
+ * indexOf + re test 0.07 / 0.17 / 0.28 0.19 / 0.50 / 0.85
+ *
+ * An additional advantage of checking if replace actually needs to be called
+ * is a reduction in the number of object allocations, so as the size of the
+ * application grows the difference between the various methods would increase.
+ *
+ * @param {string} str string to be escaped.
+ * @param {boolean=} opt_isLikelyToContainHtmlChars Don't perform a check to see
+ * if the character needs replacing - use this option if you expect each of
+ * the characters to appear often. Leave false if you expect few html
+ * characters to occur in your strings, such as if you are escaping HTML.
+ * @return {string} An escaped copy of {@code str}.
+ */
+goog.string.htmlEscape = function(str, opt_isLikelyToContainHtmlChars) {
+
+ if (opt_isLikelyToContainHtmlChars) {
+ str = str.replace(goog.string.AMP_RE_, '&amp;')
+ .replace(goog.string.LT_RE_, '&lt;')
+ .replace(goog.string.GT_RE_, '&gt;')
+ .replace(goog.string.QUOT_RE_, '&quot;')
+ .replace(goog.string.SINGLE_QUOTE_RE_, '&#39;')
+ .replace(goog.string.NULL_RE_, '&#0;');
+ if (goog.string.DETECT_DOUBLE_ESCAPING) {
+ str = str.replace(goog.string.E_RE_, '&#101;');
+ }
+ return str;
+
+ } else {
+ // quick test helps in the case when there are no chars to replace, in
+ // worst case this makes barely a difference to the time taken
+ if (!goog.string.ALL_RE_.test(str)) return str;
+
+ // str.indexOf is faster than regex.test in this case
+ if (str.indexOf('&') != -1) {
+ str = str.replace(goog.string.AMP_RE_, '&amp;');
+ }
+ if (str.indexOf('<') != -1) {
+ str = str.replace(goog.string.LT_RE_, '&lt;');
+ }
+ if (str.indexOf('>') != -1) {
+ str = str.replace(goog.string.GT_RE_, '&gt;');
+ }
+ if (str.indexOf('"') != -1) {
+ str = str.replace(goog.string.QUOT_RE_, '&quot;');
+ }
+ if (str.indexOf('\'') != -1) {
+ str = str.replace(goog.string.SINGLE_QUOTE_RE_, '&#39;');
+ }
+ if (str.indexOf('\x00') != -1) {
+ str = str.replace(goog.string.NULL_RE_, '&#0;');
+ }
+ if (goog.string.DETECT_DOUBLE_ESCAPING && str.indexOf('e') != -1) {
+ str = str.replace(goog.string.E_RE_, '&#101;');
+ }
+ return str;
+ }
+};
+
+
+/**
+ * Regular expression that matches an ampersand, for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.AMP_RE_ = /&/g;
+
+
+/**
+ * Regular expression that matches a less than sign, for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.LT_RE_ = /</g;
+
+
+/**
+ * Regular expression that matches a greater than sign, for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.GT_RE_ = />/g;
+
+
+/**
+ * Regular expression that matches a double quote, for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.QUOT_RE_ = /"/g;
+
+
+/**
+ * Regular expression that matches a single quote, for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.SINGLE_QUOTE_RE_ = /'/g;
+
+
+/**
+ * Regular expression that matches null character, for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.NULL_RE_ = /\x00/g;
+
+
+/**
+ * Regular expression that matches a lowercase letter "e", for use in escaping.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.E_RE_ = /e/g;
+
+
+/**
+ * Regular expression that matches any character that needs to be escaped.
+ * @const {!RegExp}
+ * @private
+ */
+goog.string.ALL_RE_ =
+ (goog.string.DETECT_DOUBLE_ESCAPING ? /[\x00&<>"'e]/ : /[\x00&<>"']/);
+
+
+/**
+ * Unescapes an HTML string.
+ *
+ * @param {string} str The string to unescape.
+ * @return {string} An unescaped copy of {@code str}.
+ */
+goog.string.unescapeEntities = function(str) {
+ if (goog.string.contains(str, '&')) {
+ // We are careful not to use a DOM if we do not have one or we explicitly
+ // requested non-DOM html unescaping.
+ if (!goog.string.FORCE_NON_DOM_HTML_UNESCAPING &&
+ 'document' in goog.global) {
+ return goog.string.unescapeEntitiesUsingDom_(str);
+ } else {
+ // Fall back on pure XML entities
+ return goog.string.unescapePureXmlEntities_(str);
+ }
+ }
+ return str;
+};
+
+
+/**
+ * Unescapes a HTML string using the provided document.
+ *
+ * @param {string} str The string to unescape.
+ * @param {!Document} document A document to use in escaping the string.
+ * @return {string} An unescaped copy of {@code str}.
+ */
+goog.string.unescapeEntitiesWithDocument = function(str, document) {
+ if (goog.string.contains(str, '&')) {
+ return goog.string.unescapeEntitiesUsingDom_(str, document);
+ }
+ return str;
+};
+
+
+/**
+ * Unescapes an HTML string using a DOM to resolve non-XML, non-numeric
+ * entities. This function is XSS-safe and whitespace-preserving.
+ * @private
+ * @param {string} str The string to unescape.
+ * @param {Document=} opt_document An optional document to use for creating
+ * elements. If this is not specified then the default window.document
+ * will be used.
+ * @return {string} The unescaped {@code str} string.
+ */
+goog.string.unescapeEntitiesUsingDom_ = function(str, opt_document) {
+ /** @type {!Object<string, string>} */
+ var seen = {'&amp;': '&', '&lt;': '<', '&gt;': '>', '&quot;': '"'};
+ var div;
+ if (opt_document) {
+ div = opt_document.createElement('div');
+ } else {
+ div = goog.global.document.createElement('div');
+ }
+ // Match as many valid entity characters as possible. If the actual entity
+ // happens to be shorter, it will still work as innerHTML will return the
+ // trailing characters unchanged. Since the entity characters do not include
+ // open angle bracket, there is no chance of XSS from the innerHTML use.
+ // Since no whitespace is passed to innerHTML, whitespace is preserved.
+ return str.replace(goog.string.HTML_ENTITY_PATTERN_, function(s, entity) {
+ // Check for cached entity.
+ var value = seen[s];
+ if (value) {
+ return value;
+ }
+ // Check for numeric entity.
+ if (entity.charAt(0) == '#') {
+ // Prefix with 0 so that hex entities (e.g. &#x10) parse as hex numbers.
+ var n = Number('0' + entity.substr(1));
+ if (!isNaN(n)) {
+ value = String.fromCharCode(n);
+ }
+ }
+ // Fall back to innerHTML otherwise.
+ if (!value) {
+ // Append a non-entity character to avoid a bug in Webkit that parses
+ // an invalid entity at the end of innerHTML text as the empty string.
+ div.innerHTML = s + ' ';
+ // Then remove the trailing character from the result.
+ value = div.firstChild.nodeValue.slice(0, -1);
+ }
+ // Cache and return.
+ return seen[s] = value;
+ });
+};
+
+
+/**
+ * Unescapes XML entities.
+ * @private
+ * @param {string} str The string to unescape.
+ * @return {string} An unescaped copy of {@code str}.
+ */
+goog.string.unescapePureXmlEntities_ = function(str) {
+ return str.replace(/&([^;]+);/g, function(s, entity) {
+ switch (entity) {
+ case 'amp':
+ return '&';
+ case 'lt':
+ return '<';
+ case 'gt':
+ return '>';
+ case 'quot':
+ return '"';
+ default:
+ if (entity.charAt(0) == '#') {
+ // Prefix with 0 so that hex entities (e.g. &#x10) parse as hex.
+ var n = Number('0' + entity.substr(1));
+ if (!isNaN(n)) {
+ return String.fromCharCode(n);
+ }
+ }
+ // For invalid entities we just return the entity
+ return s;
+ }
+ });
+};
+
+
+/**
+ * Regular expression that matches an HTML entity.
+ * See also HTML5: Tokenization / Tokenizing character references.
+ * @private
+ * @type {!RegExp}
+ */
+goog.string.HTML_ENTITY_PATTERN_ = /&([^;\s<&]+);?/g;
+
+
+/**
+ * Do escaping of whitespace to preserve spatial formatting. We use character
+ * entity #160 to make it safer for xml.
+ * @param {string} str The string in which to escape whitespace.
+ * @param {boolean=} opt_xml Whether to use XML compatible tags.
+ * @return {string} An escaped copy of {@code str}.
+ */
+goog.string.whitespaceEscape = function(str, opt_xml) {
+ // This doesn't use goog.string.preserveSpaces for backwards compatibility.
+ return goog.string.newLineToBr(str.replace(/ /g, ' &#160;'), opt_xml);
+};
+
+
+/**
+ * Preserve spaces that would be otherwise collapsed in HTML by replacing them
+ * with non-breaking space Unicode characters.
+ * @param {string} str The string in which to preserve whitespace.
+ * @return {string} A copy of {@code str} with preserved whitespace.
+ */
+goog.string.preserveSpaces = function(str) {
+ return str.replace(/(^|[\n ]) /g, '$1' + goog.string.Unicode.NBSP);
+};
+
+
+/**
+ * Strip quote characters around a string. The second argument is a string of
+ * characters to treat as quotes. This can be a single character or a string of
+ * multiple character and in that case each of those are treated as possible
+ * quote characters. For example:
+ *
+ * <pre>
+ * goog.string.stripQuotes('"abc"', '"`') --> 'abc'
+ * goog.string.stripQuotes('`abc`', '"`') --> 'abc'
+ * </pre>
+ *
+ * @param {string} str The string to strip.
+ * @param {string} quoteChars The quote characters to strip.
+ * @return {string} A copy of {@code str} without the quotes.
+ */
+goog.string.stripQuotes = function(str, quoteChars) {
+ var length = quoteChars.length;
+ for (var i = 0; i < length; i++) {
+ var quoteChar = length == 1 ? quoteChars : quoteChars.charAt(i);
+ if (str.charAt(0) == quoteChar && str.charAt(str.length - 1) == quoteChar) {
+ return str.substring(1, str.length - 1);
+ }
+ }
+ return str;
+};
+
+
+/**
+ * Truncates a string to a certain length and adds '...' if necessary. The
+ * length also accounts for the ellipsis, so a maximum length of 10 and a string
+ * 'Hello World!' produces 'Hello W...'.
+ * @param {string} str The string to truncate.
+ * @param {number} chars Max number of characters.
+ * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped
+ * characters from being cut off in the middle.
+ * @return {string} The truncated {@code str} string.
+ */
+goog.string.truncate = function(str, chars, opt_protectEscapedCharacters) {
+ if (opt_protectEscapedCharacters) {
+ str = goog.string.unescapeEntities(str);
+ }
+
+ if (str.length > chars) {
+ str = str.substring(0, chars - 3) + '...';
+ }
+
+ if (opt_protectEscapedCharacters) {
+ str = goog.string.htmlEscape(str);
+ }
+
+ return str;
+};
+
+
+/**
+ * Truncate a string in the middle, adding "..." if necessary,
+ * and favoring the beginning of the string.
+ * @param {string} str The string to truncate the middle of.
+ * @param {number} chars Max number of characters.
+ * @param {boolean=} opt_protectEscapedCharacters Whether to protect escaped
+ * characters from being cutoff in the middle.
+ * @param {number=} opt_trailingChars Optional number of trailing characters to
+ * leave at the end of the string, instead of truncating as close to the
+ * middle as possible.
+ * @return {string} A truncated copy of {@code str}.
+ */
+goog.string.truncateMiddle = function(
+ str, chars, opt_protectEscapedCharacters, opt_trailingChars) {
+ if (opt_protectEscapedCharacters) {
+ str = goog.string.unescapeEntities(str);
+ }
+
+ if (opt_trailingChars && str.length > chars) {
+ if (opt_trailingChars > chars) {
+ opt_trailingChars = chars;
+ }
+ var endPoint = str.length - opt_trailingChars;
+ var startPoint = chars - opt_trailingChars;
+ str = str.substring(0, startPoint) + '...' + str.substring(endPoint);
+ } else if (str.length > chars) {
+ // Favor the beginning of the string:
+ var half = Math.floor(chars / 2);
+ var endPos = str.length - half;
+ half += chars % 2;
+ str = str.substring(0, half) + '...' + str.substring(endPos);
+ }
+
+ if (opt_protectEscapedCharacters) {
+ str = goog.string.htmlEscape(str);
+ }
+
+ return str;
+};
+
+
+/**
+ * Special chars that need to be escaped for goog.string.quote.
+ * @private {!Object<string, string>}
+ */
+goog.string.specialEscapeChars_ = {
+ '\0': '\\0',
+ '\b': '\\b',
+ '\f': '\\f',
+ '\n': '\\n',
+ '\r': '\\r',
+ '\t': '\\t',
+ '\x0B': '\\x0B', // '\v' is not supported in JScript
+ '"': '\\"',
+ '\\': '\\\\',
+ // To support the use case of embedding quoted strings inside of script
+ // tags, we have to make sure HTML comments and opening/closing script tags do
+ // not appear in the resulting string. The specific strings that must be
+ // escaped are documented at:
+ // http://www.w3.org/TR/html51/semantics.html#restrictions-for-contents-of-script-elements
+ '<': '\x3c'
+};
+
+
+/**
+ * Character mappings used internally for goog.string.escapeChar.
+ * @private {!Object<string, string>}
+ */
+goog.string.jsEscapeCache_ = {
+ '\'': '\\\''
+};
+
+
+/**
+ * Encloses a string in double quotes and escapes characters so that the
+ * string is a valid JS string. The resulting string is safe to embed in
+ * `<script>` tags as "<" is escaped.
+ * @param {string} s The string to quote.
+ * @return {string} A copy of {@code s} surrounded by double quotes.
+ */
+goog.string.quote = function(s) {
+ s = String(s);
+ var sb = ['"'];
+ for (var i = 0; i < s.length; i++) {
+ var ch = s.charAt(i);
+ var cc = ch.charCodeAt(0);
+ sb[i + 1] = goog.string.specialEscapeChars_[ch] ||
+ ((cc > 31 && cc < 127) ? ch : goog.string.escapeChar(ch));
+ }
+ sb.push('"');
+ return sb.join('');
+};
+
+
+/**
+ * Takes a string and returns the escaped string for that character.
+ * @param {string} str The string to escape.
+ * @return {string} An escaped string representing {@code str}.
+ */
+goog.string.escapeString = function(str) {
+ var sb = [];
+ for (var i = 0; i < str.length; i++) {
+ sb[i] = goog.string.escapeChar(str.charAt(i));
+ }
+ return sb.join('');
+};
+
+
+/**
+ * Takes a character and returns the escaped string for that character. For
+ * example escapeChar(String.fromCharCode(15)) -> "\\x0E".
+ * @param {string} c The character to escape.
+ * @return {string} An escaped string representing {@code c}.
+ */
+goog.string.escapeChar = function(c) {
+ if (c in goog.string.jsEscapeCache_) {
+ return goog.string.jsEscapeCache_[c];
+ }
+
+ if (c in goog.string.specialEscapeChars_) {
+ return goog.string.jsEscapeCache_[c] = goog.string.specialEscapeChars_[c];
+ }
+
+ var rv = c;
+ var cc = c.charCodeAt(0);
+ if (cc > 31 && cc < 127) {
+ rv = c;
+ } else {
+ // tab is 9 but handled above
+ if (cc < 256) {
+ rv = '\\x';
+ if (cc < 16 || cc > 256) {
+ rv += '0';
+ }
+ } else {
+ rv = '\\u';
+ if (cc < 4096) { // \u1000
+ rv += '0';
+ }
+ }
+ rv += cc.toString(16).toUpperCase();
+ }
+
+ return goog.string.jsEscapeCache_[c] = rv;
+};
+
+
+/**
+ * Determines whether a string contains a substring.
+ * @param {string} str The string to search.
+ * @param {string} subString The substring to search for.
+ * @return {boolean} Whether {@code str} contains {@code subString}.
+ */
+goog.string.contains = function(str, subString) {
+ return str.indexOf(subString) != -1;
+};
+
+
+/**
+ * Determines whether a string contains a substring, ignoring case.
+ * @param {string} str The string to search.
+ * @param {string} subString The substring to search for.
+ * @return {boolean} Whether {@code str} contains {@code subString}.
+ */
+goog.string.caseInsensitiveContains = function(str, subString) {
+ return goog.string.contains(str.toLowerCase(), subString.toLowerCase());
+};
+
+
+/**
+ * Returns the non-overlapping occurrences of ss in s.
+ * If either s or ss evalutes to false, then returns zero.
+ * @param {string} s The string to look in.
+ * @param {string} ss The string to look for.
+ * @return {number} Number of occurrences of ss in s.
+ */
+goog.string.countOf = function(s, ss) {
+ return s && ss ? s.split(ss).length - 1 : 0;
+};
+
+
+/**
+ * Removes a substring of a specified length at a specific
+ * index in a string.
+ * @param {string} s The base string from which to remove.
+ * @param {number} index The index at which to remove the substring.
+ * @param {number} stringLength The length of the substring to remove.
+ * @return {string} A copy of {@code s} with the substring removed or the full
+ * string if nothing is removed or the input is invalid.
+ */
+goog.string.removeAt = function(s, index, stringLength) {
+ var resultStr = s;
+ // If the index is greater or equal to 0 then remove substring
+ if (index >= 0 && index < s.length && stringLength > 0) {
+ resultStr = s.substr(0, index) +
+ s.substr(index + stringLength, s.length - index - stringLength);
+ }
+ return resultStr;
+};
+
+
+/**
+ * Removes the first occurrence of a substring from a string.
+ * @param {string} s The base string from which to remove.
+ * @param {string} ss The string to remove.
+ * @return {string} A copy of {@code s} with {@code ss} removed or the full
+ * string if nothing is removed.
+ */
+goog.string.remove = function(s, ss) {
+ var re = new RegExp(goog.string.regExpEscape(ss), '');
+ return s.replace(re, '');
+};
+
+
+/**
+ * Removes all occurrences of a substring from a string.
+ * @param {string} s The base string from which to remove.
+ * @param {string} ss The string to remove.
+ * @return {string} A copy of {@code s} with {@code ss} removed or the full
+ * string if nothing is removed.
+ */
+goog.string.removeAll = function(s, ss) {
+ var re = new RegExp(goog.string.regExpEscape(ss), 'g');
+ return s.replace(re, '');
+};
+
+
+/**
+ * Escapes characters in the string that are not safe to use in a RegExp.
+ * @param {*} s The string to escape. If not a string, it will be casted
+ * to one.
+ * @return {string} A RegExp safe, escaped copy of {@code s}.
+ */
+goog.string.regExpEscape = function(s) {
+ return String(s)
+ .replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1')
+ .replace(/\x08/g, '\\x08');
+};
+
+
+/**
+ * Repeats a string n times.
+ * @param {string} string The string to repeat.
+ * @param {number} length The number of times to repeat.
+ * @return {string} A string containing {@code length} repetitions of
+ * {@code string}.
+ */
+goog.string.repeat = (String.prototype.repeat) ? function(string, length) {
+ // The native method is over 100 times faster than the alternative.
+ return string.repeat(length);
+} : function(string, length) {
+ return new Array(length + 1).join(string);
+};
+
+
+/**
+ * Pads number to given length and optionally rounds it to a given precision.
+ * For example:
+ * <pre>padNumber(1.25, 2, 3) -> '01.250'
+ * padNumber(1.25, 2) -> '01.25'
+ * padNumber(1.25, 2, 1) -> '01.3'
+ * padNumber(1.25, 0) -> '1.25'</pre>
+ *
+ * @param {number} num The number to pad.
+ * @param {number} length The desired length.
+ * @param {number=} opt_precision The desired precision.
+ * @return {string} {@code num} as a string with the given options.
+ */
+goog.string.padNumber = function(num, length, opt_precision) {
+ var s = goog.isDef(opt_precision) ? num.toFixed(opt_precision) : String(num);
+ var index = s.indexOf('.');
+ if (index == -1) {
+ index = s.length;
+ }
+ return goog.string.repeat('0', Math.max(0, length - index)) + s;
+};
+
+
+/**
+ * Returns a string representation of the given object, with
+ * null and undefined being returned as the empty string.
+ *
+ * @param {*} obj The object to convert.
+ * @return {string} A string representation of the {@code obj}.
+ */
+goog.string.makeSafe = function(obj) {
+ return obj == null ? '' : String(obj);
+};
+
+
+/**
+ * Concatenates string expressions. This is useful
+ * since some browsers are very inefficient when it comes to using plus to
+ * concat strings. Be careful when using null and undefined here since
+ * these will not be included in the result. If you need to represent these
+ * be sure to cast the argument to a String first.
+ * For example:
+ * <pre>buildString('a', 'b', 'c', 'd') -> 'abcd'
+ * buildString(null, undefined) -> ''
+ * </pre>
+ * @param {...*} var_args A list of strings to concatenate. If not a string,
+ * it will be casted to one.
+ * @return {string} The concatenation of {@code var_args}.
+ */
+goog.string.buildString = function(var_args) {
+ return Array.prototype.join.call(arguments, '');
+};
+
+
+/**
+ * Returns a string with at least 64-bits of randomness.
+ *
+ * Doesn't trust Javascript's random function entirely. Uses a combination of
+ * random and current timestamp, and then encodes the string in base-36 to
+ * make it shorter.
+ *
+ * @return {string} A random string, e.g. sn1s7vb4gcic.
+ */
+goog.string.getRandomString = function() {
+ var x = 2147483648;
+ return Math.floor(Math.random() * x).toString(36) +
+ Math.abs(Math.floor(Math.random() * x) ^ goog.now()).toString(36);
+};
+
+
+/**
+ * Compares two version numbers.
+ *
+ * @param {string|number} version1 Version of first item.
+ * @param {string|number} version2 Version of second item.
+ *
+ * @return {number} 1 if {@code version1} is higher.
+ * 0 if arguments are equal.
+ * -1 if {@code version2} is higher.
+ */
+goog.string.compareVersions = function(version1, version2) {
+ var order = 0;
+ // Trim leading and trailing whitespace and split the versions into
+ // subversions.
+ var v1Subs = goog.string.trim(String(version1)).split('.');
+ var v2Subs = goog.string.trim(String(version2)).split('.');
+ var subCount = Math.max(v1Subs.length, v2Subs.length);
+
+ // Iterate over the subversions, as long as they appear to be equivalent.
+ for (var subIdx = 0; order == 0 && subIdx < subCount; subIdx++) {
+ var v1Sub = v1Subs[subIdx] || '';
+ var v2Sub = v2Subs[subIdx] || '';
+
+ // Split the subversions into pairs of numbers and qualifiers (like 'b').
+ // Two different RegExp objects are needed because they are both using
+ // the 'g' flag.
+ var v1CompParser = new RegExp('(\\d*)(\\D*)', 'g');
+ var v2CompParser = new RegExp('(\\d*)(\\D*)', 'g');
+ do {
+ var v1Comp = v1CompParser.exec(v1Sub) || ['', '', ''];
+ var v2Comp = v2CompParser.exec(v2Sub) || ['', '', ''];
+ // Break if there are no more matches.
+ if (v1Comp[0].length == 0 && v2Comp[0].length == 0) {
+ break;
+ }
+
+ // Parse the numeric part of the subversion. A missing number is
+ // equivalent to 0.
+ var v1CompNum = v1Comp[1].length == 0 ? 0 : parseInt(v1Comp[1], 10);
+ var v2CompNum = v2Comp[1].length == 0 ? 0 : parseInt(v2Comp[1], 10);
+
+ // Compare the subversion components. The number has the highest
+ // precedence. Next, if the numbers are equal, a subversion without any
+ // qualifier is always higher than a subversion with any qualifier. Next,
+ // the qualifiers are compared as strings.
+ order = goog.string.compareElements_(v1CompNum, v2CompNum) ||
+ goog.string.compareElements_(
+ v1Comp[2].length == 0, v2Comp[2].length == 0) ||
+ goog.string.compareElements_(v1Comp[2], v2Comp[2]);
+ // Stop as soon as an inequality is discovered.
+ } while (order == 0);
+ }
+
+ return order;
+};
+
+
+/**
+ * Compares elements of a version number.
+ *
+ * @param {string|number|boolean} left An element from a version number.
+ * @param {string|number|boolean} right An element from a version number.
+ *
+ * @return {number} 1 if {@code left} is higher.
+ * 0 if arguments are equal.
+ * -1 if {@code right} is higher.
+ * @private
+ */
+goog.string.compareElements_ = function(left, right) {
+ if (left < right) {
+ return -1;
+ } else if (left > right) {
+ return 1;
+ }
+ return 0;
+};
+
+
+/**
+ * String hash function similar to java.lang.String.hashCode().
+ * The hash code for a string is computed as
+ * s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
+ * where s[i] is the ith character of the string and n is the length of
+ * the string. We mod the result to make it between 0 (inclusive) and 2^32
+ * (exclusive).
+ * @param {string} str A string.
+ * @return {number} Hash value for {@code str}, between 0 (inclusive) and 2^32
+ * (exclusive). The empty string returns 0.
+ */
+goog.string.hashCode = function(str) {
+ var result = 0;
+ for (var i = 0; i < str.length; ++i) {
+ // Normalize to 4 byte range, 0 ... 2^32.
+ result = (31 * result + str.charCodeAt(i)) >>> 0;
+ }
+ return result;
+};
+
+
+/**
+ * The most recent unique ID. |0 is equivalent to Math.floor in this case.
+ * @type {number}
+ * @private
+ */
+goog.string.uniqueStringCounter_ = Math.random() * 0x80000000 | 0;
+
+
+/**
+ * Generates and returns a string which is unique in the current document.
+ * This is useful, for example, to create unique IDs for DOM elements.
+ * @return {string} A unique id.
+ */
+goog.string.createUniqueString = function() {
+ return 'goog_' + goog.string.uniqueStringCounter_++;
+};
+
+
+/**
+ * Converts the supplied string to a number, which may be Infinity or NaN.
+ * This function strips whitespace: (toNumber(' 123') === 123)
+ * This function accepts scientific notation: (toNumber('1e1') === 10)
+ *
+ * This is better than Javascript's built-in conversions because, sadly:
+ * (Number(' ') === 0) and (parseFloat('123a') === 123)
+ *
+ * @param {string} str The string to convert.
+ * @return {number} The number the supplied string represents, or NaN.
+ */
+goog.string.toNumber = function(str) {
+ var num = Number(str);
+ if (num == 0 && goog.string.isEmptyOrWhitespace(str)) {
+ return NaN;
+ }
+ return num;
+};
+
+
+/**
+ * Returns whether the given string is lower camel case (e.g. "isFooBar").
+ *
+ * Note that this assumes the string is entirely letters.
+ * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms
+ *
+ * @param {string} str String to test.
+ * @return {boolean} Whether the string is lower camel case.
+ */
+goog.string.isLowerCamelCase = function(str) {
+ return /^[a-z]+([A-Z][a-z]*)*$/.test(str);
+};
+
+
+/**
+ * Returns whether the given string is upper camel case (e.g. "FooBarBaz").
+ *
+ * Note that this assumes the string is entirely letters.
+ * @see http://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms
+ *
+ * @param {string} str String to test.
+ * @return {boolean} Whether the string is upper camel case.
+ */
+goog.string.isUpperCamelCase = function(str) {
+ return /^([A-Z][a-z]*)+$/.test(str);
+};
+
+
+/**
+ * Converts a string from selector-case to camelCase (e.g. from
+ * "multi-part-string" to "multiPartString"), useful for converting
+ * CSS selectors and HTML dataset keys to their equivalent JS properties.
+ * @param {string} str The string in selector-case form.
+ * @return {string} The string in camelCase form.
+ */
+goog.string.toCamelCase = function(str) {
+ return String(str).replace(
+ /\-([a-z])/g, function(all, match) { return match.toUpperCase(); });
+};
+
+
+/**
+ * Converts a string from camelCase to selector-case (e.g. from
+ * "multiPartString" to "multi-part-string"), useful for converting JS
+ * style and dataset properties to equivalent CSS selectors and HTML keys.
+ * @param {string} str The string in camelCase form.
+ * @return {string} The string in selector-case form.
+ */
+goog.string.toSelectorCase = function(str) {
+ return String(str).replace(/([A-Z])/g, '-$1').toLowerCase();
+};
+
+
+/**
+ * Converts a string into TitleCase. First character of the string is always
+ * capitalized in addition to the first letter of every subsequent word.
+ * Words are delimited by one or more whitespaces by default. Custom delimiters
+ * can optionally be specified to replace the default, which doesn't preserve
+ * whitespace delimiters and instead must be explicitly included if needed.
+ *
+ * Default delimiter => " ":
+ * goog.string.toTitleCase('oneTwoThree') => 'OneTwoThree'
+ * goog.string.toTitleCase('one two three') => 'One Two Three'
+ * goog.string.toTitleCase(' one two ') => ' One Two '
+ * goog.string.toTitleCase('one_two_three') => 'One_two_three'
+ * goog.string.toTitleCase('one-two-three') => 'One-two-three'
+ *
+ * Custom delimiter => "_-.":
+ * goog.string.toTitleCase('oneTwoThree', '_-.') => 'OneTwoThree'
+ * goog.string.toTitleCase('one two three', '_-.') => 'One two three'
+ * goog.string.toTitleCase(' one two ', '_-.') => ' one two '
+ * goog.string.toTitleCase('one_two_three', '_-.') => 'One_Two_Three'
+ * goog.string.toTitleCase('one-two-three', '_-.') => 'One-Two-Three'
+ * goog.string.toTitleCase('one...two...three', '_-.') => 'One...Two...Three'
+ * goog.string.toTitleCase('one. two. three', '_-.') => 'One. two. three'
+ * goog.string.toTitleCase('one-two.three', '_-.') => 'One-Two.Three'
+ *
+ * @param {string} str String value in camelCase form.
+ * @param {string=} opt_delimiters Custom delimiter character set used to
+ * distinguish words in the string value. Each character represents a
+ * single delimiter. When provided, default whitespace delimiter is
+ * overridden and must be explicitly included if needed.
+ * @return {string} String value in TitleCase form.
+ */
+goog.string.toTitleCase = function(str, opt_delimiters) {
+ var delimiters = goog.isString(opt_delimiters) ?
+ goog.string.regExpEscape(opt_delimiters) :
+ '\\s';
+
+ // For IE8, we need to prevent using an empty character set. Otherwise,
+ // incorrect matching will occur.
+ delimiters = delimiters ? '|[' + delimiters + ']+' : '';
+
+ var regexp = new RegExp('(^' + delimiters + ')([a-z])', 'g');
+ return str.replace(
+ regexp, function(all, p1, p2) { return p1 + p2.toUpperCase(); });
+};
+
+
+/**
+ * Capitalizes a string, i.e. converts the first letter to uppercase
+ * and all other letters to lowercase, e.g.:
+ *
+ * goog.string.capitalize('one') => 'One'
+ * goog.string.capitalize('ONE') => 'One'
+ * goog.string.capitalize('one two') => 'One two'
+ *
+ * Note that this function does not trim initial whitespace.
+ *
+ * @param {string} str String value to capitalize.
+ * @return {string} String value with first letter in uppercase.
+ */
+goog.string.capitalize = function(str) {
+ return String(str.charAt(0)).toUpperCase() +
+ String(str.substr(1)).toLowerCase();
+};
+
+
+/**
+ * Parse a string in decimal or hexidecimal ('0xFFFF') form.
+ *
+ * To parse a particular radix, please use parseInt(string, radix) directly. See
+ * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt
+ *
+ * This is a wrapper for the built-in parseInt function that will only parse
+ * numbers as base 10 or base 16. Some JS implementations assume strings
+ * starting with "0" are intended to be octal. ES3 allowed but discouraged
+ * this behavior. ES5 forbids it. This function emulates the ES5 behavior.
+ *
+ * For more information, see Mozilla JS Reference: http://goo.gl/8RiFj
+ *
+ * @param {string|number|null|undefined} value The value to be parsed.
+ * @return {number} The number, parsed. If the string failed to parse, this
+ * will be NaN.
+ */
+goog.string.parseInt = function(value) {
+ // Force finite numbers to strings.
+ if (isFinite(value)) {
+ value = String(value);
+ }
+
+ if (goog.isString(value)) {
+ // If the string starts with '0x' or '-0x', parse as hex.
+ return /^\s*-?0x/i.test(value) ? parseInt(value, 16) : parseInt(value, 10);
+ }
+
+ return NaN;
+};
+
+
+/**
+ * Splits a string on a separator a limited number of times.
+ *
+ * This implementation is more similar to Python or Java, where the limit
+ * parameter specifies the maximum number of splits rather than truncating
+ * the number of results.
+ *
+ * See http://docs.python.org/2/library/stdtypes.html#str.split
+ * See JavaDoc: http://goo.gl/F2AsY
+ * See Mozilla reference: http://goo.gl/dZdZs
+ *
+ * @param {string} str String to split.
+ * @param {string} separator The separator.
+ * @param {number} limit The limit to the number of splits. The resulting array
+ * will have a maximum length of limit+1. Negative numbers are the same
+ * as zero.
+ * @return {!Array<string>} The string, split.
+ */
+goog.string.splitLimit = function(str, separator, limit) {
+ var parts = str.split(separator);
+ var returnVal = [];
+
+ // Only continue doing this while we haven't hit the limit and we have
+ // parts left.
+ while (limit > 0 && parts.length) {
+ returnVal.push(parts.shift());
+ limit--;
+ }
+
+ // If there are remaining parts, append them to the end.
+ if (parts.length) {
+ returnVal.push(parts.join(separator));
+ }
+
+ return returnVal;
+};
+
+
+/**
+ * Finds the characters to the right of the last instance of any separator
+ *
+ * This function is similar to goog.string.path.baseName, except it can take a
+ * list of characters to split the string on. It will return the rightmost
+ * grouping of characters to the right of any separator as a left-to-right
+ * oriented string.
+ *
+ * @see goog.string.path.baseName
+ * @param {string} str The string
+ * @param {string|!Array<string>} separators A list of separator characters
+ * @return {string} The last part of the string with respect to the separators
+ */
+goog.string.lastComponent = function(str, separators) {
+ if (!separators) {
+ return str;
+ } else if (typeof separators == 'string') {
+ separators = [separators];
+ }
+
+ var lastSeparatorIndex = -1;
+ for (var i = 0; i < separators.length; i++) {
+ if (separators[i] == '') {
+ continue;
+ }
+ var currentSeparatorIndex = str.lastIndexOf(separators[i]);
+ if (currentSeparatorIndex > lastSeparatorIndex) {
+ lastSeparatorIndex = currentSeparatorIndex;
+ }
+ }
+ if (lastSeparatorIndex == -1) {
+ return str;
+ }
+ return str.slice(lastSeparatorIndex + 1);
+};
+
+
+/**
+ * Computes the Levenshtein edit distance between two strings.
+ * @param {string} a
+ * @param {string} b
+ * @return {number} The edit distance between the two strings.
+ */
+goog.string.editDistance = function(a, b) {
+ var v0 = [];
+ var v1 = [];
+
+ if (a == b) {
+ return 0;
+ }
+
+ if (!a.length || !b.length) {
+ return Math.max(a.length, b.length);
+ }
+
+ for (var i = 0; i < b.length + 1; i++) {
+ v0[i] = i;
+ }
+
+ for (var i = 0; i < a.length; i++) {
+ v1[0] = i + 1;
+
+ for (var j = 0; j < b.length; j++) {
+ var cost = Number(a[i] != b[j]);
+ // Cost for the substring is the minimum of adding one character, removing
+ // one character, or a swap.
+ v1[j + 1] = Math.min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost);
+ }
+
+ for (var j = 0; j < v0.length; j++) {
+ v0[j] = v1[j];
+ }
+ }
+
+ return v1[b.length];
+};
+
+// Copyright 2008 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities to check the preconditions, postconditions and
+ * invariants runtime.
+ *
+ * Methods in this package should be given special treatment by the compiler
+ * for type-inference. For example, <code>goog.asserts.assert(foo)</code>
+ * will restrict <code>foo</code> to a truthy value.
+ *
+ * The compiler has an option to disable asserts. So code like:
+ * <code>
+ * var x = goog.asserts.assert(foo()); goog.asserts.assert(bar());
+ * </code>
+ * will be transformed into:
+ * <code>
+ * var x = foo();
+ * </code>
+ * The compiler will leave in foo() (because its return value is used),
+ * but it will remove bar() because it assumes it does not have side-effects.
+ *
+ * @author agrieve@google.com (Andrew Grieve)
+ */
+
+goog.provide('goog.asserts');
+goog.provide('goog.asserts.AssertionError');
+
+goog.require('goog.debug.Error');
+goog.require('goog.dom.NodeType');
+goog.require('goog.string');
+
+
+/**
+ * @define {boolean} Whether to strip out asserts or to leave them in.
+ */
+goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG);
+
+
+
+/**
+ * Error object for failed assertions.
+ * @param {string} messagePattern The pattern that was used to form message.
+ * @param {!Array<*>} messageArgs The items to substitute into the pattern.
+ * @constructor
+ * @extends {goog.debug.Error}
+ * @final
+ */
+goog.asserts.AssertionError = function(messagePattern, messageArgs) {
+ messageArgs.unshift(messagePattern);
+ goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs));
+ // Remove the messagePattern afterwards to avoid permanently modifying the
+ // passed in array.
+ messageArgs.shift();
+
+ /**
+ * The message pattern used to format the error message. Error handlers can
+ * use this to uniquely identify the assertion.
+ * @type {string}
+ */
+ this.messagePattern = messagePattern;
+};
+goog.inherits(goog.asserts.AssertionError, goog.debug.Error);
+
+
+/** @override */
+goog.asserts.AssertionError.prototype.name = 'AssertionError';
+
+
+/**
+ * The default error handler.
+ * @param {!goog.asserts.AssertionError} e The exception to be handled.
+ */
+goog.asserts.DEFAULT_ERROR_HANDLER = function(e) {
+ throw e;
+};
+
+
+/**
+ * The handler responsible for throwing or logging assertion errors.
+ * @private {function(!goog.asserts.AssertionError)}
+ */
+goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER;
+
+
+/**
+ * Throws an exception with the given message and "Assertion failed" prefixed
+ * onto it.
+ * @param {string} defaultMessage The message to use if givenMessage is empty.
+ * @param {Array<*>} defaultArgs The substitution arguments for defaultMessage.
+ * @param {string|undefined} givenMessage Message supplied by the caller.
+ * @param {Array<*>} givenArgs The substitution arguments for givenMessage.
+ * @throws {goog.asserts.AssertionError} When the value is not a number.
+ * @private
+ */
+goog.asserts.doAssertFailure_ = function(
+ defaultMessage, defaultArgs, givenMessage, givenArgs) {
+ var message = 'Assertion failed';
+ if (givenMessage) {
+ message += ': ' + givenMessage;
+ var args = givenArgs;
+ } else if (defaultMessage) {
+ message += ': ' + defaultMessage;
+ args = defaultArgs;
+ }
+ // The '' + works around an Opera 10 bug in the unit tests. Without it,
+ // a stack trace is added to var message above. With this, a stack trace is
+ // not added until this line (it causes the extra garbage to be added after
+ // the assertion message instead of in the middle of it).
+ var e = new goog.asserts.AssertionError('' + message, args || []);
+ goog.asserts.errorHandler_(e);
+};
+
+
+/**
+ * Sets a custom error handler that can be used to customize the behavior of
+ * assertion failures, for example by turning all assertion failures into log
+ * messages.
+ * @param {function(!goog.asserts.AssertionError)} errorHandler
+ */
+goog.asserts.setErrorHandler = function(errorHandler) {
+ if (goog.asserts.ENABLE_ASSERTS) {
+ goog.asserts.errorHandler_ = errorHandler;
+ }
+};
+
+
+/**
+ * Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is
+ * true.
+ * @template T
+ * @param {T} condition The condition to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {T} The value of the condition.
+ * @throws {goog.asserts.AssertionError} When the condition evaluates to false.
+ */
+goog.asserts.assert = function(condition, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !condition) {
+ goog.asserts.doAssertFailure_(
+ '', null, opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return condition;
+};
+
+
+/**
+ * Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case
+ * when we want to add a check in the unreachable area like switch-case
+ * statement:
+ *
+ * <pre>
+ * switch(type) {
+ * case FOO: doSomething(); break;
+ * case BAR: doSomethingElse(); break;
+ * default: goog.asserts.fail('Unrecognized type: ' + type);
+ * // We have only 2 types - "default:" section is unreachable code.
+ * }
+ * </pre>
+ *
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @throws {goog.asserts.AssertionError} Failure.
+ */
+goog.asserts.fail = function(opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS) {
+ goog.asserts.errorHandler_(
+ new goog.asserts.AssertionError(
+ 'Failure' + (opt_message ? ': ' + opt_message : ''),
+ Array.prototype.slice.call(arguments, 1)));
+ }
+};
+
+
+/**
+ * Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {number} The value, guaranteed to be a number when asserts enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a number.
+ */
+goog.asserts.assertNumber = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !goog.isNumber(value)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected number but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {number} */ (value);
+};
+
+
+/**
+ * Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {string} The value, guaranteed to be a string when asserts enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a string.
+ */
+goog.asserts.assertString = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !goog.isString(value)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected string but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {string} */ (value);
+};
+
+
+/**
+ * Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Function} The value, guaranteed to be a function when asserts
+ * enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a function.
+ */
+goog.asserts.assertFunction = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !goog.isFunction(value)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected function but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {!Function} */ (value);
+};
+
+
+/**
+ * Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Object} The value, guaranteed to be a non-null object.
+ * @throws {goog.asserts.AssertionError} When the value is not an object.
+ */
+goog.asserts.assertObject = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected object but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {!Object} */ (value);
+};
+
+
+/**
+ * Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Array<?>} The value, guaranteed to be a non-null array.
+ * @throws {goog.asserts.AssertionError} When the value is not an array.
+ */
+goog.asserts.assertArray = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !goog.isArray(value)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected array but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {!Array<?>} */ (value);
+};
+
+
+/**
+ * Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {boolean} The value, guaranteed to be a boolean when asserts are
+ * enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a boolean.
+ */
+goog.asserts.assertBoolean = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !goog.isBoolean(value)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected boolean but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {boolean} */ (value);
+};
+
+
+/**
+ * Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Element} The value, likely to be a DOM Element when asserts are
+ * enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not an Element.
+ */
+goog.asserts.assertElement = function(value, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS &&
+ (!goog.isObject(value) || value.nodeType != goog.dom.NodeType.ELEMENT)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected Element but got %s: %s.', [goog.typeOf(value), value],
+ opt_message, Array.prototype.slice.call(arguments, 2));
+ }
+ return /** @type {!Element} */ (value);
+};
+
+
+/**
+ * Checks if the value is an instance of the user-defined type if
+ * goog.asserts.ENABLE_ASSERTS is true.
+ *
+ * The compiler may tighten the type returned by this function.
+ *
+ * @param {?} value The value to check.
+ * @param {function(new: T, ...)} type A user-defined constructor.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @throws {goog.asserts.AssertionError} When the value is not an instance of
+ * type.
+ * @return {T}
+ * @template T
+ */
+goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) {
+ if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) {
+ goog.asserts.doAssertFailure_(
+ 'Expected instanceof %s but got %s.',
+ [goog.asserts.getType_(type), goog.asserts.getType_(value)],
+ opt_message, Array.prototype.slice.call(arguments, 3));
+ }
+ return value;
+};
+
+
+/**
+ * Checks that no enumerable keys are present in Object.prototype. Such keys
+ * would break most code that use {@code for (var ... in ...)} loops.
+ */
+goog.asserts.assertObjectPrototypeIsIntact = function() {
+ for (var key in Object.prototype) {
+ goog.asserts.fail(key + ' should not be enumerable in Object.prototype.');
+ }
+};
+
+
+/**
+ * Returns the type of a value. If a constructor is passed, and a suitable
+ * string cannot be found, 'unknown type name' will be returned.
+ * @param {*} value A constructor, object, or primitive.
+ * @return {string} The best display name for the value, or 'unknown type name'.
+ * @private
+ */
+goog.asserts.getType_ = function(value) {
+ if (value instanceof Function) {
+ return value.displayName || value.name || 'unknown type name';
+ } else if (value instanceof Object) {
+ return value.constructor.displayName || value.constructor.name ||
+ Object.prototype.toString.call(value);
+ } else {
+ return value === null ? 'null' : typeof value;
+ }
+};
+
+goog.provide('ol.math');
+
+goog.require('goog.asserts');
+
+
+/**
+ * Takes a number and clamps it to within the provided bounds.
+ * @param {number} value The input number.
+ * @param {number} min The minimum value to return.
+ * @param {number} max The maximum value to return.
+ * @return {number} The input number if it is within bounds, or the nearest
+ * number within the bounds.
+ */
+ol.math.clamp = function(value, min, max) {
+ return Math.min(Math.max(value, min), max);
+};
+
+
+/**
+ * Return the hyperbolic cosine of a given number. The method will use the
+ * native `Math.cosh` function if it is available, otherwise the hyperbolic
+ * cosine will be calculated via the reference implementation of the Mozilla
+ * developer network.
+ *
+ * @param {number} x X.
+ * @return {number} Hyperbolic cosine of x.
+ */
+ol.math.cosh = (function() {
+ // Wrapped in a iife, to save the overhead of checking for the native
+ // implementation on every invocation.
+ var cosh;
+ if ('cosh' in Math) {
+ // The environment supports the native Math.cosh function, use it…
+ cosh = Math.cosh;
+ } else {
+ // … else, use the reference implementation of MDN:
+ cosh = function(x) {
+ var y = Math.exp(x);
+ return (y + 1 / y) / 2;
+ };
+ }
+ return cosh;
+}());
+
+
+/**
+ * @param {number} x X.
+ * @return {number} The smallest power of two greater than or equal to x.
+ */
+ol.math.roundUpToPowerOfTwo = function(x) {
+ goog.asserts.assert(0 < x, 'x should be larger than 0');
+ return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));
+};
+
+
+/**
+ * Returns the square of the closest distance between the point (x, y) and the
+ * line segment (x1, y1) to (x2, y2).
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {number} x1 X1.
+ * @param {number} y1 Y1.
+ * @param {number} x2 X2.
+ * @param {number} y2 Y2.
+ * @return {number} Squared distance.
+ */
+ol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) {
+ var dx = x2 - x1;
+ var dy = y2 - y1;
+ if (dx !== 0 || dy !== 0) {
+ var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
+ if (t > 1) {
+ x1 = x2;
+ y1 = y2;
+ } else if (t > 0) {
+ x1 += dx * t;
+ y1 += dy * t;
+ }
+ }
+ return ol.math.squaredDistance(x, y, x1, y1);
+};
+
+
+/**
+ * Returns the square of the distance between the points (x1, y1) and (x2, y2).
+ * @param {number} x1 X1.
+ * @param {number} y1 Y1.
+ * @param {number} x2 X2.
+ * @param {number} y2 Y2.
+ * @return {number} Squared distance.
+ */
+ol.math.squaredDistance = function(x1, y1, x2, y2) {
+ var dx = x2 - x1;
+ var dy = y2 - y1;
+ return dx * dx + dy * dy;
+};
+
+
+/**
+ * Solves system of linear equations using Gaussian elimination method.
+ *
+ * @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column)
+ * in row-major order.
+ * @return {Array.<number>} The resulting vector.
+ */
+ol.math.solveLinearSystem = function(mat) {
+ var n = mat.length;
+
+ if (goog.asserts.ENABLE_ASSERTS) {
+ for (var row = 0; row < n; row++) {
+ goog.asserts.assert(mat[row].length == n + 1,
+ 'every row should have correct number of columns');
+ }
+ }
+
+ for (var i = 0; i < n; i++) {
+ // Find max in the i-th column (ignoring i - 1 first rows)
+ var maxRow = i;
+ var maxEl = Math.abs(mat[i][i]);
+ for (var r = i + 1; r < n; r++) {
+ var absValue = Math.abs(mat[r][i]);
+ if (absValue > maxEl) {
+ maxEl = absValue;
+ maxRow = r;
+ }
+ }
+
+ if (maxEl === 0) {
+ return null; // matrix is singular
+ }
+
+ // Swap max row with i-th (current) row
+ var tmp = mat[maxRow];
+ mat[maxRow] = mat[i];
+ mat[i] = tmp;
+
+ // Subtract the i-th row to make all the remaining rows 0 in the i-th column
+ for (var j = i + 1; j < n; j++) {
+ var coef = -mat[j][i] / mat[i][i];
+ for (var k = i; k < n + 1; k++) {
+ if (i == k) {
+ mat[j][k] = 0;
+ } else {
+ mat[j][k] += coef * mat[i][k];
+ }
+ }
+ }
+ }
+
+ // Solve Ax=b for upper triangular matrix A (mat)
+ var x = new Array(n);
+ for (var l = n - 1; l >= 0; l--) {
+ x[l] = mat[l][n] / mat[l][l];
+ for (var m = l - 1; m >= 0; m--) {
+ mat[m][n] -= mat[m][l] * x[l];
+ }
+ }
+ return x;
+};
+
+
+/**
+ * Converts radians to to degrees.
+ *
+ * @param {number} angleInRadians Angle in radians.
+ * @return {number} Angle in degrees.
+ */
+ol.math.toDegrees = function(angleInRadians) {
+ return angleInRadians * 180 / Math.PI;
+};
+
+
+/**
+ * Converts degrees to radians.
+ *
+ * @param {number} angleInDegrees Angle in degrees.
+ * @return {number} Angle in radians.
+ */
+ol.math.toRadians = function(angleInDegrees) {
+ return angleInDegrees * Math.PI / 180;
+};
+
+/**
+ * Returns the modulo of a / b, depending on the sign of b.
+ *
+ * @param {number} a Dividend.
+ * @param {number} b Divisor.
+ * @return {number} Modulo.
+ */
+ol.math.modulo = function(a, b) {
+ var r = a % b;
+ return r * b < 0 ? r + b : r;
+};
+
+/**
+ * Calculates the linearly interpolated value of x between a and b.
+ *
+ * @param {number} a Number
+ * @param {number} b Number
+ * @param {number} x Value to be interpolated.
+ * @return {number} Interpolated value.
+ */
+ol.math.lerp = function(a, b, x) {
+ return a + x * (b - a);
+};
+
+goog.provide('ol.CenterConstraint');
+
+goog.require('ol.math');
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.CenterConstraintType} The constraint.
+ */
+ol.CenterConstraint.createExtent = function(extent) {
+ return (
+ /**
+ * @param {ol.Coordinate|undefined} center Center.
+ * @return {ol.Coordinate|undefined} Center.
+ */
+ function(center) {
+ if (center) {
+ return [
+ ol.math.clamp(center[0], extent[0], extent[2]),
+ ol.math.clamp(center[1], extent[1], extent[3])
+ ];
+ } else {
+ return undefined;
+ }
+ });
+};
+
+
+/**
+ * @param {ol.Coordinate|undefined} center Center.
+ * @return {ol.Coordinate|undefined} Center.
+ */
+ol.CenterConstraint.none = function(center) {
+ return center;
+};
+
+goog.provide('ol.Constraints');
+
+
+/**
+ * @constructor
+ * @param {ol.CenterConstraintType} centerConstraint Center constraint.
+ * @param {ol.ResolutionConstraintType} resolutionConstraint
+ * Resolution constraint.
+ * @param {ol.RotationConstraintType} rotationConstraint
+ * Rotation constraint.
+ */
+ol.Constraints = function(centerConstraint, resolutionConstraint, rotationConstraint) {
+
+ /**
+ * @type {ol.CenterConstraintType}
+ */
+ this.center = centerConstraint;
+
+ /**
+ * @type {ol.ResolutionConstraintType}
+ */
+ this.resolution = resolutionConstraint;
+
+ /**
+ * @type {ol.RotationConstraintType}
+ */
+ this.rotation = rotationConstraint;
+
+};
+
+goog.provide('ol.object');
+
+
+/**
+ * Polyfill for Object.assign(). Assigns enumerable and own properties from
+ * one or more source objects to a target object.
+ *
+ * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+ * @param {!Object} target The target object.
+ * @param {...Object} var_sources The source object(s).
+ * @return {!Object} The modified target object.
+ */
+ol.object.assign = (typeof Object.assign === 'function') ? Object.assign : function(target, var_sources) {
+ if (target === undefined || target === null) {
+ throw new TypeError('Cannot convert undefined or null to object');
+ }
+
+ var output = Object(target);
+ for (var i = 1, ii = arguments.length; i < ii; ++i) {
+ var source = arguments[i];
+ if (source !== undefined && source !== null) {
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
+ output[key] = source[key];
+ }
+ }
+ }
+ }
+ return output;
+};
+
+
+/**
+ * Removes all properties from an object.
+ * @param {Object} object The object to clear.
+ */
+ol.object.clear = function(object) {
+ for (var property in object) {
+ delete object[property];
+ }
+};
+
+
+/**
+ * Get an array of property values from an object.
+ * @param {Object<K,V>} object The object from which to get the values.
+ * @return {!Array<V>} The property values.
+ * @template K,V
+ */
+ol.object.getValues = function(object) {
+ var values = [];
+ for (var property in object) {
+ values.push(object[property]);
+ }
+ return values;
+};
+
+
+/**
+ * Determine if an object has any properties.
+ * @param {Object} object The object to check.
+ * @return {boolean} The object is empty.
+ */
+ol.object.isEmpty = function(object) {
+ var property;
+ for (property in object) {
+ return false;
+ }
+ return !property;
+};
+
+goog.provide('ol.events');
+goog.provide('ol.events.EventType');
+goog.provide('ol.events.KeyCode');
+
+goog.require('ol.object');
+
+
+/**
+ * @enum {string}
+ * @const
+ */
+ol.events.EventType = {
+ /**
+ * Generic change event.
+ * @event ol.events.Event#change
+ * @api
+ */
+ CHANGE: 'change',
+
+ CLICK: 'click',
+ DBLCLICK: 'dblclick',
+ DRAGENTER: 'dragenter',
+ DRAGOVER: 'dragover',
+ DROP: 'drop',
+ ERROR: 'error',
+ KEYDOWN: 'keydown',
+ KEYPRESS: 'keypress',
+ LOAD: 'load',
+ MOUSEDOWN: 'mousedown',
+ MOUSEMOVE: 'mousemove',
+ MOUSEOUT: 'mouseout',
+ MOUSEUP: 'mouseup',
+ MOUSEWHEEL: 'mousewheel',
+ MSPOINTERDOWN: 'mspointerdown',
+ RESIZE: 'resize',
+ TOUCHSTART: 'touchstart',
+ TOUCHMOVE: 'touchmove',
+ TOUCHEND: 'touchend',
+ WHEEL: 'wheel'
+};
+
+
+/**
+ * @enum {number}
+ * @const
+ */
+ol.events.KeyCode = {
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40
+};
+
+
+/**
+ * Property name on an event target for the listener map associated with the
+ * event target.
+ * @const {string}
+ * @private
+ */
+ol.events.LISTENER_MAP_PROP_ = 'olm_' + ((Math.random() * 1e4) | 0);
+
+
+/**
+ * @param {ol.EventsKey} listenerObj Listener object.
+ * @return {ol.EventsListenerFunctionType} Bound listener.
+ */
+ol.events.bindListener_ = function(listenerObj) {
+ var boundListener = function(evt) {
+ var listener = listenerObj.listener;
+ var bindTo = listenerObj.bindTo || listenerObj.target;
+ if (listenerObj.callOnce) {
+ ol.events.unlistenByKey(listenerObj);
+ }
+ return listener.call(bindTo, evt);
+ };
+ listenerObj.boundListener = boundListener;
+ return boundListener;
+};
+
+
+/**
+ * Finds the matching {@link ol.EventsKey} in the given listener
+ * array.
+ *
+ * @param {!Array<!ol.EventsKey>} listeners Array of listeners.
+ * @param {!Function} listener The listener function.
+ * @param {Object=} opt_this The `this` value inside the listener.
+ * @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching
+ * listener, for {@link ol.events.unlistenByKey}.
+ * @return {ol.EventsKey|undefined} The matching listener object.
+ * @private
+ */
+ol.events.findListener_ = function(listeners, listener, opt_this,
+ opt_setDeleteIndex) {
+ var listenerObj;
+ for (var i = 0, ii = listeners.length; i < ii; ++i) {
+ listenerObj = listeners[i];
+ if (listenerObj.listener === listener &&
+ listenerObj.bindTo === opt_this) {
+ if (opt_setDeleteIndex) {
+ listenerObj.deleteIndex = i;
+ }
+ return listenerObj;
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @param {ol.EventTargetLike} target Target.
+ * @param {string} type Type.
+ * @return {Array.<ol.EventsKey>|undefined} Listeners.
+ */
+ol.events.getListeners = function(target, type) {
+ var listenerMap = target[ol.events.LISTENER_MAP_PROP_];
+ return listenerMap ? listenerMap[type] : undefined;
+};
+
+
+/**
+ * Get the lookup of listeners. If one does not exist on the target, it is
+ * created.
+ * @param {ol.EventTargetLike} target Target.
+ * @return {!Object.<string, Array.<ol.EventsKey>>} Map of
+ * listeners by event type.
+ * @private
+ */
+ol.events.getListenerMap_ = function(target) {
+ var listenerMap = target[ol.events.LISTENER_MAP_PROP_];
+ if (!listenerMap) {
+ listenerMap = target[ol.events.LISTENER_MAP_PROP_] = {};
+ }
+ return listenerMap;
+};
+
+
+/**
+ * Clean up all listener objects of the given type. All properties on the
+ * listener objects will be removed, and if no listeners remain in the listener
+ * map, it will be removed from the target.
+ * @param {ol.EventTargetLike} target Target.
+ * @param {string} type Type.
+ * @private
+ */
+ol.events.removeListeners_ = function(target, type) {
+ var listeners = ol.events.getListeners(target, type);
+ if (listeners) {
+ for (var i = 0, ii = listeners.length; i < ii; ++i) {
+ target.removeEventListener(type, listeners[i].boundListener);
+ ol.object.clear(listeners[i]);
+ }
+ listeners.length = 0;
+ var listenerMap = target[ol.events.LISTENER_MAP_PROP_];
+ if (listenerMap) {
+ delete listenerMap[type];
+ if (Object.keys(listenerMap).length === 0) {
+ delete target[ol.events.LISTENER_MAP_PROP_];
+ }
+ }
+ }
+};
+
+
+/**
+ * Registers an event listener on an event target. Inspired by
+ * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
+ *
+ * This function efficiently binds a `listener` to a `this` object, and returns
+ * a key for use with {@link ol.events.unlistenByKey}.
+ *
+ * @param {ol.EventTargetLike} target Event target.
+ * @param {string} type Event type.
+ * @param {ol.EventsListenerFunctionType} listener Listener.
+ * @param {Object=} opt_this Object referenced by the `this` keyword in the
+ * listener. Default is the `target`.
+ * @param {boolean=} opt_once If true, add the listener as one-off listener.
+ * @return {ol.EventsKey} Unique key for the listener.
+ */
+ol.events.listen = function(target, type, listener, opt_this, opt_once) {
+ var listenerMap = ol.events.getListenerMap_(target);
+ var listeners = listenerMap[type];
+ if (!listeners) {
+ listeners = listenerMap[type] = [];
+ }
+ var listenerObj = ol.events.findListener_(listeners, listener, opt_this,
+ false);
+ if (listenerObj) {
+ if (!opt_once) {
+ // Turn one-off listener into a permanent one.
+ listenerObj.callOnce = false;
+ }
+ } else {
+ listenerObj = /** @type {ol.EventsKey} */ ({
+ bindTo: opt_this,
+ callOnce: !!opt_once,
+ listener: listener,
+ target: target,
+ type: type
+ });
+ target.addEventListener(type, ol.events.bindListener_(listenerObj));
+ listeners.push(listenerObj);
+ }
+
+ return listenerObj;
+};
+
+
+/**
+ * Registers a one-off event listener on an event target. Inspired by
+ * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
+ *
+ * This function efficiently binds a `listener` as self-unregistering listener
+ * to a `this` object, and returns a key for use with
+ * {@link ol.events.unlistenByKey} in case the listener needs to be unregistered
+ * before it is called.
+ *
+ * When {@link ol.events.listen} is called with the same arguments after this
+ * function, the self-unregistering listener will be turned into a permanent
+ * listener.
+ *
+ * @param {ol.EventTargetLike} target Event target.
+ * @param {string} type Event type.
+ * @param {ol.EventsListenerFunctionType} listener Listener.
+ * @param {Object=} opt_this Object referenced by the `this` keyword in the
+ * listener. Default is the `target`.
+ * @return {ol.EventsKey} Key for unlistenByKey.
+ */
+ol.events.listenOnce = function(target, type, listener, opt_this) {
+ return ol.events.listen(target, type, listener, opt_this, true);
+};
+
+
+/**
+ * Unregisters an event listener on an event target. Inspired by
+ * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
+ *
+ * To return a listener, this function needs to be called with the exact same
+ * arguments that were used for a previous {@link ol.events.listen} call.
+ *
+ * @param {ol.EventTargetLike} target Event target.
+ * @param {string} type Event type.
+ * @param {ol.EventsListenerFunctionType} listener Listener.
+ * @param {Object=} opt_this Object referenced by the `this` keyword in the
+ * listener. Default is the `target`.
+ */
+ol.events.unlisten = function(target, type, listener, opt_this) {
+ var listeners = ol.events.getListeners(target, type);
+ if (listeners) {
+ var listenerObj = ol.events.findListener_(listeners, listener, opt_this,
+ true);
+ if (listenerObj) {
+ ol.events.unlistenByKey(listenerObj);
+ }
+ }
+};
+
+
+/**
+ * Unregisters event listeners on an event target. Inspired by
+ * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
+ *
+ * The argument passed to this function is the key returned from
+ * {@link ol.events.listen} or {@link ol.events.listenOnce}.
+ *
+ * @param {ol.EventsKey} key The key.
+ */
+ol.events.unlistenByKey = function(key) {
+ if (key && key.target) {
+ key.target.removeEventListener(key.type, key.boundListener);
+ var listeners = ol.events.getListeners(key.target, key.type);
+ if (listeners) {
+ var i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);
+ if (i !== -1) {
+ listeners.splice(i, 1);
+ }
+ if (listeners.length === 0) {
+ ol.events.removeListeners_(key.target, key.type);
+ }
+ }
+ ol.object.clear(key);
+ }
+};
+
+
+/**
+ * Unregisters all event listeners on an event target. Inspired by
+ * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
+ *
+ * @param {ol.EventTargetLike} target Target.
+ */
+ol.events.unlistenAll = function(target) {
+ var listenerMap = ol.events.getListenerMap_(target);
+ for (var type in listenerMap) {
+ ol.events.removeListeners_(target, type);
+ }
+};
+
+goog.provide('ol.Disposable');
+
+goog.require('ol');
+
+/**
+ * Objects that need to clean up after themselves.
+ * @constructor
+ */
+ol.Disposable = function() {};
+
+/**
+ * The object has already been disposed.
+ * @type {boolean}
+ * @private
+ */
+ol.Disposable.prototype.disposed_ = false;
+
+/**
+ * Clean up.
+ */
+ol.Disposable.prototype.dispose = function() {
+ if (!this.disposed_) {
+ this.disposed_ = true;
+ this.disposeInternal();
+ }
+};
+
+/**
+ * Extension point for disposable objects.
+ * @protected
+ */
+ol.Disposable.prototype.disposeInternal = ol.nullFunction;
+
+goog.provide('ol.events.Event');
+
+
+/**
+ * @classdesc
+ * Stripped down implementation of the W3C DOM Level 2 Event interface.
+ * @see {@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface}
+ *
+ * This implementation only provides `type` and `target` properties, and
+ * `stopPropagation` and `preventDefault` methods. It is meant as base class
+ * for higher level events defined in the library, and works with
+ * {@link ol.events.EventTarget}.
+ *
+ * @constructor
+ * @implements {oli.events.Event}
+ * @param {string} type Type.
+ * @param {Object=} opt_target Target.
+ */
+ol.events.Event = function(type, opt_target) {
+
+ /**
+ * @type {boolean}
+ */
+ this.propagationStopped;
+
+ /**
+ * The event type.
+ * @type {string}
+ * @api stable
+ */
+ this.type = type;
+
+ /**
+ * The event target.
+ * @type {Object}
+ * @api stable
+ */
+ this.target = opt_target || null;
+
+};
+
+
+/**
+ * Stop event propagation.
+ * @function
+ * @api stable
+ */
+ol.events.Event.prototype.preventDefault =
+
+/**
+ * Stop event propagation.
+ * @function
+ * @api stable
+ */
+ol.events.Event.prototype.stopPropagation = function() {
+ this.propagationStopped = true;
+};
+
+
+/**
+ * @param {Event|ol.events.Event} evt Event
+ */
+ol.events.Event.stopPropagation = function(evt) {
+ evt.stopPropagation();
+};
+
+
+/**
+ * @param {Event|ol.events.Event} evt Event
+ */
+ol.events.Event.preventDefault = function(evt) {
+ evt.preventDefault();
+};
+
+goog.provide('ol.events.EventTarget');
+
+goog.require('goog.asserts');
+goog.require('ol.Disposable');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+
+
+/**
+ * @classdesc
+ * A simplified implementation of the W3C DOM Level 2 EventTarget interface.
+ * @see {@link https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget}
+ *
+ * There are two important simplifications compared to the specification:
+ *
+ * 1. The handling of `useCapture` in `addEventListener` and
+ * `removeEventListener`. There is no real capture model.
+ * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.
+ * There is no event target hierarchy. When a listener calls
+ * `stopPropagation` or `preventDefault` on an event object, it means that no
+ * more listeners after this one will be called. Same as when the listener
+ * returns false.
+ *
+ * @constructor
+ * @extends {ol.Disposable}
+ */
+ol.events.EventTarget = function() {
+
+ ol.Disposable.call(this);
+
+ /**
+ * @private
+ * @type {!Object.<string, number>}
+ */
+ this.pendingRemovals_ = {};
+
+ /**
+ * @private
+ * @type {!Object.<string, number>}
+ */
+ this.dispatching_ = {};
+
+ /**
+ * @private
+ * @type {!Object.<string, Array.<ol.EventsListenerFunctionType>>}
+ */
+ this.listeners_ = {};
+
+};
+ol.inherits(ol.events.EventTarget, ol.Disposable);
+
+
+/**
+ * @param {string} type Type.
+ * @param {ol.EventsListenerFunctionType} listener Listener.
+ */
+ol.events.EventTarget.prototype.addEventListener = function(type, listener) {
+ var listeners = this.listeners_[type];
+ if (!listeners) {
+ listeners = this.listeners_[type] = [];
+ }
+ if (listeners.indexOf(listener) === -1) {
+ listeners.push(listener);
+ }
+};
+
+
+/**
+ * @param {{type: string,
+ * target: (EventTarget|ol.events.EventTarget|undefined)}|ol.events.Event|
+ * string} event Event or event type.
+ * @return {boolean|undefined} `false` if anyone called preventDefault on the
+ * event object or if any of the listeners returned false.
+ */
+ol.events.EventTarget.prototype.dispatchEvent = function(event) {
+ var evt = typeof event === 'string' ? new ol.events.Event(event) : event;
+ var type = evt.type;
+ evt.target = this;
+ var listeners = this.listeners_[type];
+ var propagate;
+ if (listeners) {
+ if (!(type in this.dispatching_)) {
+ this.dispatching_[type] = 0;
+ this.pendingRemovals_[type] = 0;
+ }
+ ++this.dispatching_[type];
+ for (var i = 0, ii = listeners.length; i < ii; ++i) {
+ if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
+ propagate = false;
+ break;
+ }
+ }
+ --this.dispatching_[type];
+ if (this.dispatching_[type] === 0) {
+ var pendingRemovals = this.pendingRemovals_[type];
+ delete this.pendingRemovals_[type];
+ while (pendingRemovals--) {
+ this.removeEventListener(type, ol.nullFunction);
+ }
+ delete this.dispatching_[type];
+ }
+ return propagate;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.events.EventTarget.prototype.disposeInternal = function() {
+ ol.events.unlistenAll(this);
+};
+
+
+/**
+ * Get the listeners for a specified event type. Listeners are returned in the
+ * order that they will be called in.
+ *
+ * @param {string} type Type.
+ * @return {Array.<ol.EventsListenerFunctionType>} Listeners.
+ */
+ol.events.EventTarget.prototype.getListeners = function(type) {
+ return this.listeners_[type];
+};
+
+
+/**
+ * @param {string=} opt_type Type. If not provided,
+ * `true` will be returned if this EventTarget has any listeners.
+ * @return {boolean} Has listeners.
+ */
+ol.events.EventTarget.prototype.hasListener = function(opt_type) {
+ return opt_type ?
+ opt_type in this.listeners_ :
+ Object.keys(this.listeners_).length > 0;
+};
+
+
+/**
+ * @param {string} type Type.
+ * @param {ol.EventsListenerFunctionType} listener Listener.
+ */
+ol.events.EventTarget.prototype.removeEventListener = function(type, listener) {
+ var listeners = this.listeners_[type];
+ if (listeners) {
+ var index = listeners.indexOf(listener);
+ goog.asserts.assert(index != -1, 'listener not found');
+ if (type in this.pendingRemovals_) {
+ // make listener a no-op, and remove later in #dispatchEvent()
+ listeners[index] = ol.nullFunction;
+ ++this.pendingRemovals_[type];
+ } else {
+ listeners.splice(index, 1);
+ if (listeners.length === 0) {
+ delete this.listeners_[type];
+ }
+ }
+ }
+};
+
+goog.provide('ol.Observable');
+
+goog.require('ol.events');
+goog.require('ol.events.EventTarget');
+goog.require('ol.events.EventType');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * An event target providing convenient methods for listener registration
+ * and unregistration. A generic `change` event is always available through
+ * {@link ol.Observable#changed}.
+ *
+ * @constructor
+ * @extends {ol.events.EventTarget}
+ * @fires change
+ * @struct
+ * @api stable
+ */
+ol.Observable = function() {
+
+ ol.events.EventTarget.call(this);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.revision_ = 0;
+
+};
+ol.inherits(ol.Observable, ol.events.EventTarget);
+
+
+/**
+ * Removes an event listener using the key returned by `on()` or `once()`.
+ * @param {ol.EventsKey|Array.<ol.EventsKey>} key The key returned by `on()`
+ * or `once()` (or an array of keys).
+ * @api stable
+ */
+ol.Observable.unByKey = function(key) {
+ if (Array.isArray(key)) {
+ for (var i = 0, ii = key.length; i < ii; ++i) {
+ ol.events.unlistenByKey(key[i]);
+ }
+ } else {
+ ol.events.unlistenByKey(/** @type {ol.EventsKey} */ (key));
+ }
+};
+
+
+/**
+ * Increases the revision counter and dispatches a 'change' event.
+ * @api
+ */
+ol.Observable.prototype.changed = function() {
+ ++this.revision_;
+ this.dispatchEvent(ol.events.EventType.CHANGE);
+};
+
+
+/**
+ * Triggered when the revision counter is increased.
+ * @event change
+ * @api
+ */
+
+
+/**
+ * Dispatches an event and calls all listeners listening for events
+ * of this type. The event parameter can either be a string or an
+ * Object with a `type` property.
+ *
+ * @param {{type: string,
+ * target: (EventTarget|ol.events.EventTarget|undefined)}|ol.events.Event|
+ * string} event Event object.
+ * @function
+ * @api
+ */
+ol.Observable.prototype.dispatchEvent;
+
+
+/**
+ * Get the version number for this object. Each time the object is modified,
+ * its version number will be incremented.
+ * @return {number} Revision.
+ * @api
+ */
+ol.Observable.prototype.getRevision = function() {
+ return this.revision_;
+};
+
+
+/**
+ * Listen for a certain type of event.
+ * @param {string|Array.<string>} type The event type or array of event types.
+ * @param {function(?): ?} listener The listener function.
+ * @param {Object=} opt_this The object to use as `this` in `listener`.
+ * @return {ol.EventsKey|Array.<ol.EventsKey>} Unique key for the listener. If
+ * called with an array of event types as the first argument, the return
+ * will be an array of keys.
+ * @api stable
+ */
+ol.Observable.prototype.on = function(type, listener, opt_this) {
+ if (Array.isArray(type)) {
+ var len = type.length;
+ var keys = new Array(len);
+ for (var i = 0; i < len; ++i) {
+ keys[i] = ol.events.listen(this, type[i], listener, opt_this);
+ }
+ return keys;
+ } else {
+ return ol.events.listen(
+ this, /** @type {string} */ (type), listener, opt_this);
+ }
+};
+
+
+/**
+ * Listen once for a certain type of event.
+ * @param {string|Array.<string>} type The event type or array of event types.
+ * @param {function(?): ?} listener The listener function.
+ * @param {Object=} opt_this The object to use as `this` in `listener`.
+ * @return {ol.EventsKey|Array.<ol.EventsKey>} Unique key for the listener. If
+ * called with an array of event types as the first argument, the return
+ * will be an array of keys.
+ * @api stable
+ */
+ol.Observable.prototype.once = function(type, listener, opt_this) {
+ if (Array.isArray(type)) {
+ var len = type.length;
+ var keys = new Array(len);
+ for (var i = 0; i < len; ++i) {
+ keys[i] = ol.events.listenOnce(this, type[i], listener, opt_this);
+ }
+ return keys;
+ } else {
+ return ol.events.listenOnce(
+ this, /** @type {string} */ (type), listener, opt_this);
+ }
+};
+
+
+/**
+ * Unlisten for a certain type of event.
+ * @param {string|Array.<string>} type The event type or array of event types.
+ * @param {function(?): ?} listener The listener function.
+ * @param {Object=} opt_this The object which was used as `this` by the
+ * `listener`.
+ * @api stable
+ */
+ol.Observable.prototype.un = function(type, listener, opt_this) {
+ if (Array.isArray(type)) {
+ for (var i = 0, ii = type.length; i < ii; ++i) {
+ ol.events.unlisten(this, type[i], listener, opt_this);
+ }
+ return;
+ } else {
+ ol.events.unlisten(this, /** @type {string} */ (type), listener, opt_this);
+ }
+};
+
+
+/**
+ * Removes an event listener using the key returned by `on()` or `once()`.
+ * Note that using the {@link ol.Observable.unByKey} static function is to
+ * be preferred.
+ * @param {ol.EventsKey|Array.<ol.EventsKey>} key The key returned by `on()`
+ * or `once()` (or an array of keys).
+ * @function
+ * @api stable
+ */
+ol.Observable.prototype.unByKey = ol.Observable.unByKey;
+
+goog.provide('ol.Object');
+goog.provide('ol.ObjectEvent');
+goog.provide('ol.ObjectEventType');
+
+goog.require('ol.Observable');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.object');
+
+
+/**
+ * @enum {string}
+ */
+ol.ObjectEventType = {
+ /**
+ * Triggered when a property is changed.
+ * @event ol.ObjectEvent#propertychange
+ * @api stable
+ */
+ PROPERTYCHANGE: 'propertychange'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.Object} instances are instances of this type.
+ *
+ * @param {string} type The event type.
+ * @param {string} key The property name.
+ * @param {*} oldValue The old value for `key`.
+ * @extends {ol.events.Event}
+ * @implements {oli.ObjectEvent}
+ * @constructor
+ */
+ol.ObjectEvent = function(type, key, oldValue) {
+ ol.events.Event.call(this, type);
+
+ /**
+ * The name of the property whose value is changing.
+ * @type {string}
+ * @api stable
+ */
+ this.key = key;
+
+ /**
+ * The old value. To get the new value use `e.target.get(e.key)` where
+ * `e` is the event object.
+ * @type {*}
+ * @api stable
+ */
+ this.oldValue = oldValue;
+
+};
+ol.inherits(ol.ObjectEvent, ol.events.Event);
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Most non-trivial classes inherit from this.
+ *
+ * This extends {@link ol.Observable} with observable properties, where each
+ * property is observable as well as the object as a whole.
+ *
+ * Classes that inherit from this have pre-defined properties, to which you can
+ * add your owns. The pre-defined properties are listed in this documentation as
+ * 'Observable Properties', and have their own accessors; for example,
+ * {@link ol.Map} has a `target` property, accessed with `getTarget()` and
+ * changed with `setTarget()`. Not all properties are however settable. There
+ * are also general-purpose accessors `get()` and `set()`. For example,
+ * `get('target')` is equivalent to `getTarget()`.
+ *
+ * The `set` accessors trigger a change event, and you can monitor this by
+ * registering a listener. For example, {@link ol.View} has a `center`
+ * property, so `view.on('change:center', function(evt) {...});` would call the
+ * function whenever the value of the center property changes. Within the
+ * function, `evt.target` would be the view, so `evt.target.getCenter()` would
+ * return the new center.
+ *
+ * You can add your own observable properties with
+ * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`.
+ * You can listen for changes on that property value with
+ * `object.on('change:prop', listener)`. You can get a list of all
+ * properties with {@link ol.Object#getProperties object.getProperties()}.
+ *
+ * Note that the observable properties are separate from standard JS properties.
+ * You can, for example, give your map object a title with
+ * `map.title='New title'` and with `map.set('title', 'Another title')`. The
+ * first will be a `hasOwnProperty`; the second will appear in
+ * `getProperties()`. Only the second is observable.
+ *
+ * Properties can be deleted by using the unset method. E.g.
+ * object.unset('foo').
+ *
+ * @constructor
+ * @extends {ol.Observable}
+ * @param {Object.<string, *>=} opt_values An object with key-value pairs.
+ * @fires ol.ObjectEvent
+ * @api
+ */
+ol.Object = function(opt_values) {
+ ol.Observable.call(this);
+
+ // Call goog.getUid to ensure that the order of objects' ids is the same as
+ // the order in which they were created. This also helps to ensure that
+ // object properties are always added in the same order, which helps many
+ // JavaScript engines generate faster code.
+ goog.getUid(this);
+
+ /**
+ * @private
+ * @type {!Object.<string, *>}
+ */
+ this.values_ = {};
+
+ if (opt_values !== undefined) {
+ this.setProperties(opt_values);
+ }
+};
+ol.inherits(ol.Object, ol.Observable);
+
+
+/**
+ * @private
+ * @type {Object.<string, string>}
+ */
+ol.Object.changeEventTypeCache_ = {};
+
+
+/**
+ * @param {string} key Key name.
+ * @return {string} Change name.
+ */
+ol.Object.getChangeEventType = function(key) {
+ return ol.Object.changeEventTypeCache_.hasOwnProperty(key) ?
+ ol.Object.changeEventTypeCache_[key] :
+ (ol.Object.changeEventTypeCache_[key] = 'change:' + key);
+};
+
+
+/**
+ * Gets a value.
+ * @param {string} key Key name.
+ * @return {*} Value.
+ * @api stable
+ */
+ol.Object.prototype.get = function(key) {
+ var value;
+ if (this.values_.hasOwnProperty(key)) {
+ value = this.values_[key];
+ }
+ return value;
+};
+
+
+/**
+ * Get a list of object property names.
+ * @return {Array.<string>} List of property names.
+ * @api stable
+ */
+ol.Object.prototype.getKeys = function() {
+ return Object.keys(this.values_);
+};
+
+
+/**
+ * Get an object of all property names and values.
+ * @return {Object.<string, *>} Object.
+ * @api stable
+ */
+ol.Object.prototype.getProperties = function() {
+ return ol.object.assign({}, this.values_);
+};
+
+
+/**
+ * @param {string} key Key name.
+ * @param {*} oldValue Old value.
+ */
+ol.Object.prototype.notify = function(key, oldValue) {
+ var eventType;
+ eventType = ol.Object.getChangeEventType(key);
+ this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue));
+ eventType = ol.ObjectEventType.PROPERTYCHANGE;
+ this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue));
+};
+
+
+/**
+ * Sets a value.
+ * @param {string} key Key name.
+ * @param {*} value Value.
+ * @param {boolean=} opt_silent Update without triggering an event.
+ * @api stable
+ */
+ol.Object.prototype.set = function(key, value, opt_silent) {
+ if (opt_silent) {
+ this.values_[key] = value;
+ } else {
+ var oldValue = this.values_[key];
+ this.values_[key] = value;
+ if (oldValue !== value) {
+ this.notify(key, oldValue);
+ }
+ }
+};
+
+
+/**
+ * Sets a collection of key-value pairs. Note that this changes any existing
+ * properties and adds new ones (it does not remove any existing properties).
+ * @param {Object.<string, *>} values Values.
+ * @param {boolean=} opt_silent Update without triggering an event.
+ * @api stable
+ */
+ol.Object.prototype.setProperties = function(values, opt_silent) {
+ var key;
+ for (key in values) {
+ this.set(key, values[key], opt_silent);
+ }
+};
+
+
+/**
+ * Unsets a property.
+ * @param {string} key Key name.
+ * @param {boolean=} opt_silent Unset without triggering an event.
+ * @api stable
+ */
+ol.Object.prototype.unset = function(key, opt_silent) {
+ if (key in this.values_) {
+ var oldValue = this.values_[key];
+ delete this.values_[key];
+ if (!opt_silent) {
+ this.notify(key, oldValue);
+ }
+ }
+};
+
+goog.provide('ol.array');
+
+goog.require('goog.asserts');
+
+
+/**
+ * Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1.
+ * https://github.com/darkskyapp/binary-search
+ *
+ * @param {Array.<*>} haystack Items to search through.
+ * @param {*} needle The item to look for.
+ * @param {Function=} opt_comparator Comparator function.
+ * @return {number} The index of the item if found, -1 if not.
+ */
+ol.array.binarySearch = function(haystack, needle, opt_comparator) {
+ var mid, cmp;
+ var comparator = opt_comparator || ol.array.numberSafeCompareFunction;
+ var low = 0;
+ var high = haystack.length;
+ var found = false;
+
+ while (low < high) {
+ /* Note that "(low + high) >>> 1" may overflow, and results in a typecast
+ * to double (which gives the wrong results). */
+ mid = low + (high - low >> 1);
+ cmp = +comparator(haystack[mid], needle);
+
+ if (cmp < 0.0) { /* Too low. */
+ low = mid + 1;
+
+ } else { /* Key found or too high */
+ high = mid;
+ found = !cmp;
+ }
+ }
+
+ /* Key not found. */
+ return found ? low : ~low;
+};
+
+/**
+ * @param {Array.<number>} arr Array.
+ * @param {number} target Target.
+ * @return {number} Index.
+ */
+ol.array.binaryFindNearest = function(arr, target) {
+ var index = ol.array.binarySearch(arr, target,
+ /**
+ * @param {number} a A.
+ * @param {number} b B.
+ * @return {number} b minus a.
+ */
+ function(a, b) {
+ return b - a;
+ });
+ if (index >= 0) {
+ return index;
+ } else if (index == -1) {
+ return 0;
+ } else if (index == -arr.length - 1) {
+ return arr.length - 1;
+ } else {
+ var left = -index - 2;
+ var right = -index - 1;
+ if (arr[left] - target < target - arr[right]) {
+ return left;
+ } else {
+ return right;
+ }
+ }
+};
+
+
+/**
+ * Compare function for array sort that is safe for numbers.
+ * @param {*} a The first object to be compared.
+ * @param {*} b The second object to be compared.
+ * @return {number} A negative number, zero, or a positive number as the first
+ * argument is less than, equal to, or greater than the second.
+ */
+ol.array.numberSafeCompareFunction = function(a, b) {
+ return a > b ? 1 : a < b ? -1 : 0;
+};
+
+
+/**
+ * Whether the array contains the given object.
+ * @param {Array.<*>} arr The array to test for the presence of the element.
+ * @param {*} obj The object for which to test.
+ * @return {boolean} The object is in the array.
+ */
+ol.array.includes = function(arr, obj) {
+ return arr.indexOf(obj) >= 0;
+};
+
+
+/**
+ * @param {Array.<number>} arr Array.
+ * @param {number} target Target.
+ * @param {number} direction 0 means return the nearest, > 0
+ * means return the largest nearest, < 0 means return the
+ * smallest nearest.
+ * @return {number} Index.
+ */
+ol.array.linearFindNearest = function(arr, target, direction) {
+ var n = arr.length;
+ if (arr[0] <= target) {
+ return 0;
+ } else if (target <= arr[n - 1]) {
+ return n - 1;
+ } else {
+ var i;
+ if (direction > 0) {
+ for (i = 1; i < n; ++i) {
+ if (arr[i] < target) {
+ return i - 1;
+ }
+ }
+ } else if (direction < 0) {
+ for (i = 1; i < n; ++i) {
+ if (arr[i] <= target) {
+ return i;
+ }
+ }
+ } else {
+ for (i = 1; i < n; ++i) {
+ if (arr[i] == target) {
+ return i;
+ } else if (arr[i] < target) {
+ if (arr[i - 1] - target < target - arr[i]) {
+ return i - 1;
+ } else {
+ return i;
+ }
+ }
+ }
+ }
+ // We should never get here, but the compiler complains
+ // if it finds a path for which no number is returned.
+ goog.asserts.fail();
+ return n - 1;
+ }
+};
+
+
+/**
+ * @param {Array.<*>} arr Array.
+ * @param {number} begin Begin index.
+ * @param {number} end End index.
+ */
+ol.array.reverseSubArray = function(arr, begin, end) {
+ goog.asserts.assert(begin >= 0,
+ 'Array begin index should be equal to or greater than 0');
+ goog.asserts.assert(end < arr.length,
+ 'Array end index should be less than the array length');
+ while (begin < end) {
+ var tmp = arr[begin];
+ arr[begin] = arr[end];
+ arr[end] = tmp;
+ ++begin;
+ --end;
+ }
+};
+
+
+/**
+ * @param {Array.<*>} arr Array.
+ * @return {!Array.<?>} Flattened Array.
+ */
+ol.array.flatten = function(arr) {
+ var data = arr.reduce(function(flattened, value) {
+ if (Array.isArray(value)) {
+ return flattened.concat(ol.array.flatten(value));
+ } else {
+ return flattened.concat(value);
+ }
+ }, []);
+ return data;
+};
+
+
+/**
+ * @param {Array.<VALUE>} arr The array to modify.
+ * @param {Array.<VALUE>|VALUE} data The elements or arrays of elements
+ * to add to arr.
+ * @template VALUE
+ */
+ol.array.extend = function(arr, data) {
+ var i;
+ var extension = goog.isArrayLike(data) ? data : [data];
+ var length = extension.length;
+ for (i = 0; i < length; i++) {
+ arr[arr.length] = extension[i];
+ }
+};
+
+
+/**
+ * @param {Array.<VALUE>} arr The array to modify.
+ * @param {VALUE} obj The element to remove.
+ * @template VALUE
+ * @return {boolean} If the element was removed.
+ */
+ol.array.remove = function(arr, obj) {
+ var i = arr.indexOf(obj);
+ var found = i > -1;
+ if (found) {
+ arr.splice(i, 1);
+ }
+ return found;
+};
+
+
+/**
+ * @param {Array.<VALUE>} arr The array to search in.
+ * @param {function(VALUE, number, ?) : boolean} func The function to compare.
+ * @template VALUE
+ * @return {VALUE} The element found.
+ */
+ol.array.find = function(arr, func) {
+ var length = arr.length >>> 0;
+ var value;
+
+ for (var i = 0; i < length; i++) {
+ value = arr[i];
+ if (func(value, i, arr)) {
+ return value;
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @param {Array|Uint8ClampedArray} arr1 The first array to compare.
+ * @param {Array|Uint8ClampedArray} arr2 The second array to compare.
+ * @return {boolean} Whether the two arrays are equal.
+ */
+ol.array.equals = function(arr1, arr2) {
+ var len1 = arr1.length;
+ if (len1 !== arr2.length) {
+ return false;
+ }
+ for (var i = 0; i < len1; i++) {
+ if (arr1[i] !== arr2[i]) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * @param {Array.<*>} arr The array to sort (modifies original).
+ * @param {Function} compareFnc Comparison function.
+ */
+ol.array.stableSort = function(arr, compareFnc) {
+ var length = arr.length;
+ var tmp = Array(arr.length);
+ var i;
+ for (i = 0; i < length; i++) {
+ tmp[i] = {index: i, value: arr[i]};
+ }
+ tmp.sort(function(a, b) {
+ return compareFnc(a.value, b.value) || a.index - b.index;
+ });
+ for (i = 0; i < arr.length; i++) {
+ arr[i] = tmp[i].value;
+ }
+};
+
+
+/**
+ * @param {Array.<*>} arr The array to search in.
+ * @param {Function} func Comparison function.
+ * @return {number} Return index.
+ */
+ol.array.findIndex = function(arr, func) {
+ var index;
+ var found = !arr.every(function(el, idx) {
+ index = idx;
+ return !func(el, idx, arr);
+ });
+ return found ? index : -1;
+};
+
+
+/**
+ * @param {Array.<*>} arr The array to test.
+ * @param {Function=} opt_func Comparison function.
+ * @param {boolean=} opt_strict Strictly sorted (default false).
+ * @return {boolean} Return index.
+ */
+ol.array.isSorted = function(arr, opt_func, opt_strict) {
+ var compare = opt_func || ol.array.numberSafeCompareFunction;
+ return arr.every(function(currentVal, index) {
+ if (index === 0) {
+ return true;
+ }
+ var res = compare(arr[index - 1], currentVal);
+ return !(res > 0 || opt_strict && res === 0);
+ });
+};
+
+goog.provide('ol.ResolutionConstraint');
+
+goog.require('ol.array');
+goog.require('ol.math');
+
+
+/**
+ * @param {Array.<number>} resolutions Resolutions.
+ * @return {ol.ResolutionConstraintType} Zoom function.
+ */
+ol.ResolutionConstraint.createSnapToResolutions = function(resolutions) {
+ return (
+ /**
+ * @param {number|undefined} resolution Resolution.
+ * @param {number} delta Delta.
+ * @param {number} direction Direction.
+ * @return {number|undefined} Resolution.
+ */
+ function(resolution, delta, direction) {
+ if (resolution !== undefined) {
+ var z =
+ ol.array.linearFindNearest(resolutions, resolution, direction);
+ z = ol.math.clamp(z + delta, 0, resolutions.length - 1);
+ return resolutions[z];
+ } else {
+ return undefined;
+ }
+ });
+};
+
+
+/**
+ * @param {number} power Power.
+ * @param {number} maxResolution Maximum resolution.
+ * @param {number=} opt_maxLevel Maximum level.
+ * @return {ol.ResolutionConstraintType} Zoom function.
+ */
+ol.ResolutionConstraint.createSnapToPower = function(power, maxResolution, opt_maxLevel) {
+ return (
+ /**
+ * @param {number|undefined} resolution Resolution.
+ * @param {number} delta Delta.
+ * @param {number} direction Direction.
+ * @return {number|undefined} Resolution.
+ */
+ function(resolution, delta, direction) {
+ if (resolution !== undefined) {
+ var offset;
+ if (direction > 0) {
+ offset = 0;
+ } else if (direction < 0) {
+ offset = 1;
+ } else {
+ offset = 0.5;
+ }
+ var oldLevel = Math.floor(
+ Math.log(maxResolution / resolution) / Math.log(power) + offset);
+ var newLevel = Math.max(oldLevel + delta, 0);
+ if (opt_maxLevel !== undefined) {
+ newLevel = Math.min(newLevel, opt_maxLevel);
+ }
+ return maxResolution / Math.pow(power, newLevel);
+ } else {
+ return undefined;
+ }
+ });
+};
+
+goog.provide('ol.RotationConstraint');
+
+goog.require('ol.math');
+
+
+/**
+ * @param {number|undefined} rotation Rotation.
+ * @param {number} delta Delta.
+ * @return {number|undefined} Rotation.
+ */
+ol.RotationConstraint.disable = function(rotation, delta) {
+ if (rotation !== undefined) {
+ return 0;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {number|undefined} rotation Rotation.
+ * @param {number} delta Delta.
+ * @return {number|undefined} Rotation.
+ */
+ol.RotationConstraint.none = function(rotation, delta) {
+ if (rotation !== undefined) {
+ return rotation + delta;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {number} n N.
+ * @return {ol.RotationConstraintType} Rotation constraint.
+ */
+ol.RotationConstraint.createSnapToN = function(n) {
+ var theta = 2 * Math.PI / n;
+ return (
+ /**
+ * @param {number|undefined} rotation Rotation.
+ * @param {number} delta Delta.
+ * @return {number|undefined} Rotation.
+ */
+ function(rotation, delta) {
+ if (rotation !== undefined) {
+ rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;
+ return rotation;
+ } else {
+ return undefined;
+ }
+ });
+};
+
+
+/**
+ * @param {number=} opt_tolerance Tolerance.
+ * @return {ol.RotationConstraintType} Rotation constraint.
+ */
+ol.RotationConstraint.createSnapToZero = function(opt_tolerance) {
+ var tolerance = opt_tolerance || ol.math.toRadians(5);
+ return (
+ /**
+ * @param {number|undefined} rotation Rotation.
+ * @param {number} delta Delta.
+ * @return {number|undefined} Rotation.
+ */
+ function(rotation, delta) {
+ if (rotation !== undefined) {
+ if (Math.abs(rotation + delta) <= tolerance) {
+ return 0;
+ } else {
+ return rotation + delta;
+ }
+ } else {
+ return undefined;
+ }
+ });
+};
+
+goog.provide('ol.string');
+
+/**
+ * @param {number} number Number to be formatted
+ * @param {number} width The desired width
+ * @param {number=} opt_precision Precision of the output string (i.e. number of decimal places)
+ * @returns {string} Formatted string
+*/
+ol.string.padNumber = function(number, width, opt_precision) {
+ var numberString = opt_precision !== undefined ? number.toFixed(opt_precision) : '' + number;
+ var decimal = numberString.indexOf('.');
+ decimal = decimal === -1 ? numberString.length : decimal;
+ return decimal > width ? numberString : new Array(1 + width - decimal).join('0') + numberString;
+};
+
+/**
+ * Adapted from https://github.com/omichelsen/compare-versions/blob/master/index.js
+ * @param {string|number} v1 First version
+ * @param {string|number} v2 Second version
+ * @returns {number} Value
+ */
+ol.string.compareVersions = function(v1, v2) {
+ var s1 = ('' + v1).split('.');
+ var s2 = ('' + v2).split('.');
+
+ for (var i = 0; i < Math.max(s1.length, s2.length); i++) {
+ var n1 = parseInt(s1[i] || '0', 10);
+ var n2 = parseInt(s2[i] || '0', 10);
+
+ if (n1 > n2) return 1;
+ if (n2 > n1) return -1;
+ }
+
+ return 0;
+};
+
+goog.provide('ol.coordinate');
+
+goog.require('ol.math');
+goog.require('ol.string');
+
+
+/**
+ * Add `delta` to `coordinate`. `coordinate` is modified in place and returned
+ * by the function.
+ *
+ * Example:
+ *
+ * var coord = [7.85, 47.983333];
+ * ol.coordinate.add(coord, [-2, 4]);
+ * // coord is now [5.85, 51.983333]
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.Coordinate} delta Delta.
+ * @return {ol.Coordinate} The input coordinate adjusted by the given delta.
+ * @api stable
+ */
+ol.coordinate.add = function(coordinate, delta) {
+ coordinate[0] += delta[0];
+ coordinate[1] += delta[1];
+ return coordinate;
+};
+
+
+/**
+ * Calculates the point closest to the passed coordinate on the passed segment.
+ * This is the foot of the perpendicular of the coordinate to the segment when
+ * the foot is on the segment, or the closest segment coordinate when the foot
+ * is outside the segment.
+ *
+ * @param {ol.Coordinate} coordinate The coordinate.
+ * @param {Array.<ol.Coordinate>} segment The two coordinates of the segment.
+ * @return {ol.Coordinate} The foot of the perpendicular of the coordinate to
+ * the segment.
+ */
+ol.coordinate.closestOnSegment = function(coordinate, segment) {
+ var x0 = coordinate[0];
+ var y0 = coordinate[1];
+ var start = segment[0];
+ var end = segment[1];
+ var x1 = start[0];
+ var y1 = start[1];
+ var x2 = end[0];
+ var y2 = end[1];
+ var dx = x2 - x1;
+ var dy = y2 - y1;
+ var along = (dx === 0 && dy === 0) ? 0 :
+ ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);
+ var x, y;
+ if (along <= 0) {
+ x = x1;
+ y = y1;
+ } else if (along >= 1) {
+ x = x2;
+ y = y2;
+ } else {
+ x = x1 + along * dx;
+ y = y1 + along * dy;
+ }
+ return [x, y];
+};
+
+
+/**
+ * Returns a {@link ol.CoordinateFormatType} function that can be used to format
+ * a {ol.Coordinate} to a string.
+ *
+ * Example without specifying the fractional digits:
+ *
+ * var coord = [7.85, 47.983333];
+ * var stringifyFunc = ol.coordinate.createStringXY();
+ * var out = stringifyFunc(coord);
+ * // out is now '8, 48'
+ *
+ * Example with explicitly specifying 2 fractional digits:
+ *
+ * var coord = [7.85, 47.983333];
+ * var stringifyFunc = ol.coordinate.createStringXY(2);
+ * var out = stringifyFunc(coord);
+ * // out is now '7.85, 47.98'
+ *
+ * @param {number=} opt_fractionDigits The number of digits to include
+ * after the decimal point. Default is `0`.
+ * @return {ol.CoordinateFormatType} Coordinate format.
+ * @api stable
+ */
+ol.coordinate.createStringXY = function(opt_fractionDigits) {
+ return (
+ /**
+ * @param {ol.Coordinate|undefined} coordinate Coordinate.
+ * @return {string} String XY.
+ */
+ function(coordinate) {
+ return ol.coordinate.toStringXY(coordinate, opt_fractionDigits);
+ });
+};
+
+
+/**
+ * @private
+ * @param {number} degrees Degrees.
+ * @param {string} hemispheres Hemispheres.
+ * @param {number=} opt_fractionDigits The number of digits to include
+ * after the decimal point. Default is `0`.
+ * @return {string} String.
+ */
+ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres, opt_fractionDigits) {
+ var normalizedDegrees = ol.math.modulo(degrees + 180, 360) - 180;
+ var x = Math.abs(3600 * normalizedDegrees);
+ var dflPrecision = opt_fractionDigits || 0;
+ return Math.floor(x / 3600) + '\u00b0 ' +
+ ol.string.padNumber(Math.floor((x / 60) % 60), 2) + '\u2032 ' +
+ ol.string.padNumber((x % 60), 2, dflPrecision) + '\u2033 ' +
+ hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);
+};
+
+
+/**
+ * Transforms the given {@link ol.Coordinate} to a string using the given string
+ * template. The strings `{x}` and `{y}` in the template will be replaced with
+ * the first and second coordinate values respectively.
+ *
+ * Example without specifying the fractional digits:
+ *
+ * var coord = [7.85, 47.983333];
+ * var template = 'Coordinate is ({x}|{y}).';
+ * var out = ol.coordinate.format(coord, template);
+ * // out is now 'Coordinate is (8|48).'
+ *
+ * Example explicitly specifying the fractional digits:
+ *
+ * var coord = [7.85, 47.983333];
+ * var template = 'Coordinate is ({x}|{y}).';
+ * var out = ol.coordinate.format(coord, template, 2);
+ * // out is now 'Coordinate is (7.85|47.98).'
+ *
+ * @param {ol.Coordinate|undefined} coordinate Coordinate.
+ * @param {string} template A template string with `{x}` and `{y}` placeholders
+ * that will be replaced by first and second coordinate values.
+ * @param {number=} opt_fractionDigits The number of digits to include
+ * after the decimal point. Default is `0`.
+ * @return {string} Formatted coordinate.
+ * @api stable
+ */
+ol.coordinate.format = function(coordinate, template, opt_fractionDigits) {
+ if (coordinate) {
+ return template
+ .replace('{x}', coordinate[0].toFixed(opt_fractionDigits))
+ .replace('{y}', coordinate[1].toFixed(opt_fractionDigits));
+ } else {
+ return '';
+ }
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate1 First coordinate.
+ * @param {ol.Coordinate} coordinate2 Second coordinate.
+ * @return {boolean} Whether the passed coordinates are equal.
+ */
+ol.coordinate.equals = function(coordinate1, coordinate2) {
+ var equals = true;
+ for (var i = coordinate1.length - 1; i >= 0; --i) {
+ if (coordinate1[i] != coordinate2[i]) {
+ equals = false;
+ break;
+ }
+ }
+ return equals;
+};
+
+
+/**
+ * Rotate `coordinate` by `angle`. `coordinate` is modified in place and
+ * returned by the function.
+ *
+ * Example:
+ *
+ * var coord = [7.85, 47.983333];
+ * var rotateRadians = Math.PI / 2; // 90 degrees
+ * ol.coordinate.rotate(coord, rotateRadians);
+ * // coord is now [-47.983333, 7.85]
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} angle Angle in radian.
+ * @return {ol.Coordinate} Coordinate.
+ * @api stable
+ */
+ol.coordinate.rotate = function(coordinate, angle) {
+ var cosAngle = Math.cos(angle);
+ var sinAngle = Math.sin(angle);
+ var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
+ var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
+ coordinate[0] = x;
+ coordinate[1] = y;
+ return coordinate;
+};
+
+
+/**
+ * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned
+ * by the function.
+ *
+ * Example:
+ *
+ * var coord = [7.85, 47.983333];
+ * var scale = 1.2;
+ * ol.coordinate.scale(coord, scale);
+ * // coord is now [9.42, 57.5799996]
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} scale Scale factor.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ol.coordinate.scale = function(coordinate, scale) {
+ coordinate[0] *= scale;
+ coordinate[1] *= scale;
+ return coordinate;
+};
+
+
+/**
+ * Subtract `delta` to `coordinate`. `coordinate` is modified in place and
+ * returned by the function.
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.Coordinate} delta Delta.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ol.coordinate.sub = function(coordinate, delta) {
+ coordinate[0] -= delta[0];
+ coordinate[1] -= delta[1];
+ return coordinate;
+};
+
+
+/**
+ * @param {ol.Coordinate} coord1 First coordinate.
+ * @param {ol.Coordinate} coord2 Second coordinate.
+ * @return {number} Squared distance between coord1 and coord2.
+ */
+ol.coordinate.squaredDistance = function(coord1, coord2) {
+ var dx = coord1[0] - coord2[0];
+ var dy = coord1[1] - coord2[1];
+ return dx * dx + dy * dy;
+};
+
+
+/**
+ * Calculate the squared distance from a coordinate to a line segment.
+ *
+ * @param {ol.Coordinate} coordinate Coordinate of the point.
+ * @param {Array.<ol.Coordinate>} segment Line segment (2 coordinates).
+ * @return {number} Squared distance from the point to the line segment.
+ */
+ol.coordinate.squaredDistanceToSegment = function(coordinate, segment) {
+ return ol.coordinate.squaredDistance(coordinate,
+ ol.coordinate.closestOnSegment(coordinate, segment));
+};
+
+
+/**
+ * Format a geographic coordinate with the hemisphere, degrees, minutes, and
+ * seconds.
+ *
+ * Example without specifying fractional digits:
+ *
+ * var coord = [7.85, 47.983333];
+ * var out = ol.coordinate.toStringHDMS(coord);
+ * // out is now '47° 58′ 60″ N 7° 50′ 60″ E'
+ *
+ * Example explicitly specifying 1 fractional digit:
+ *
+ * var coord = [7.85, 47.983333];
+ * var out = ol.coordinate.toStringHDMS(coord, 1);
+ * // out is now '47° 58′ 60.0″ N 7° 50′ 60.0″ E'
+ *
+ * @param {ol.Coordinate|undefined} coordinate Coordinate.
+ * @param {number=} opt_fractionDigits The number of digits to include
+ * after the decimal point. Default is `0`.
+ * @return {string} Hemisphere, degrees, minutes and seconds.
+ * @api stable
+ */
+ol.coordinate.toStringHDMS = function(coordinate, opt_fractionDigits) {
+ if (coordinate) {
+ return ol.coordinate.degreesToStringHDMS_(coordinate[1], 'NS', opt_fractionDigits) + ' ' +
+ ol.coordinate.degreesToStringHDMS_(coordinate[0], 'EW', opt_fractionDigits);
+ } else {
+ return '';
+ }
+};
+
+
+/**
+ * Format a coordinate as a comma delimited string.
+ *
+ * Example without specifying fractional digits:
+ *
+ * var coord = [7.85, 47.983333];
+ * var out = ol.coordinate.toStringXY(coord);
+ * // out is now '8, 48'
+ *
+ * Example explicitly specifying 1 fractional digit:
+ *
+ * var coord = [7.85, 47.983333];
+ * var out = ol.coordinate.toStringXY(coord, 1);
+ * // out is now '7.8, 48.0'
+ *
+ * @param {ol.Coordinate|undefined} coordinate Coordinate.
+ * @param {number=} opt_fractionDigits The number of digits to include
+ * after the decimal point. Default is `0`.
+ * @return {string} XY.
+ * @api stable
+ */
+ol.coordinate.toStringXY = function(coordinate, opt_fractionDigits) {
+ return ol.coordinate.format(coordinate, '{x}, {y}', opt_fractionDigits);
+};
+
+
+/**
+ * Create an ol.Coordinate from an Array and take into account axis order.
+ *
+ * Examples:
+ *
+ * var northCoord = ol.coordinate.fromProjectedArray([1, 2], 'n');
+ * // northCoord is now [2, 1]
+ *
+ * var eastCoord = ol.coordinate.fromProjectedArray([1, 2], 'e');
+ * // eastCoord is now [1, 2]
+ *
+ * @param {Array} array The array with coordinates.
+ * @param {string} axis the axis info.
+ * @return {ol.Coordinate} The coordinate created.
+ */
+ol.coordinate.fromProjectedArray = function(array, axis) {
+ var firstAxis = axis.charAt(0);
+ if (firstAxis === 'n' || firstAxis === 's') {
+ return [array[1], array[0]];
+ } else {
+ return array;
+ }
+};
+
+goog.provide('ol.extent');
+goog.provide('ol.extent.Corner');
+goog.provide('ol.extent.Relationship');
+
+goog.require('goog.asserts');
+
+
+/**
+ * Extent corner.
+ * @enum {string}
+ */
+ol.extent.Corner = {
+ BOTTOM_LEFT: 'bottom-left',
+ BOTTOM_RIGHT: 'bottom-right',
+ TOP_LEFT: 'top-left',
+ TOP_RIGHT: 'top-right'
+};
+
+
+/**
+ * Relationship to an extent.
+ * @enum {number}
+ */
+ol.extent.Relationship = {
+ UNKNOWN: 0,
+ INTERSECTING: 1,
+ ABOVE: 2,
+ RIGHT: 4,
+ BELOW: 8,
+ LEFT: 16
+};
+
+
+/**
+ * Build an extent that includes all given coordinates.
+ *
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @return {ol.Extent} Bounding extent.
+ * @api stable
+ */
+ol.extent.boundingExtent = function(coordinates) {
+ var extent = ol.extent.createEmpty();
+ for (var i = 0, ii = coordinates.length; i < ii; ++i) {
+ ol.extent.extendCoordinate(extent, coordinates[i]);
+ }
+ return extent;
+};
+
+
+/**
+ * @param {Array.<number>} xs Xs.
+ * @param {Array.<number>} ys Ys.
+ * @param {ol.Extent=} opt_extent Destination extent.
+ * @private
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) {
+ goog.asserts.assert(xs.length > 0, 'xs length should be larger than 0');
+ goog.asserts.assert(ys.length > 0, 'ys length should be larger than 0');
+ var minX = Math.min.apply(null, xs);
+ var minY = Math.min.apply(null, ys);
+ var maxX = Math.max.apply(null, xs);
+ var maxY = Math.max.apply(null, ys);
+ return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
+};
+
+
+/**
+ * Return extent increased by the provided value.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} value The amount by which the extent should be buffered.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ * @api stable
+ */
+ol.extent.buffer = function(extent, value, opt_extent) {
+ if (opt_extent) {
+ opt_extent[0] = extent[0] - value;
+ opt_extent[1] = extent[1] - value;
+ opt_extent[2] = extent[2] + value;
+ opt_extent[3] = extent[3] + value;
+ return opt_extent;
+ } else {
+ return [
+ extent[0] - value,
+ extent[1] - value,
+ extent[2] + value,
+ extent[3] + value
+ ];
+ }
+};
+
+
+/**
+ * Creates a clone of an extent.
+ *
+ * @param {ol.Extent} extent Extent to clone.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} The clone.
+ */
+ol.extent.clone = function(extent, opt_extent) {
+ if (opt_extent) {
+ opt_extent[0] = extent[0];
+ opt_extent[1] = extent[1];
+ opt_extent[2] = extent[2];
+ opt_extent[3] = extent[3];
+ return opt_extent;
+ } else {
+ return extent.slice();
+ }
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {number} Closest squared distance.
+ */
+ol.extent.closestSquaredDistanceXY = function(extent, x, y) {
+ var dx, dy;
+ if (x < extent[0]) {
+ dx = extent[0] - x;
+ } else if (extent[2] < x) {
+ dx = x - extent[2];
+ } else {
+ dx = 0;
+ }
+ if (y < extent[1]) {
+ dy = extent[1] - y;
+ } else if (extent[3] < y) {
+ dy = y - extent[3];
+ } else {
+ dy = 0;
+ }
+ return dx * dx + dy * dy;
+};
+
+
+/**
+ * Check if the passed coordinate is contained or on the edge of the extent.
+ *
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {boolean} The coordinate is contained in the extent.
+ * @api stable
+ */
+ol.extent.containsCoordinate = function(extent, coordinate) {
+ return ol.extent.containsXY(extent, coordinate[0], coordinate[1]);
+};
+
+
+/**
+ * Check if one extent contains another.
+ *
+ * An extent is deemed contained if it lies completely within the other extent,
+ * including if they share one or more edges.
+ *
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent 2.
+ * @return {boolean} The second extent is contained by or on the edge of the
+ * first.
+ * @api stable
+ */
+ol.extent.containsExtent = function(extent1, extent2) {
+ return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] &&
+ extent1[1] <= extent2[1] && extent2[3] <= extent1[3];
+};
+
+
+/**
+ * Check if the passed coordinate is contained or on the edge of the extent.
+ *
+ * @param {ol.Extent} extent Extent.
+ * @param {number} x X coordinate.
+ * @param {number} y Y coordinate.
+ * @return {boolean} The x, y values are contained in the extent.
+ * @api stable
+ */
+ol.extent.containsXY = function(extent, x, y) {
+ return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];
+};
+
+
+/**
+ * Get the relationship between a coordinate and extent.
+ * @param {ol.Extent} extent The extent.
+ * @param {ol.Coordinate} coordinate The coordinate.
+ * @return {number} The relationship (bitwise compare with
+ * ol.extent.Relationship).
+ */
+ol.extent.coordinateRelationship = function(extent, coordinate) {
+ var minX = extent[0];
+ var minY = extent[1];
+ var maxX = extent[2];
+ var maxY = extent[3];
+ var x = coordinate[0];
+ var y = coordinate[1];
+ var relationship = ol.extent.Relationship.UNKNOWN;
+ if (x < minX) {
+ relationship = relationship | ol.extent.Relationship.LEFT;
+ } else if (x > maxX) {
+ relationship = relationship | ol.extent.Relationship.RIGHT;
+ }
+ if (y < minY) {
+ relationship = relationship | ol.extent.Relationship.BELOW;
+ } else if (y > maxY) {
+ relationship = relationship | ol.extent.Relationship.ABOVE;
+ }
+ if (relationship === ol.extent.Relationship.UNKNOWN) {
+ relationship = ol.extent.Relationship.INTERSECTING;
+ }
+ return relationship;
+};
+
+
+/**
+ * Create an empty extent.
+ * @return {ol.Extent} Empty extent.
+ * @api stable
+ */
+ol.extent.createEmpty = function() {
+ return [Infinity, Infinity, -Infinity, -Infinity];
+};
+
+
+/**
+ * Create a new extent or update the provided extent.
+ * @param {number} minX Minimum X.
+ * @param {number} minY Minimum Y.
+ * @param {number} maxX Maximum X.
+ * @param {number} maxY Maximum Y.
+ * @param {ol.Extent=} opt_extent Destination extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) {
+ if (opt_extent) {
+ opt_extent[0] = minX;
+ opt_extent[1] = minY;
+ opt_extent[2] = maxX;
+ opt_extent[3] = maxY;
+ return opt_extent;
+ } else {
+ return [minX, minY, maxX, maxY];
+ }
+};
+
+
+/**
+ * Create a new empty extent or make the provided one empty.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.createOrUpdateEmpty = function(opt_extent) {
+ return ol.extent.createOrUpdate(
+ Infinity, Infinity, -Infinity, -Infinity, opt_extent);
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) {
+ var x = coordinate[0];
+ var y = coordinate[1];
+ return ol.extent.createOrUpdate(x, y, x, y, opt_extent);
+};
+
+
+/**
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) {
+ var extent = ol.extent.createOrUpdateEmpty(opt_extent);
+ return ol.extent.extendCoordinates(extent, coordinates);
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.createOrUpdateFromFlatCoordinates = function(flatCoordinates, offset, end, stride, opt_extent) {
+ var extent = ol.extent.createOrUpdateEmpty(opt_extent);
+ return ol.extent.extendFlatCoordinates(
+ extent, flatCoordinates, offset, end, stride);
+};
+
+
+/**
+ * @param {Array.<Array.<ol.Coordinate>>} rings Rings.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.createOrUpdateFromRings = function(rings, opt_extent) {
+ var extent = ol.extent.createOrUpdateEmpty(opt_extent);
+ return ol.extent.extendRings(extent, rings);
+};
+
+
+/**
+ * Empty an extent in place.
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.empty = function(extent) {
+ extent[0] = extent[1] = Infinity;
+ extent[2] = extent[3] = -Infinity;
+ return extent;
+};
+
+
+/**
+ * Determine if two extents are equivalent.
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent 2.
+ * @return {boolean} The two extents are equivalent.
+ * @api stable
+ */
+ol.extent.equals = function(extent1, extent2) {
+ return extent1[0] == extent2[0] && extent1[2] == extent2[2] &&
+ extent1[1] == extent2[1] && extent1[3] == extent2[3];
+};
+
+
+/**
+ * Modify an extent to include another extent.
+ * @param {ol.Extent} extent1 The extent to be modified.
+ * @param {ol.Extent} extent2 The extent that will be included in the first.
+ * @return {ol.Extent} A reference to the first (extended) extent.
+ * @api stable
+ */
+ol.extent.extend = function(extent1, extent2) {
+ if (extent2[0] < extent1[0]) {
+ extent1[0] = extent2[0];
+ }
+ if (extent2[2] > extent1[2]) {
+ extent1[2] = extent2[2];
+ }
+ if (extent2[1] < extent1[1]) {
+ extent1[1] = extent2[1];
+ }
+ if (extent2[3] > extent1[3]) {
+ extent1[3] = extent2[3];
+ }
+ return extent1;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ */
+ol.extent.extendCoordinate = function(extent, coordinate) {
+ if (coordinate[0] < extent[0]) {
+ extent[0] = coordinate[0];
+ }
+ if (coordinate[0] > extent[2]) {
+ extent[2] = coordinate[0];
+ }
+ if (coordinate[1] < extent[1]) {
+ extent[1] = coordinate[1];
+ }
+ if (coordinate[1] > extent[3]) {
+ extent[3] = coordinate[1];
+ }
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.extendCoordinates = function(extent, coordinates) {
+ var i, ii;
+ for (i = 0, ii = coordinates.length; i < ii; ++i) {
+ ol.extent.extendCoordinate(extent, coordinates[i]);
+ }
+ return extent;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.extendFlatCoordinates = function(extent, flatCoordinates, offset, end, stride) {
+ for (; offset < end; offset += stride) {
+ ol.extent.extendXY(
+ extent, flatCoordinates[offset], flatCoordinates[offset + 1]);
+ }
+ return extent;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {Array.<Array.<ol.Coordinate>>} rings Rings.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.extendRings = function(extent, rings) {
+ var i, ii;
+ for (i = 0, ii = rings.length; i < ii; ++i) {
+ ol.extent.extendCoordinates(extent, rings[i]);
+ }
+ return extent;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} x X.
+ * @param {number} y Y.
+ */
+ol.extent.extendXY = function(extent, x, y) {
+ extent[0] = Math.min(extent[0], x);
+ extent[1] = Math.min(extent[1], y);
+ extent[2] = Math.max(extent[2], x);
+ extent[3] = Math.max(extent[3], y);
+};
+
+
+/**
+ * This function calls `callback` for each corner of the extent. If the
+ * callback returns a truthy value the function returns that value
+ * immediately. Otherwise the function returns `false`.
+ * @param {ol.Extent} extent Extent.
+ * @param {function(this:T, ol.Coordinate): S} callback Callback.
+ * @param {T=} opt_this Value to use as `this` when executing `callback`.
+ * @return {S|boolean} Value.
+ * @template S, T
+ */
+ol.extent.forEachCorner = function(extent, callback, opt_this) {
+ var val;
+ val = callback.call(opt_this, ol.extent.getBottomLeft(extent));
+ if (val) {
+ return val;
+ }
+ val = callback.call(opt_this, ol.extent.getBottomRight(extent));
+ if (val) {
+ return val;
+ }
+ val = callback.call(opt_this, ol.extent.getTopRight(extent));
+ if (val) {
+ return val;
+ }
+ val = callback.call(opt_this, ol.extent.getTopLeft(extent));
+ if (val) {
+ return val;
+ }
+ return false;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @return {number} Area.
+ */
+ol.extent.getArea = function(extent) {
+ var area = 0;
+ if (!ol.extent.isEmpty(extent)) {
+ area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent);
+ }
+ return area;
+};
+
+
+/**
+ * Get the bottom left coordinate of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.Coordinate} Bottom left coordinate.
+ * @api stable
+ */
+ol.extent.getBottomLeft = function(extent) {
+ return [extent[0], extent[1]];
+};
+
+
+/**
+ * Get the bottom right coordinate of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.Coordinate} Bottom right coordinate.
+ * @api stable
+ */
+ol.extent.getBottomRight = function(extent) {
+ return [extent[2], extent[1]];
+};
+
+
+/**
+ * Get the center coordinate of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.Coordinate} Center.
+ * @api stable
+ */
+ol.extent.getCenter = function(extent) {
+ return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];
+};
+
+
+/**
+ * Get a corner coordinate of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.extent.Corner} corner Corner.
+ * @return {ol.Coordinate} Corner coordinate.
+ */
+ol.extent.getCorner = function(extent, corner) {
+ var coordinate;
+ if (corner === ol.extent.Corner.BOTTOM_LEFT) {
+ coordinate = ol.extent.getBottomLeft(extent);
+ } else if (corner === ol.extent.Corner.BOTTOM_RIGHT) {
+ coordinate = ol.extent.getBottomRight(extent);
+ } else if (corner === ol.extent.Corner.TOP_LEFT) {
+ coordinate = ol.extent.getTopLeft(extent);
+ } else if (corner === ol.extent.Corner.TOP_RIGHT) {
+ coordinate = ol.extent.getTopRight(extent);
+ } else {
+ goog.asserts.fail('Invalid corner: %s', corner);
+ }
+ goog.asserts.assert(coordinate, 'coordinate should be defined');
+ return coordinate;
+};
+
+
+/**
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent 2.
+ * @return {number} Enlarged area.
+ */
+ol.extent.getEnlargedArea = function(extent1, extent2) {
+ var minX = Math.min(extent1[0], extent2[0]);
+ var minY = Math.min(extent1[1], extent2[1]);
+ var maxX = Math.max(extent1[2], extent2[2]);
+ var maxY = Math.max(extent1[3], extent2[3]);
+ return (maxX - minX) * (maxY - minY);
+};
+
+
+/**
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {ol.Extent=} opt_extent Destination extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.getForViewAndSize = function(center, resolution, rotation, size, opt_extent) {
+ var dx = resolution * size[0] / 2;
+ var dy = resolution * size[1] / 2;
+ var cosRotation = Math.cos(rotation);
+ var sinRotation = Math.sin(rotation);
+ var xCos = dx * cosRotation;
+ var xSin = dx * sinRotation;
+ var yCos = dy * cosRotation;
+ var ySin = dy * sinRotation;
+ var x = center[0];
+ var y = center[1];
+ var x0 = x - xCos + ySin;
+ var x1 = x - xCos - ySin;
+ var x2 = x + xCos - ySin;
+ var x3 = x + xCos + ySin;
+ var y0 = y - xSin - yCos;
+ var y1 = y - xSin + yCos;
+ var y2 = y + xSin + yCos;
+ var y3 = y + xSin - yCos;
+ return ol.extent.createOrUpdate(
+ Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),
+ Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),
+ opt_extent);
+};
+
+
+/**
+ * Get the height of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {number} Height.
+ * @api stable
+ */
+ol.extent.getHeight = function(extent) {
+ return extent[3] - extent[1];
+};
+
+
+/**
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent 2.
+ * @return {number} Intersection area.
+ */
+ol.extent.getIntersectionArea = function(extent1, extent2) {
+ var intersection = ol.extent.getIntersection(extent1, extent2);
+ return ol.extent.getArea(intersection);
+};
+
+
+/**
+ * Get the intersection of two extents.
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent 2.
+ * @param {ol.Extent=} opt_extent Optional extent to populate with intersection.
+ * @return {ol.Extent} Intersecting extent.
+ * @api stable
+ */
+ol.extent.getIntersection = function(extent1, extent2, opt_extent) {
+ var intersection = opt_extent ? opt_extent : ol.extent.createEmpty();
+ if (ol.extent.intersects(extent1, extent2)) {
+ if (extent1[0] > extent2[0]) {
+ intersection[0] = extent1[0];
+ } else {
+ intersection[0] = extent2[0];
+ }
+ if (extent1[1] > extent2[1]) {
+ intersection[1] = extent1[1];
+ } else {
+ intersection[1] = extent2[1];
+ }
+ if (extent1[2] < extent2[2]) {
+ intersection[2] = extent1[2];
+ } else {
+ intersection[2] = extent2[2];
+ }
+ if (extent1[3] < extent2[3]) {
+ intersection[3] = extent1[3];
+ } else {
+ intersection[3] = extent2[3];
+ }
+ }
+ return intersection;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @return {number} Margin.
+ */
+ol.extent.getMargin = function(extent) {
+ return ol.extent.getWidth(extent) + ol.extent.getHeight(extent);
+};
+
+
+/**
+ * Get the size (width, height) of an extent.
+ * @param {ol.Extent} extent The extent.
+ * @return {ol.Size} The extent size.
+ * @api stable
+ */
+ol.extent.getSize = function(extent) {
+ return [extent[2] - extent[0], extent[3] - extent[1]];
+};
+
+
+/**
+ * Get the top left coordinate of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.Coordinate} Top left coordinate.
+ * @api stable
+ */
+ol.extent.getTopLeft = function(extent) {
+ return [extent[0], extent[3]];
+};
+
+
+/**
+ * Get the top right coordinate of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {ol.Coordinate} Top right coordinate.
+ * @api stable
+ */
+ol.extent.getTopRight = function(extent) {
+ return [extent[2], extent[3]];
+};
+
+
+/**
+ * Get the width of an extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {number} Width.
+ * @api stable
+ */
+ol.extent.getWidth = function(extent) {
+ return extent[2] - extent[0];
+};
+
+
+/**
+ * Determine if one extent intersects another.
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent.
+ * @return {boolean} The two extents intersect.
+ * @api stable
+ */
+ol.extent.intersects = function(extent1, extent2) {
+ return extent1[0] <= extent2[2] &&
+ extent1[2] >= extent2[0] &&
+ extent1[1] <= extent2[3] &&
+ extent1[3] >= extent2[1];
+};
+
+
+/**
+ * Determine if an extent is empty.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} Is empty.
+ * @api stable
+ */
+ol.extent.isEmpty = function(extent) {
+ return extent[2] < extent[0] || extent[3] < extent[1];
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} Is infinite.
+ */
+ol.extent.isInfinite = function(extent) {
+ return extent[0] == -Infinity || extent[1] == -Infinity ||
+ extent[2] == Infinity || extent[3] == Infinity;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ol.extent.normalize = function(extent, coordinate) {
+ return [
+ (coordinate[0] - extent[0]) / (extent[2] - extent[0]),
+ (coordinate[1] - extent[1]) / (extent[3] - extent[1])
+ ];
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} Extent.
+ */
+ol.extent.returnOrUpdate = function(extent, opt_extent) {
+ if (opt_extent) {
+ opt_extent[0] = extent[0];
+ opt_extent[1] = extent[1];
+ opt_extent[2] = extent[2];
+ opt_extent[3] = extent[3];
+ return opt_extent;
+ } else {
+ return extent;
+ }
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} value Value.
+ */
+ol.extent.scaleFromCenter = function(extent, value) {
+ var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);
+ var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);
+ extent[0] -= deltaX;
+ extent[2] += deltaX;
+ extent[1] -= deltaY;
+ extent[3] += deltaY;
+};
+
+
+/**
+ * Determine if the segment between two coordinates intersects (crosses,
+ * touches, or is contained by) the provided extent.
+ * @param {ol.Extent} extent The extent.
+ * @param {ol.Coordinate} start Segment start coordinate.
+ * @param {ol.Coordinate} end Segment end coordinate.
+ * @return {boolean} The segment intersects the extent.
+ */
+ol.extent.intersectsSegment = function(extent, start, end) {
+ var intersects = false;
+ var startRel = ol.extent.coordinateRelationship(extent, start);
+ var endRel = ol.extent.coordinateRelationship(extent, end);
+ if (startRel === ol.extent.Relationship.INTERSECTING ||
+ endRel === ol.extent.Relationship.INTERSECTING) {
+ intersects = true;
+ } else {
+ var minX = extent[0];
+ var minY = extent[1];
+ var maxX = extent[2];
+ var maxY = extent[3];
+ var startX = start[0];
+ var startY = start[1];
+ var endX = end[0];
+ var endY = end[1];
+ var slope = (endY - startY) / (endX - startX);
+ var x, y;
+ if (!!(endRel & ol.extent.Relationship.ABOVE) &&
+ !(startRel & ol.extent.Relationship.ABOVE)) {
+ // potentially intersects top
+ x = endX - ((endY - maxY) / slope);
+ intersects = x >= minX && x <= maxX;
+ }
+ if (!intersects && !!(endRel & ol.extent.Relationship.RIGHT) &&
+ !(startRel & ol.extent.Relationship.RIGHT)) {
+ // potentially intersects right
+ y = endY - ((endX - maxX) * slope);
+ intersects = y >= minY && y <= maxY;
+ }
+ if (!intersects && !!(endRel & ol.extent.Relationship.BELOW) &&
+ !(startRel & ol.extent.Relationship.BELOW)) {
+ // potentially intersects bottom
+ x = endX - ((endY - minY) / slope);
+ intersects = x >= minX && x <= maxX;
+ }
+ if (!intersects && !!(endRel & ol.extent.Relationship.LEFT) &&
+ !(startRel & ol.extent.Relationship.LEFT)) {
+ // potentially intersects left
+ y = endY - ((endX - minX) * slope);
+ intersects = y >= minY && y <= maxY;
+ }
+
+ }
+ return intersects;
+};
+
+
+/**
+ * @param {ol.Extent} extent1 Extent 1.
+ * @param {ol.Extent} extent2 Extent 2.
+ * @return {boolean} Touches.
+ */
+ol.extent.touches = function(extent1, extent2) {
+ var intersects = ol.extent.intersects(extent1, extent2);
+ return intersects &&
+ (extent1[0] == extent2[2] || extent1[2] == extent2[0] ||
+ extent1[1] == extent2[3] || extent1[3] == extent2[1]);
+};
+
+
+/**
+ * Apply a transform function to the extent.
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.TransformFunction} transformFn Transform function. Called with
+ * [minX, minY, maxX, maxY] extent coordinates.
+ * @param {ol.Extent=} opt_extent Destination extent.
+ * @return {ol.Extent} Extent.
+ * @api stable
+ */
+ol.extent.applyTransform = function(extent, transformFn, opt_extent) {
+ var coordinates = [
+ extent[0], extent[1],
+ extent[0], extent[3],
+ extent[2], extent[1],
+ extent[2], extent[3]
+ ];
+ transformFn(coordinates, coordinates, 2);
+ var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
+ var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
+ return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
+};
+
+goog.provide('ol.functions');
+
+/**
+ * Always returns true.
+ * @returns {boolean} true.
+ */
+ol.functions.TRUE = function() {
+ return true;
+};
+
+/**
+ * Always returns false.
+ * @returns {boolean} false.
+ */
+ol.functions.FALSE = function() {
+ return false;
+};
+
+/**
+ * @license
+ * Latitude/longitude spherical geodesy formulae taken from
+ * http://www.movable-type.co.uk/scripts/latlong.html
+ * Licensed under CC-BY-3.0.
+ */
+
+goog.provide('ol.Sphere');
+
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * Class to create objects that can be used with {@link
+ * ol.geom.Polygon.circular}.
+ *
+ * For example to create a sphere whose radius is equal to the semi-major
+ * axis of the WGS84 ellipsoid:
+ *
+ * ```js
+ * var wgs84Sphere= new ol.Sphere(6378137);
+ * ```
+ *
+ * @constructor
+ * @param {number} radius Radius.
+ * @api
+ */
+ol.Sphere = function(radius) {
+
+ /**
+ * @type {number}
+ */
+ this.radius = radius;
+
+};
+
+
+/**
+ * Returns the geodesic area for a list of coordinates.
+ *
+ * [Reference](http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409)
+ * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
+ * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
+ * Laboratory, Pasadena, CA, June 2007
+ *
+ * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear
+ * ring. If the ring is oriented clockwise, the area will be positive,
+ * otherwise it will be negative.
+ * @return {number} Area.
+ * @api
+ */
+ol.Sphere.prototype.geodesicArea = function(coordinates) {
+ var area = 0, len = coordinates.length;
+ var x1 = coordinates[len - 1][0];
+ var y1 = coordinates[len - 1][1];
+ for (var i = 0; i < len; i++) {
+ var x2 = coordinates[i][0], y2 = coordinates[i][1];
+ area += ol.math.toRadians(x2 - x1) *
+ (2 + Math.sin(ol.math.toRadians(y1)) +
+ Math.sin(ol.math.toRadians(y2)));
+ x1 = x2;
+ y1 = y2;
+ }
+ return area * this.radius * this.radius / 2.0;
+};
+
+
+/**
+ * Returns the distance from c1 to c2 using the haversine formula.
+ *
+ * @param {ol.Coordinate} c1 Coordinate 1.
+ * @param {ol.Coordinate} c2 Coordinate 2.
+ * @return {number} Haversine distance.
+ * @api
+ */
+ol.Sphere.prototype.haversineDistance = function(c1, c2) {
+ var lat1 = ol.math.toRadians(c1[1]);
+ var lat2 = ol.math.toRadians(c2[1]);
+ var deltaLatBy2 = (lat2 - lat1) / 2;
+ var deltaLonBy2 = ol.math.toRadians(c2[0] - c1[0]) / 2;
+ var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +
+ Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) *
+ Math.cos(lat1) * Math.cos(lat2);
+ return 2 * this.radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+};
+
+
+/**
+ * Returns the coordinate at the given distance and bearing from `c1`.
+ *
+ * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees).
+ * @param {number} distance The great-circle distance between the origin
+ * point and the target point.
+ * @param {number} bearing The bearing (in radians).
+ * @return {ol.Coordinate} The target point.
+ */
+ol.Sphere.prototype.offset = function(c1, distance, bearing) {
+ var lat1 = ol.math.toRadians(c1[1]);
+ var lon1 = ol.math.toRadians(c1[0]);
+ var dByR = distance / this.radius;
+ var lat = Math.asin(
+ Math.sin(lat1) * Math.cos(dByR) +
+ Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
+ var lon = lon1 + Math.atan2(
+ Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1),
+ Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
+ return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)];
+};
+
+goog.provide('ol.sphere.NORMAL');
+
+goog.require('ol.Sphere');
+
+
+/**
+ * The normal sphere.
+ * @const
+ * @type {ol.Sphere}
+ */
+ol.sphere.NORMAL = new ol.Sphere(6370997);
+
+goog.provide('ol.proj');
+goog.provide('ol.proj.METERS_PER_UNIT');
+goog.provide('ol.proj.Projection');
+goog.provide('ol.proj.Units');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.sphere.NORMAL');
+
+
+/**
+ * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or
+ * `'us-ft'`.
+ * @enum {string}
+ */
+ol.proj.Units = {
+ DEGREES: 'degrees',
+ FEET: 'ft',
+ METERS: 'm',
+ PIXELS: 'pixels',
+ TILE_PIXELS: 'tile-pixels',
+ USFEET: 'us-ft'
+};
+
+
+/**
+ * Meters per unit lookup table.
+ * @const
+ * @type {Object.<ol.proj.Units, number>}
+ * @api stable
+ */
+ol.proj.METERS_PER_UNIT = {};
+ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] =
+ 2 * Math.PI * ol.sphere.NORMAL.radius / 360;
+ol.proj.METERS_PER_UNIT[ol.proj.Units.FEET] = 0.3048;
+ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1;
+ol.proj.METERS_PER_UNIT[ol.proj.Units.USFEET] = 1200 / 3937;
+
+
+/**
+ * @classdesc
+ * Projection definition class. One of these is created for each projection
+ * supported in the application and stored in the {@link ol.proj} namespace.
+ * You can use these in applications, but this is not required, as API params
+ * and options use {@link ol.ProjectionLike} which means the simple string
+ * code will suffice.
+ *
+ * You can use {@link ol.proj.get} to retrieve the object for a particular
+ * projection.
+ *
+ * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together
+ * with the following aliases:
+ * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326,
+ * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84,
+ * http://www.opengis.net/gml/srs/epsg.xml#4326,
+ * urn:x-ogc:def:crs:EPSG:4326
+ * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913,
+ * urn:ogc:def:crs:EPSG:6.18:3:3857,
+ * http://www.opengis.net/gml/srs/epsg.xml#3857
+ *
+ * If you use proj4js, aliases can be added using `proj4.defs()`; see
+ * [documentation](https://github.com/proj4js/proj4js). To set an alternative
+ * namespace for proj4, use {@link ol.proj.setProj4}.
+ *
+ * @constructor
+ * @param {olx.ProjectionOptions} options Projection options.
+ * @struct
+ * @api stable
+ */
+ol.proj.Projection = function(options) {
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.code_ = options.code;
+
+ /**
+ * @private
+ * @type {ol.proj.Units}
+ */
+ this.units_ = /** @type {ol.proj.Units} */ (options.units);
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.extent_ = options.extent !== undefined ? options.extent : null;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.worldExtent_ = options.worldExtent !== undefined ?
+ options.worldExtent : null;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.axisOrientation_ = options.axisOrientation !== undefined ?
+ options.axisOrientation : 'enu';
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.global_ = options.global !== undefined ? options.global : false;
+
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.canWrapX_ = !!(this.global_ && this.extent_);
+
+ /**
+ * @private
+ * @type {function(number, ol.Coordinate):number}
+ */
+ this.getPointResolutionFunc_ = options.getPointResolution !== undefined ?
+ options.getPointResolution : this.getPointResolution_;
+
+ /**
+ * @private
+ * @type {ol.tilegrid.TileGrid}
+ */
+ this.defaultTileGrid_ = null;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.metersPerUnit_ = options.metersPerUnit;
+
+ var projections = ol.proj.projections_;
+ var code = options.code;
+ goog.asserts.assert(code !== undefined,
+ 'Option "code" is required for constructing instance');
+ if (ol.ENABLE_PROJ4JS) {
+ var proj4js = ol.proj.proj4_ || ol.global['proj4'];
+ if (typeof proj4js == 'function' && projections[code] === undefined) {
+ var def = proj4js.defs(code);
+ if (def !== undefined) {
+ if (def.axis !== undefined && options.axisOrientation === undefined) {
+ this.axisOrientation_ = def.axis;
+ }
+ if (options.metersPerUnit === undefined) {
+ this.metersPerUnit_ = def.to_meter;
+ }
+ if (options.units === undefined) {
+ this.units_ = def.units;
+ }
+ var currentCode, currentDef, currentProj, proj4Transform;
+ for (currentCode in projections) {
+ currentDef = proj4js.defs(currentCode);
+ if (currentDef !== undefined) {
+ currentProj = ol.proj.get(currentCode);
+ if (currentDef === def) {
+ ol.proj.addEquivalentProjections([currentProj, this]);
+ } else {
+ proj4Transform = proj4js(currentCode, code);
+ ol.proj.addCoordinateTransforms(currentProj, this,
+ proj4Transform.forward, proj4Transform.inverse);
+ }
+ }
+ }
+ }
+ }
+ }
+
+};
+
+
+/**
+ * @return {boolean} The projection is suitable for wrapping the x-axis
+ */
+ol.proj.Projection.prototype.canWrapX = function() {
+ return this.canWrapX_;
+};
+
+
+/**
+ * Get the code for this projection, e.g. 'EPSG:4326'.
+ * @return {string} Code.
+ * @api stable
+ */
+ol.proj.Projection.prototype.getCode = function() {
+ return this.code_;
+};
+
+
+/**
+ * Get the validity extent for this projection.
+ * @return {ol.Extent} Extent.
+ * @api stable
+ */
+ol.proj.Projection.prototype.getExtent = function() {
+ return this.extent_;
+};
+
+
+/**
+ * Get the units of this projection.
+ * @return {ol.proj.Units} Units.
+ * @api stable
+ */
+ol.proj.Projection.prototype.getUnits = function() {
+ return this.units_;
+};
+
+
+/**
+ * Get the amount of meters per unit of this projection. If the projection is
+ * not configured with `metersPerUnit` or a units identifier, the return is
+ * `undefined`.
+ * @return {number|undefined} Meters.
+ * @api stable
+ */
+ol.proj.Projection.prototype.getMetersPerUnit = function() {
+ return this.metersPerUnit_ || ol.proj.METERS_PER_UNIT[this.units_];
+};
+
+
+/**
+ * Get the world extent for this projection.
+ * @return {ol.Extent} Extent.
+ * @api
+ */
+ol.proj.Projection.prototype.getWorldExtent = function() {
+ return this.worldExtent_;
+};
+
+
+/**
+ * Get the axis orientation of this projection.
+ * Example values are:
+ * enu - the default easting, northing, elevation.
+ * neu - northing, easting, up - useful for "lat/long" geographic coordinates,
+ * or south orientated transverse mercator.
+ * wnu - westing, northing, up - some planetary coordinate systems have
+ * "west positive" coordinate systems
+ * @return {string} Axis orientation.
+ */
+ol.proj.Projection.prototype.getAxisOrientation = function() {
+ return this.axisOrientation_;
+};
+
+
+/**
+ * Is this projection a global projection which spans the whole world?
+ * @return {boolean} Whether the projection is global.
+ * @api stable
+ */
+ol.proj.Projection.prototype.isGlobal = function() {
+ return this.global_;
+};
+
+
+/**
+* Set if the projection is a global projection which spans the whole world
+* @param {boolean} global Whether the projection is global.
+* @api stable
+*/
+ol.proj.Projection.prototype.setGlobal = function(global) {
+ this.global_ = global;
+ this.canWrapX_ = !!(global && this.extent_);
+};
+
+
+/**
+ * @return {ol.tilegrid.TileGrid} The default tile grid.
+ */
+ol.proj.Projection.prototype.getDefaultTileGrid = function() {
+ return this.defaultTileGrid_;
+};
+
+
+/**
+ * @param {ol.tilegrid.TileGrid} tileGrid The default tile grid.
+ */
+ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) {
+ this.defaultTileGrid_ = tileGrid;
+};
+
+
+/**
+ * Set the validity extent for this projection.
+ * @param {ol.Extent} extent Extent.
+ * @api stable
+ */
+ol.proj.Projection.prototype.setExtent = function(extent) {
+ this.extent_ = extent;
+ this.canWrapX_ = !!(this.global_ && extent);
+};
+
+
+/**
+ * Set the world extent for this projection.
+ * @param {ol.Extent} worldExtent World extent
+ * [minlon, minlat, maxlon, maxlat].
+ * @api
+ */
+ol.proj.Projection.prototype.setWorldExtent = function(worldExtent) {
+ this.worldExtent_ = worldExtent;
+};
+
+
+/**
+* Set the getPointResolution function for this projection.
+* @param {function(number, ol.Coordinate):number} func Function
+* @api
+*/
+ol.proj.Projection.prototype.setGetPointResolution = function(func) {
+ this.getPointResolutionFunc_ = func;
+};
+
+
+/**
+* Default version.
+* Get the resolution of the point in degrees or distance units.
+* For projections with degrees as the unit this will simply return the
+* provided resolution. For other projections the point resolution is
+* estimated by transforming the 'point' pixel to EPSG:4326,
+* measuring its width and height on the normal sphere,
+* and taking the average of the width and height.
+* @param {number} resolution Nominal resolution in projection units.
+* @param {ol.Coordinate} point Point to find adjusted resolution at.
+* @return {number} Point resolution at point in projection units.
+* @private
+*/
+ol.proj.Projection.prototype.getPointResolution_ = function(resolution, point) {
+ var units = this.getUnits();
+ if (units == ol.proj.Units.DEGREES) {
+ return resolution;
+ } else {
+ // Estimate point resolution by transforming the center pixel to EPSG:4326,
+ // measuring its width and height on the normal sphere, and taking the
+ // average of the width and height.
+ var toEPSG4326 = ol.proj.getTransformFromProjections(
+ this, ol.proj.get('EPSG:4326'));
+ var vertices = [
+ point[0] - resolution / 2, point[1],
+ point[0] + resolution / 2, point[1],
+ point[0], point[1] - resolution / 2,
+ point[0], point[1] + resolution / 2
+ ];
+ vertices = toEPSG4326(vertices, vertices, 2);
+ var width = ol.sphere.NORMAL.haversineDistance(
+ vertices.slice(0, 2), vertices.slice(2, 4));
+ var height = ol.sphere.NORMAL.haversineDistance(
+ vertices.slice(4, 6), vertices.slice(6, 8));
+ var pointResolution = (width + height) / 2;
+ var metersPerUnit = this.getMetersPerUnit();
+ if (metersPerUnit !== undefined) {
+ pointResolution /= metersPerUnit;
+ }
+ return pointResolution;
+ }
+};
+
+
+/**
+ * Get the resolution of the point in degrees or distance units.
+ * For projections with degrees as the unit this will simply return the
+ * provided resolution. The default for other projections is to estimate
+ * the point resolution by transforming the 'point' pixel to EPSG:4326,
+ * measuring its width and height on the normal sphere,
+ * and taking the average of the width and height.
+ * An alternative implementation may be given when constructing a
+ * projection. For many local projections,
+ * such a custom function will return the resolution unchanged.
+ * @param {number} resolution Resolution in projection units.
+ * @param {ol.Coordinate} point Point.
+ * @return {number} Point resolution in projection units.
+ * @api
+ */
+ol.proj.Projection.prototype.getPointResolution = function(resolution, point) {
+ return this.getPointResolutionFunc_(resolution, point);
+};
+
+
+/**
+ * @private
+ * @type {Object.<string, ol.proj.Projection>}
+ */
+ol.proj.projections_ = {};
+
+
+/**
+ * @private
+ * @type {Object.<string, Object.<string, ol.TransformFunction>>}
+ */
+ol.proj.transforms_ = {};
+
+
+/**
+ * @private
+ * @type {proj4}
+ */
+ol.proj.proj4_ = null;
+
+
+if (ol.ENABLE_PROJ4JS) {
+ /**
+ * Register proj4. If not explicitly registered, it will be assumed that
+ * proj4js will be loaded in the global namespace. For example in a
+ * browserify ES6 environment you could use:
+ *
+ * import ol from 'openlayers';
+ * import proj4 from 'proj4';
+ * ol.proj.setProj4(proj4);
+ *
+ * @param {proj4} proj4 Proj4.
+ * @api
+ */
+ ol.proj.setProj4 = function(proj4) {
+ goog.asserts.assert(typeof proj4 == 'function',
+ 'proj4 argument should be a function');
+ ol.proj.proj4_ = proj4;
+ };
+}
+
+
+/**
+ * Registers transformation functions that don't alter coordinates. Those allow
+ * to transform between projections with equal meaning.
+ *
+ * @param {Array.<ol.proj.Projection>} projections Projections.
+ * @api
+ */
+ol.proj.addEquivalentProjections = function(projections) {
+ ol.proj.addProjections(projections);
+ projections.forEach(function(source) {
+ projections.forEach(function(destination) {
+ if (source !== destination) {
+ ol.proj.addTransform(source, destination, ol.proj.cloneTransform);
+ }
+ });
+ });
+};
+
+
+/**
+ * Registers transformation functions to convert coordinates in any projection
+ * in projection1 to any projection in projection2.
+ *
+ * @param {Array.<ol.proj.Projection>} projections1 Projections with equal
+ * meaning.
+ * @param {Array.<ol.proj.Projection>} projections2 Projections with equal
+ * meaning.
+ * @param {ol.TransformFunction} forwardTransform Transformation from any
+ * projection in projection1 to any projection in projection2.
+ * @param {ol.TransformFunction} inverseTransform Transform from any projection
+ * in projection2 to any projection in projection1..
+ */
+ol.proj.addEquivalentTransforms = function(projections1, projections2, forwardTransform, inverseTransform) {
+ projections1.forEach(function(projection1) {
+ projections2.forEach(function(projection2) {
+ ol.proj.addTransform(projection1, projection2, forwardTransform);
+ ol.proj.addTransform(projection2, projection1, inverseTransform);
+ });
+ });
+};
+
+
+/**
+ * Add a Projection object to the list of supported projections that can be
+ * looked up by their code.
+ *
+ * @param {ol.proj.Projection} projection Projection instance.
+ * @api stable
+ */
+ol.proj.addProjection = function(projection) {
+ ol.proj.projections_[projection.getCode()] = projection;
+ ol.proj.addTransform(projection, projection, ol.proj.cloneTransform);
+};
+
+
+/**
+ * @param {Array.<ol.proj.Projection>} projections Projections.
+ */
+ol.proj.addProjections = function(projections) {
+ var addedProjections = [];
+ projections.forEach(function(projection) {
+ addedProjections.push(ol.proj.addProjection(projection));
+ });
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.proj.clearAllProjections = function() {
+ ol.proj.projections_ = {};
+ ol.proj.transforms_ = {};
+};
+
+
+/**
+ * @param {ol.proj.Projection|string|undefined} projection Projection.
+ * @param {string} defaultCode Default code.
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.proj.createProjection = function(projection, defaultCode) {
+ if (!projection) {
+ return ol.proj.get(defaultCode);
+ } else if (typeof projection === 'string') {
+ return ol.proj.get(projection);
+ } else {
+ goog.asserts.assertInstanceof(projection, ol.proj.Projection,
+ 'projection should be an ol.proj.Projection');
+ return projection;
+ }
+};
+
+
+/**
+ * Registers a conversion function to convert coordinates from the source
+ * projection to the destination projection.
+ *
+ * @param {ol.proj.Projection} source Source.
+ * @param {ol.proj.Projection} destination Destination.
+ * @param {ol.TransformFunction} transformFn Transform.
+ */
+ol.proj.addTransform = function(source, destination, transformFn) {
+ var sourceCode = source.getCode();
+ var destinationCode = destination.getCode();
+ var transforms = ol.proj.transforms_;
+ if (!(sourceCode in transforms)) {
+ transforms[sourceCode] = {};
+ }
+ transforms[sourceCode][destinationCode] = transformFn;
+};
+
+
+/**
+ * Registers coordinate transform functions to convert coordinates between the
+ * source projection and the destination projection.
+ * The forward and inverse functions convert coordinate pairs; this function
+ * converts these into the functions used internally which also handle
+ * extents and coordinate arrays.
+ *
+ * @param {ol.ProjectionLike} source Source projection.
+ * @param {ol.ProjectionLike} destination Destination projection.
+ * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform
+ * function (that is, from the source projection to the destination
+ * projection) that takes a {@link ol.Coordinate} as argument and returns
+ * the transformed {@link ol.Coordinate}.
+ * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform
+ * function (that is, from the destination projection to the source
+ * projection) that takes a {@link ol.Coordinate} as argument and returns
+ * the transformed {@link ol.Coordinate}.
+ * @api stable
+ */
+ol.proj.addCoordinateTransforms = function(source, destination, forward, inverse) {
+ var sourceProj = ol.proj.get(source);
+ var destProj = ol.proj.get(destination);
+ ol.proj.addTransform(sourceProj, destProj,
+ ol.proj.createTransformFromCoordinateTransform(forward));
+ ol.proj.addTransform(destProj, sourceProj,
+ ol.proj.createTransformFromCoordinateTransform(inverse));
+};
+
+
+/**
+ * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform
+ * function.
+ * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate
+ * transform.
+ * @return {ol.TransformFunction} Transform function.
+ */
+ol.proj.createTransformFromCoordinateTransform = function(transform) {
+ return (
+ /**
+ * @param {Array.<number>} input Input.
+ * @param {Array.<number>=} opt_output Output.
+ * @param {number=} opt_dimension Dimension.
+ * @return {Array.<number>} Output.
+ */
+ function(input, opt_output, opt_dimension) {
+ var length = input.length;
+ var dimension = opt_dimension !== undefined ? opt_dimension : 2;
+ var output = opt_output !== undefined ? opt_output : new Array(length);
+ var point, i, j;
+ for (i = 0; i < length; i += dimension) {
+ point = transform([input[i], input[i + 1]]);
+ output[i] = point[0];
+ output[i + 1] = point[1];
+ for (j = dimension - 1; j >= 2; --j) {
+ output[i + j] = input[i + j];
+ }
+ }
+ return output;
+ });
+};
+
+
+/**
+ * Unregisters the conversion function to convert coordinates from the source
+ * projection to the destination projection. This method is used to clean up
+ * cached transforms during testing.
+ *
+ * @param {ol.proj.Projection} source Source projection.
+ * @param {ol.proj.Projection} destination Destination projection.
+ * @return {ol.TransformFunction} transformFn The unregistered transform.
+ */
+ol.proj.removeTransform = function(source, destination) {
+ var sourceCode = source.getCode();
+ var destinationCode = destination.getCode();
+ var transforms = ol.proj.transforms_;
+ goog.asserts.assert(sourceCode in transforms,
+ 'sourceCode should be in transforms');
+ goog.asserts.assert(destinationCode in transforms[sourceCode],
+ 'destinationCode should be in transforms of sourceCode');
+ var transform = transforms[sourceCode][destinationCode];
+ delete transforms[sourceCode][destinationCode];
+ if (ol.object.isEmpty(transforms[sourceCode])) {
+ delete transforms[sourceCode];
+ }
+ return transform;
+};
+
+
+/**
+ * Transforms a coordinate from longitude/latitude to a different projection.
+ * @param {ol.Coordinate} coordinate Coordinate as longitude and latitude, i.e.
+ * an array with longitude as 1st and latitude as 2nd element.
+ * @param {ol.ProjectionLike=} opt_projection Target projection. The
+ * default is Web Mercator, i.e. 'EPSG:3857'.
+ * @return {ol.Coordinate} Coordinate projected to the target projection.
+ * @api stable
+ */
+ol.proj.fromLonLat = function(coordinate, opt_projection) {
+ return ol.proj.transform(coordinate, 'EPSG:4326',
+ opt_projection !== undefined ? opt_projection : 'EPSG:3857');
+};
+
+
+/**
+ * Transforms a coordinate to longitude/latitude.
+ * @param {ol.Coordinate} coordinate Projected coordinate.
+ * @param {ol.ProjectionLike=} opt_projection Projection of the coordinate.
+ * The default is Web Mercator, i.e. 'EPSG:3857'.
+ * @return {ol.Coordinate} Coordinate as longitude and latitude, i.e. an array
+ * with longitude as 1st and latitude as 2nd element.
+ * @api stable
+ */
+ol.proj.toLonLat = function(coordinate, opt_projection) {
+ return ol.proj.transform(coordinate,
+ opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326');
+};
+
+
+/**
+ * Fetches a Projection object for the code specified.
+ *
+ * @param {ol.ProjectionLike} projectionLike Either a code string which is
+ * a combination of authority and identifier such as "EPSG:4326", or an
+ * existing projection object, or undefined.
+ * @return {ol.proj.Projection} Projection object, or null if not in list.
+ * @api stable
+ */
+ol.proj.get = function(projectionLike) {
+ var projection;
+ if (projectionLike instanceof ol.proj.Projection) {
+ projection = projectionLike;
+ } else if (typeof projectionLike === 'string') {
+ var code = projectionLike;
+ projection = ol.proj.projections_[code];
+ if (ol.ENABLE_PROJ4JS) {
+ var proj4js = ol.proj.proj4_ || ol.global['proj4'];
+ if (projection === undefined && typeof proj4js == 'function' &&
+ proj4js.defs(code) !== undefined) {
+ projection = new ol.proj.Projection({code: code});
+ ol.proj.addProjection(projection);
+ }
+ }
+ } else {
+ projection = null;
+ }
+ return projection;
+};
+
+
+/**
+ * Checks if two projections are the same, that is every coordinate in one
+ * projection does represent the same geographic point as the same coordinate in
+ * the other projection.
+ *
+ * @param {ol.proj.Projection} projection1 Projection 1.
+ * @param {ol.proj.Projection} projection2 Projection 2.
+ * @return {boolean} Equivalent.
+ * @api
+ */
+ol.proj.equivalent = function(projection1, projection2) {
+ if (projection1 === projection2) {
+ return true;
+ }
+ var equalUnits = projection1.getUnits() === projection2.getUnits();
+ if (projection1.getCode() === projection2.getCode()) {
+ return equalUnits;
+ } else {
+ var transformFn = ol.proj.getTransformFromProjections(
+ projection1, projection2);
+ return transformFn === ol.proj.cloneTransform && equalUnits;
+ }
+};
+
+
+/**
+ * Given the projection-like objects, searches for a transformation
+ * function to convert a coordinates array from the source projection to the
+ * destination projection.
+ *
+ * @param {ol.ProjectionLike} source Source.
+ * @param {ol.ProjectionLike} destination Destination.
+ * @return {ol.TransformFunction} Transform function.
+ * @api stable
+ */
+ol.proj.getTransform = function(source, destination) {
+ var sourceProjection = ol.proj.get(source);
+ var destinationProjection = ol.proj.get(destination);
+ return ol.proj.getTransformFromProjections(
+ sourceProjection, destinationProjection);
+};
+
+
+/**
+ * Searches in the list of transform functions for the function for converting
+ * coordinates from the source projection to the destination projection.
+ *
+ * @param {ol.proj.Projection} sourceProjection Source Projection object.
+ * @param {ol.proj.Projection} destinationProjection Destination Projection
+ * object.
+ * @return {ol.TransformFunction} Transform function.
+ */
+ol.proj.getTransformFromProjections = function(sourceProjection, destinationProjection) {
+ var transforms = ol.proj.transforms_;
+ var sourceCode = sourceProjection.getCode();
+ var destinationCode = destinationProjection.getCode();
+ var transform;
+ if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {
+ transform = transforms[sourceCode][destinationCode];
+ }
+ if (transform === undefined) {
+ goog.asserts.assert(transform !== undefined, 'transform should be defined');
+ transform = ol.proj.identityTransform;
+ }
+ return transform;
+};
+
+
+/**
+ * @param {Array.<number>} input Input coordinate array.
+ * @param {Array.<number>=} opt_output Output array of coordinate values.
+ * @param {number=} opt_dimension Dimension.
+ * @return {Array.<number>} Input coordinate array (same array as input).
+ */
+ol.proj.identityTransform = function(input, opt_output, opt_dimension) {
+ if (opt_output !== undefined && input !== opt_output) {
+ // TODO: consider making this a warning instead
+ goog.asserts.fail('This should not be used internally.');
+ for (var i = 0, ii = input.length; i < ii; ++i) {
+ opt_output[i] = input[i];
+ }
+ input = opt_output;
+ }
+ return input;
+};
+
+
+/**
+ * @param {Array.<number>} input Input coordinate array.
+ * @param {Array.<number>=} opt_output Output array of coordinate values.
+ * @param {number=} opt_dimension Dimension.
+ * @return {Array.<number>} Output coordinate array (new array, same coordinate
+ * values).
+ */
+ol.proj.cloneTransform = function(input, opt_output, opt_dimension) {
+ var output;
+ if (opt_output !== undefined) {
+ for (var i = 0, ii = input.length; i < ii; ++i) {
+ opt_output[i] = input[i];
+ }
+ output = opt_output;
+ } else {
+ output = input.slice();
+ }
+ return output;
+};
+
+
+/**
+ * Transforms a coordinate from source projection to destination projection.
+ * This returns a new coordinate (and does not modify the original).
+ *
+ * See {@link ol.proj.transformExtent} for extent transformation.
+ * See the transform method of {@link ol.geom.Geometry} and its subclasses for
+ * geometry transforms.
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.ProjectionLike} source Source projection-like.
+ * @param {ol.ProjectionLike} destination Destination projection-like.
+ * @return {ol.Coordinate} Coordinate.
+ * @api stable
+ */
+ol.proj.transform = function(coordinate, source, destination) {
+ var transformFn = ol.proj.getTransform(source, destination);
+ return transformFn(coordinate, undefined, coordinate.length);
+};
+
+
+/**
+ * Transforms an extent from source projection to destination projection. This
+ * returns a new extent (and does not modify the original).
+ *
+ * @param {ol.Extent} extent The extent to transform.
+ * @param {ol.ProjectionLike} source Source projection-like.
+ * @param {ol.ProjectionLike} destination Destination projection-like.
+ * @return {ol.Extent} The transformed extent.
+ * @api stable
+ */
+ol.proj.transformExtent = function(extent, source, destination) {
+ var transformFn = ol.proj.getTransform(source, destination);
+ return ol.extent.applyTransform(extent, transformFn);
+};
+
+
+/**
+ * Transforms the given point to the destination projection.
+ *
+ * @param {ol.Coordinate} point Point.
+ * @param {ol.proj.Projection} sourceProjection Source projection.
+ * @param {ol.proj.Projection} destinationProjection Destination projection.
+ * @return {ol.Coordinate} Point.
+ */
+ol.proj.transformWithProjections = function(point, sourceProjection, destinationProjection) {
+ var transformFn = ol.proj.getTransformFromProjections(
+ sourceProjection, destinationProjection);
+ return transformFn(point);
+};
+
+goog.provide('ol.geom.Geometry');
+goog.provide('ol.geom.GeometryLayout');
+goog.provide('ol.geom.GeometryType');
+
+goog.require('goog.asserts');
+goog.require('ol.functions');
+goog.require('ol.Object');
+goog.require('ol.extent');
+goog.require('ol.proj');
+goog.require('ol.proj.Units');
+
+
+/**
+ * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,
+ * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,
+ * `'GeometryCollection'`, `'Circle'`.
+ * @enum {string}
+ */
+ol.geom.GeometryType = {
+ POINT: 'Point',
+ LINE_STRING: 'LineString',
+ LINEAR_RING: 'LinearRing',
+ POLYGON: 'Polygon',
+ MULTI_POINT: 'MultiPoint',
+ MULTI_LINE_STRING: 'MultiLineString',
+ MULTI_POLYGON: 'MultiPolygon',
+ GEOMETRY_COLLECTION: 'GeometryCollection',
+ CIRCLE: 'Circle'
+};
+
+
+/**
+ * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')
+ * or measure ('M') coordinate is available. Supported values are `'XY'`,
+ * `'XYZ'`, `'XYM'`, `'XYZM'`.
+ * @enum {string}
+ */
+ol.geom.GeometryLayout = {
+ XY: 'XY',
+ XYZ: 'XYZ',
+ XYM: 'XYM',
+ XYZM: 'XYZM'
+};
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for vector geometries.
+ *
+ * To get notified of changes to the geometry, register a listener for the
+ * generic `change` event on your geometry instance.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @api stable
+ */
+ol.geom.Geometry = function() {
+
+ ol.Object.call(this);
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.extent_ = ol.extent.createEmpty();
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.extentRevision_ = -1;
+
+ /**
+ * @protected
+ * @type {Object.<string, ol.geom.Geometry>}
+ */
+ this.simplifiedGeometryCache = {};
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.simplifiedGeometryMaxMinSquaredTolerance = 0;
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.simplifiedGeometryRevision = 0;
+
+};
+ol.inherits(ol.geom.Geometry, ol.Object);
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @function
+ * @return {!ol.geom.Geometry} Clone.
+ */
+ol.geom.Geometry.prototype.clone = goog.abstractMethod;
+
+
+/**
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {ol.Coordinate} closestPoint Closest point.
+ * @param {number} minSquaredDistance Minimum squared distance.
+ * @return {number} Minimum squared distance.
+ */
+ol.geom.Geometry.prototype.closestPointXY = goog.abstractMethod;
+
+
+/**
+ * Return the closest point of the geometry to the passed point as
+ * {@link ol.Coordinate coordinate}.
+ * @param {ol.Coordinate} point Point.
+ * @param {ol.Coordinate=} opt_closestPoint Closest point.
+ * @return {ol.Coordinate} Closest point.
+ * @api stable
+ */
+ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {
+ var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];
+ this.closestPointXY(point[0], point[1], closestPoint, Infinity);
+ return closestPoint;
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {boolean} Contains coordinate.
+ */
+ol.geom.Geometry.prototype.containsCoordinate = function(coordinate) {
+ return this.containsXY(coordinate[0], coordinate[1]);
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @protected
+ * @return {ol.Extent} extent Extent.
+ */
+ol.geom.Geometry.prototype.computeExtent = goog.abstractMethod;
+
+
+/**
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {boolean} Contains (x, y).
+ */
+ol.geom.Geometry.prototype.containsXY = ol.functions.FALSE;
+
+
+/**
+ * Get the extent of the geometry.
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {ol.Extent} extent Extent.
+ * @api stable
+ */
+ol.geom.Geometry.prototype.getExtent = function(opt_extent) {
+ if (this.extentRevision_ != this.getRevision()) {
+ this.extent_ = this.computeExtent(this.extent_);
+ this.extentRevision_ = this.getRevision();
+ }
+ return ol.extent.returnOrUpdate(this.extent_, opt_extent);
+};
+
+
+/**
+ * Rotate the geometry around a given coordinate. This modifies the geometry
+ * coordinates in place.
+ * @param {number} angle Rotation angle in radians.
+ * @param {ol.Coordinate} anchor The rotation center.
+ * @api
+ * @function
+ */
+ol.geom.Geometry.prototype.rotate = goog.abstractMethod;
+
+
+/**
+ * Create a simplified version of this geometry. For linestrings, this uses
+ * the the {@link
+ * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ * Douglas Peucker} algorithm. For polygons, a quantization-based
+ * simplification is used to preserve topology.
+ * @function
+ * @param {number} tolerance The tolerance distance for simplification.
+ * @return {ol.geom.Geometry} A new, simplified version of the original
+ * geometry.
+ * @api
+ */
+ol.geom.Geometry.prototype.simplify = function(tolerance) {
+ return this.getSimplifiedGeometry(tolerance * tolerance);
+};
+
+
+/**
+ * Create a simplified version of this geometry using the Douglas Peucker
+ * algorithm.
+ * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ * @function
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {ol.geom.Geometry} Simplified geometry.
+ */
+ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod;
+
+
+/**
+ * Get the type of this geometry.
+ * @function
+ * @return {ol.geom.GeometryType} Geometry type.
+ */
+ol.geom.Geometry.prototype.getType = goog.abstractMethod;
+
+
+/**
+ * Apply a transform function to each coordinate of the geometry.
+ * The geometry is modified in place.
+ * If you do not want the geometry modified in place, first `clone()` it and
+ * then use this function on the clone.
+ * @function
+ * @param {ol.TransformFunction} transformFn Transform.
+ */
+ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod;
+
+
+/**
+ * Test if the geometry and the passed extent intersect.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} `true` if the geometry and the extent intersect.
+ * @function
+ */
+ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod;
+
+
+/**
+ * Translate the geometry. This modifies the geometry coordinates in place. If
+ * instead you want a new geometry, first `clone()` this geometry.
+ * @param {number} deltaX Delta X.
+ * @param {number} deltaY Delta Y.
+ * @function
+ */
+ol.geom.Geometry.prototype.translate = goog.abstractMethod;
+
+
+/**
+ * Transform each coordinate of the geometry from one coordinate reference
+ * system to another. The geometry is modified in place.
+ * For example, a line will be transformed to a line and a circle to a circle.
+ * If you do not want the geometry modified in place, first `clone()` it and
+ * then use this function on the clone.
+ *
+ * @param {ol.ProjectionLike} source The current projection. Can be a
+ * string identifier or a {@link ol.proj.Projection} object.
+ * @param {ol.ProjectionLike} destination The desired projection. Can be a
+ * string identifier or a {@link ol.proj.Projection} object.
+ * @return {ol.geom.Geometry} This geometry. Note that original geometry is
+ * modified in place.
+ * @api stable
+ */
+ol.geom.Geometry.prototype.transform = function(source, destination) {
+ goog.asserts.assert(
+ ol.proj.get(source).getUnits() !== ol.proj.Units.TILE_PIXELS &&
+ ol.proj.get(destination).getUnits() !== ol.proj.Units.TILE_PIXELS,
+ 'cannot transform geometries with TILE_PIXELS units');
+ this.applyTransform(ol.proj.getTransform(source, destination));
+ return this;
+};
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Supplies a Float32Array implementation that implements
+ * most of the Float32Array spec and that can be used when a built-in
+ * implementation is not available.
+ *
+ * Note that if no existing Float32Array implementation is found then
+ * this class and all its public properties are exported as Float32Array.
+ *
+ * Adding support for the other TypedArray classes here does not make sense
+ * since this vector math library only needs Float32Array.
+ *
+ */
+goog.provide('goog.vec.Float32Array');
+
+
+
+/**
+ * Constructs a new Float32Array. The new array is initialized to all zeros.
+ *
+ * @param {goog.vec.Float32Array|Array|ArrayBuffer|number} p0
+ * The length of the array, or an array to initialize the contents of the
+ * new Float32Array.
+ * @constructor
+ * @implements {IArrayLike<number>}
+ * @final
+ */
+goog.vec.Float32Array = function(p0) {
+ this.length = /** @type {number} */ (p0.length || p0);
+ for (var i = 0; i < this.length; i++) {
+ this[i] = p0[i] || 0;
+ }
+};
+
+
+/**
+ * The number of bytes in an element (as defined by the Typed Array
+ * specification).
+ *
+ * @type {number}
+ */
+goog.vec.Float32Array.BYTES_PER_ELEMENT = 4;
+
+
+/**
+ * The number of bytes in an element (as defined by the Typed Array
+ * specification).
+ *
+ * @type {number}
+ */
+goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT = 4;
+
+
+/**
+ * Sets elements of the array.
+ * @param {Array<number>|Float32Array} values The array of values.
+ * @param {number=} opt_offset The offset in this array to start.
+ */
+goog.vec.Float32Array.prototype.set = function(values, opt_offset) {
+ opt_offset = opt_offset || 0;
+ for (var i = 0; i < values.length && opt_offset + i < this.length; i++) {
+ this[opt_offset + i] = values[i];
+ }
+};
+
+
+/**
+ * Creates a string representation of this array.
+ * @return {string} The string version of this array.
+ * @override
+ */
+goog.vec.Float32Array.prototype.toString = Array.prototype.join;
+
+
+/**
+ * Note that we cannot implement the subarray() or (deprecated) slice()
+ * methods properly since doing so would require being able to overload
+ * the [] operator which is not possible in javascript. So we leave
+ * them unimplemented. Any attempt to call these methods will just result
+ * in a javascript error since we leave them undefined.
+ */
+
+
+/**
+ * If no existing Float32Array implementation is found then we export
+ * goog.vec.Float32Array as Float32Array.
+ */
+if (typeof Float32Array == 'undefined') {
+ goog.exportProperty(
+ goog.vec.Float32Array, 'BYTES_PER_ELEMENT',
+ goog.vec.Float32Array.BYTES_PER_ELEMENT);
+ goog.exportProperty(
+ goog.vec.Float32Array.prototype, 'BYTES_PER_ELEMENT',
+ goog.vec.Float32Array.prototype.BYTES_PER_ELEMENT);
+ goog.exportProperty(
+ goog.vec.Float32Array.prototype, 'set',
+ goog.vec.Float32Array.prototype.set);
+ goog.exportProperty(
+ goog.vec.Float32Array.prototype, 'toString',
+ goog.vec.Float32Array.prototype.toString);
+ goog.exportSymbol('Float32Array', goog.vec.Float32Array);
+}
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Supplies a Float64Array implementation that implements
+ * most of the Float64Array spec and that can be used when a built-in
+ * implementation is not available.
+ *
+ * Note that if no existing Float64Array implementation is found then this
+ * class and all its public properties are exported as Float64Array.
+ *
+ * Adding support for the other TypedArray classes here does not make sense
+ * since this vector math library only needs Float32Array and Float64Array.
+ *
+ */
+goog.provide('goog.vec.Float64Array');
+
+
+
+/**
+ * Constructs a new Float64Array. The new array is initialized to all zeros.
+ *
+ * @param {goog.vec.Float64Array|Array|ArrayBuffer|number} p0
+ * The length of the array, or an array to initialize the contents of the
+ * new Float64Array.
+ * @constructor
+ * @implements {IArrayLike<number>}
+ * @final
+ */
+goog.vec.Float64Array = function(p0) {
+ this.length = /** @type {number} */ (p0.length || p0);
+ for (var i = 0; i < this.length; i++) {
+ this[i] = p0[i] || 0;
+ }
+};
+
+
+/**
+ * The number of bytes in an element (as defined by the Typed Array
+ * specification).
+ *
+ * @type {number}
+ */
+goog.vec.Float64Array.BYTES_PER_ELEMENT = 8;
+
+
+/**
+ * The number of bytes in an element (as defined by the Typed Array
+ * specification).
+ *
+ * @type {number}
+ */
+goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT = 8;
+
+
+/**
+ * Sets elements of the array.
+ * @param {Array<number>|Float64Array} values The array of values.
+ * @param {number=} opt_offset The offset in this array to start.
+ */
+goog.vec.Float64Array.prototype.set = function(values, opt_offset) {
+ opt_offset = opt_offset || 0;
+ for (var i = 0; i < values.length && opt_offset + i < this.length; i++) {
+ this[opt_offset + i] = values[i];
+ }
+};
+
+
+/**
+ * Creates a string representation of this array.
+ * @return {string} The string version of this array.
+ * @override
+ */
+goog.vec.Float64Array.prototype.toString = Array.prototype.join;
+
+
+/**
+ * Note that we cannot implement the subarray() or (deprecated) slice()
+ * methods properly since doing so would require being able to overload
+ * the [] operator which is not possible in javascript. So we leave
+ * them unimplemented. Any attempt to call these methods will just result
+ * in a javascript error since we leave them undefined.
+ */
+
+
+/**
+ * If no existing Float64Array implementation is found then we export
+ * goog.vec.Float64Array as Float64Array.
+ */
+if (typeof Float64Array == 'undefined') {
+ try {
+ goog.exportProperty(
+ goog.vec.Float64Array, 'BYTES_PER_ELEMENT',
+ goog.vec.Float64Array.BYTES_PER_ELEMENT);
+ } catch (float64ArrayError) {
+ // Do nothing. This code is in place to fix b/7225850, in which an error
+ // is incorrectly thrown for Google TV on an old Chrome.
+ // TODO(user): remove after that version is retired.
+ }
+
+ goog.exportProperty(
+ goog.vec.Float64Array.prototype, 'BYTES_PER_ELEMENT',
+ goog.vec.Float64Array.prototype.BYTES_PER_ELEMENT);
+ goog.exportProperty(
+ goog.vec.Float64Array.prototype, 'set',
+ goog.vec.Float64Array.prototype.set);
+ goog.exportProperty(
+ goog.vec.Float64Array.prototype, 'toString',
+ goog.vec.Float64Array.prototype.toString);
+ goog.exportSymbol('Float64Array', goog.vec.Float64Array);
+}
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Supplies global data types and constants for the vector math
+ * library.
+ */
+goog.provide('goog.vec');
+goog.provide('goog.vec.AnyType');
+goog.provide('goog.vec.ArrayType');
+goog.provide('goog.vec.Float32');
+goog.provide('goog.vec.Float64');
+goog.provide('goog.vec.Number');
+
+
+/**
+ * On platforms that don't have native Float32Array or Float64Array support we
+ * use a javascript implementation so that this math library can be used on all
+ * platforms.
+ * @suppress {extraRequire}
+ */
+goog.require('goog.vec.Float32Array');
+/** @suppress {extraRequire} */
+goog.require('goog.vec.Float64Array');
+
+// All vector and matrix operations are based upon arrays of numbers using
+// either Float32Array, Float64Array, or a standard Javascript Array of
+// Numbers.
+
+
+/** @typedef {!Float32Array} */
+goog.vec.Float32;
+
+
+/** @typedef {!Float64Array} */
+goog.vec.Float64;
+
+
+/** @typedef {!Array<number>} */
+goog.vec.Number;
+
+
+/** @typedef {!goog.vec.Float32|!goog.vec.Float64|!goog.vec.Number} */
+goog.vec.AnyType;
+
+
+/**
+ * @deprecated Use AnyType.
+ * @typedef {!Float32Array|!Array<number>}
+ */
+goog.vec.ArrayType;
+
+
+/**
+ * For graphics work, 6 decimal places of accuracy are typically all that is
+ * required.
+ *
+ * @type {number}
+ * @const
+ */
+goog.vec.EPSILON = 1e-6;
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Supplies 3 element vectors that are compatible with WebGL.
+ * Each element is a float32 since that is typically the desired size of a
+ * 3-vector in the GPU. The API is structured to avoid unnecessary memory
+ * allocations. The last parameter will typically be the output vector and
+ * an object can be both an input and output parameter to all methods except
+ * where noted.
+ *
+ */
+goog.provide('goog.vec.Vec3');
+
+/** @suppress {extraRequire} */
+goog.require('goog.vec');
+
+/** @typedef {goog.vec.Float32} */ goog.vec.Vec3.Float32;
+/** @typedef {goog.vec.Float64} */ goog.vec.Vec3.Float64;
+/** @typedef {goog.vec.Number} */ goog.vec.Vec3.Number;
+/** @typedef {goog.vec.AnyType} */ goog.vec.Vec3.AnyType;
+
+// The following two types are deprecated - use the above types instead.
+/** @typedef {Float32Array} */ goog.vec.Vec3.Type;
+/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec3.Vec3Like;
+
+
+/**
+ * Creates a 3 element vector of Float32. The array is initialized to zero.
+ *
+ * @return {!goog.vec.Vec3.Float32} The new 3 element array.
+ */
+goog.vec.Vec3.createFloat32 = function() {
+ return new Float32Array(3);
+};
+
+
+/**
+ * Creates a 3 element vector of Float64. The array is initialized to zero.
+ *
+ * @return {!goog.vec.Vec3.Float64} The new 3 element array.
+ */
+goog.vec.Vec3.createFloat64 = function() {
+ return new Float64Array(3);
+};
+
+
+/**
+ * Creates a 3 element vector of Number. The array is initialized to zero.
+ *
+ * @return {!goog.vec.Vec3.Number} The new 3 element array.
+ */
+goog.vec.Vec3.createNumber = function() {
+ var a = new Array(3);
+ goog.vec.Vec3.setFromValues(a, 0, 0, 0);
+ return a;
+};
+
+
+/**
+ * Creates a 3 element vector of Float32Array. The array is initialized to zero.
+ *
+ * @deprecated Use createFloat32.
+ * @return {!goog.vec.Vec3.Type} The new 3 element array.
+ */
+goog.vec.Vec3.create = function() {
+ return new Float32Array(3);
+};
+
+
+/**
+ * Creates a new 3 element Float32 vector initialized with the value from the
+ * given array.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec The source 3 element array.
+ * @return {!goog.vec.Vec3.Float32} The new 3 element array.
+ */
+goog.vec.Vec3.createFloat32FromArray = function(vec) {
+ var newVec = goog.vec.Vec3.createFloat32();
+ goog.vec.Vec3.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+ * Creates a new 3 element Float32 vector initialized with the supplied values.
+ *
+ * @param {number} v0 The value for element at index 0.
+ * @param {number} v1 The value for element at index 1.
+ * @param {number} v2 The value for element at index 2.
+ * @return {!goog.vec.Vec3.Float32} The new vector.
+ */
+goog.vec.Vec3.createFloat32FromValues = function(v0, v1, v2) {
+ var a = goog.vec.Vec3.createFloat32();
+ goog.vec.Vec3.setFromValues(a, v0, v1, v2);
+ return a;
+};
+
+
+/**
+ * Creates a clone of the given 3 element Float32 vector.
+ *
+ * @param {goog.vec.Vec3.Float32} vec The source 3 element vector.
+ * @return {!goog.vec.Vec3.Float32} The new cloned vector.
+ */
+goog.vec.Vec3.cloneFloat32 = goog.vec.Vec3.createFloat32FromArray;
+
+
+/**
+ * Creates a new 3 element Float64 vector initialized with the value from the
+ * given array.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec The source 3 element array.
+ * @return {!goog.vec.Vec3.Float64} The new 3 element array.
+ */
+goog.vec.Vec3.createFloat64FromArray = function(vec) {
+ var newVec = goog.vec.Vec3.createFloat64();
+ goog.vec.Vec3.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+* Creates a new 3 element Float64 vector initialized with the supplied values.
+*
+* @param {number} v0 The value for element at index 0.
+* @param {number} v1 The value for element at index 1.
+* @param {number} v2 The value for element at index 2.
+* @return {!goog.vec.Vec3.Float64} The new vector.
+*/
+goog.vec.Vec3.createFloat64FromValues = function(v0, v1, v2) {
+ var vec = goog.vec.Vec3.createFloat64();
+ goog.vec.Vec3.setFromValues(vec, v0, v1, v2);
+ return vec;
+};
+
+
+/**
+ * Creates a clone of the given 3 element vector.
+ *
+ * @param {goog.vec.Vec3.Float64} vec The source 3 element vector.
+ * @return {!goog.vec.Vec3.Float64} The new cloned vector.
+ */
+goog.vec.Vec3.cloneFloat64 = goog.vec.Vec3.createFloat64FromArray;
+
+
+/**
+ * Creates a new 3 element vector initialized with the value from the given
+ * array.
+ *
+ * @deprecated Use createFloat32FromArray.
+ * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element array.
+ * @return {!goog.vec.Vec3.Type} The new 3 element array.
+ */
+goog.vec.Vec3.createFromArray = function(vec) {
+ var newVec = goog.vec.Vec3.create();
+ goog.vec.Vec3.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+ * Creates a new 3 element vector initialized with the supplied values.
+ *
+ * @deprecated Use createFloat32FromValues.
+ * @param {number} v0 The value for element at index 0.
+ * @param {number} v1 The value for element at index 1.
+ * @param {number} v2 The value for element at index 2.
+ * @return {!goog.vec.Vec3.Type} The new vector.
+ */
+goog.vec.Vec3.createFromValues = function(v0, v1, v2) {
+ var vec = goog.vec.Vec3.create();
+ goog.vec.Vec3.setFromValues(vec, v0, v1, v2);
+ return vec;
+};
+
+
+/**
+ * Creates a clone of the given 3 element vector.
+ *
+ * @deprecated Use cloneFloat32.
+ * @param {goog.vec.Vec3.Vec3Like} vec The source 3 element vector.
+ * @return {!goog.vec.Vec3.Type} The new cloned vector.
+ */
+goog.vec.Vec3.clone = function(vec) {
+ var newVec = goog.vec.Vec3.create();
+ goog.vec.Vec3.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+ * Initializes the vector with the given values.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec The vector to receive the values.
+ * @param {number} v0 The value for element at index 0.
+ * @param {number} v1 The value for element at index 1.
+ * @param {number} v2 The value for element at index 2.
+ * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.setFromValues = function(vec, v0, v1, v2) {
+ vec[0] = v0;
+ vec[1] = v1;
+ vec[2] = v2;
+ return vec;
+};
+
+
+/**
+ * Initializes the vector with the given array of values.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec The vector to receive the
+ * values.
+ * @param {goog.vec.Vec3.AnyType} values The array of values.
+ * @return {!goog.vec.Vec3.AnyType} Return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.setFromArray = function(vec, values) {
+ vec[0] = values[0];
+ vec[1] = values[1];
+ vec[2] = values[2];
+ return vec;
+};
+
+
+/**
+ * Performs a component-wise addition of vec0 and vec1 together storing the
+ * result into resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The first addend.
+ * @param {goog.vec.Vec3.AnyType} vec1 The second addend.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to
+ * receive the result. May be vec0 or vec1.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.add = function(vec0, vec1, resultVec) {
+ resultVec[0] = vec0[0] + vec1[0];
+ resultVec[1] = vec0[1] + vec1[1];
+ resultVec[2] = vec0[2] + vec1[2];
+ return resultVec;
+};
+
+
+/**
+ * Performs a component-wise subtraction of vec1 from vec0 storing the
+ * result into resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The minuend.
+ * @param {goog.vec.Vec3.AnyType} vec1 The subtrahend.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to
+ * receive the result. May be vec0 or vec1.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.subtract = function(vec0, vec1, resultVec) {
+ resultVec[0] = vec0[0] - vec1[0];
+ resultVec[1] = vec0[1] - vec1[1];
+ resultVec[2] = vec0[2] - vec1[2];
+ return resultVec;
+};
+
+
+/**
+ * Negates vec0, storing the result into resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The vector to negate.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to
+ * receive the result. May be vec0.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.negate = function(vec0, resultVec) {
+ resultVec[0] = -vec0[0];
+ resultVec[1] = -vec0[1];
+ resultVec[2] = -vec0[2];
+ return resultVec;
+};
+
+
+/**
+ * Takes the absolute value of each component of vec0 storing the result in
+ * resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The source vector.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the result.
+ * May be vec0.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.abs = function(vec0, resultVec) {
+ resultVec[0] = Math.abs(vec0[0]);
+ resultVec[1] = Math.abs(vec0[1]);
+ resultVec[2] = Math.abs(vec0[2]);
+ return resultVec;
+};
+
+
+/**
+ * Multiplies each component of vec0 with scalar storing the product into
+ * resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The source vector.
+ * @param {number} scalar The value to multiply with each component of vec0.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to
+ * receive the result. May be vec0.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.scale = function(vec0, scalar, resultVec) {
+ resultVec[0] = vec0[0] * scalar;
+ resultVec[1] = vec0[1] * scalar;
+ resultVec[2] = vec0[2] * scalar;
+ return resultVec;
+};
+
+
+/**
+ * Returns the magnitudeSquared of the given vector.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The vector.
+ * @return {number} The magnitude of the vector.
+ */
+goog.vec.Vec3.magnitudeSquared = function(vec0) {
+ var x = vec0[0], y = vec0[1], z = vec0[2];
+ return x * x + y * y + z * z;
+};
+
+
+/**
+ * Returns the magnitude of the given vector.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The vector.
+ * @return {number} The magnitude of the vector.
+ */
+goog.vec.Vec3.magnitude = function(vec0) {
+ var x = vec0[0], y = vec0[1], z = vec0[2];
+ return Math.sqrt(x * x + y * y + z * z);
+};
+
+
+/**
+ * Normalizes the given vector storing the result into resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The vector to normalize.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to
+ * receive the result. May be vec0.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.normalize = function(vec0, resultVec) {
+ var ilen = 1 / goog.vec.Vec3.magnitude(vec0);
+ resultVec[0] = vec0[0] * ilen;
+ resultVec[1] = vec0[1] * ilen;
+ resultVec[2] = vec0[2] * ilen;
+ return resultVec;
+};
+
+
+/**
+ * Returns the scalar product of vectors v0 and v1.
+ *
+ * @param {goog.vec.Vec3.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec3.AnyType} v1 The second vector.
+ * @return {number} The scalar product.
+ */
+goog.vec.Vec3.dot = function(v0, v1) {
+ return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2];
+};
+
+
+/**
+ * Computes the vector (cross) product of v0 and v1 storing the result into
+ * resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec3.AnyType} v1 The second vector.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the
+ * results. May be either v0 or v1.
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.cross = function(v0, v1, resultVec) {
+ var x0 = v0[0], y0 = v0[1], z0 = v0[2];
+ var x1 = v1[0], y1 = v1[1], z1 = v1[2];
+ resultVec[0] = y0 * z1 - z0 * y1;
+ resultVec[1] = z0 * x1 - x0 * z1;
+ resultVec[2] = x0 * y1 - y0 * x1;
+ return resultVec;
+};
+
+
+/**
+ * Returns the squared distance between two points.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 First point.
+ * @param {goog.vec.Vec3.AnyType} vec1 Second point.
+ * @return {number} The squared distance between the points.
+ */
+goog.vec.Vec3.distanceSquared = function(vec0, vec1) {
+ var x = vec0[0] - vec1[0];
+ var y = vec0[1] - vec1[1];
+ var z = vec0[2] - vec1[2];
+ return x * x + y * y + z * z;
+};
+
+
+/**
+ * Returns the distance between two points.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 First point.
+ * @param {goog.vec.Vec3.AnyType} vec1 Second point.
+ * @return {number} The distance between the points.
+ */
+goog.vec.Vec3.distance = function(vec0, vec1) {
+ return Math.sqrt(goog.vec.Vec3.distanceSquared(vec0, vec1));
+};
+
+
+/**
+ * Returns a unit vector pointing from one point to another.
+ * If the input points are equal then the result will be all zeros.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 Origin point.
+ * @param {goog.vec.Vec3.AnyType} vec1 Target point.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the
+ * results (may be vec0 or vec1).
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.direction = function(vec0, vec1, resultVec) {
+ var x = vec1[0] - vec0[0];
+ var y = vec1[1] - vec0[1];
+ var z = vec1[2] - vec0[2];
+ var d = Math.sqrt(x * x + y * y + z * z);
+ if (d) {
+ d = 1 / d;
+ resultVec[0] = x * d;
+ resultVec[1] = y * d;
+ resultVec[2] = z * d;
+ } else {
+ resultVec[0] = resultVec[1] = resultVec[2] = 0;
+ }
+ return resultVec;
+};
+
+
+/**
+ * Linearly interpolate from vec0 to v1 according to f. The value of f should be
+ * in the range [0..1] otherwise the results are undefined.
+ *
+ * @param {goog.vec.Vec3.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec3.AnyType} v1 The second vector.
+ * @param {number} f The interpolation factor.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the
+ * results (may be v0 or v1).
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.lerp = function(v0, v1, f, resultVec) {
+ var x = v0[0], y = v0[1], z = v0[2];
+ resultVec[0] = (v1[0] - x) * f + x;
+ resultVec[1] = (v1[1] - y) * f + y;
+ resultVec[2] = (v1[2] - z) * f + z;
+ return resultVec;
+};
+
+
+/**
+ * Compares the components of vec0 with the components of another vector or
+ * scalar, storing the larger values in resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The source vector.
+ * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the
+ * results (may be vec0 or limit).
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.max = function(vec0, limit, resultVec) {
+ if (goog.isNumber(limit)) {
+ resultVec[0] = Math.max(vec0[0], limit);
+ resultVec[1] = Math.max(vec0[1], limit);
+ resultVec[2] = Math.max(vec0[2], limit);
+ } else {
+ resultVec[0] = Math.max(vec0[0], limit[0]);
+ resultVec[1] = Math.max(vec0[1], limit[1]);
+ resultVec[2] = Math.max(vec0[2], limit[2]);
+ }
+ return resultVec;
+};
+
+
+/**
+ * Compares the components of vec0 with the components of another vector or
+ * scalar, storing the smaller values in resultVec.
+ *
+ * @param {goog.vec.Vec3.AnyType} vec0 The source vector.
+ * @param {goog.vec.Vec3.AnyType|number} limit The limit vector or scalar.
+ * @param {goog.vec.Vec3.AnyType} resultVec The vector to receive the
+ * results (may be vec0 or limit).
+ * @return {!goog.vec.Vec3.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec3.min = function(vec0, limit, resultVec) {
+ if (goog.isNumber(limit)) {
+ resultVec[0] = Math.min(vec0[0], limit);
+ resultVec[1] = Math.min(vec0[1], limit);
+ resultVec[2] = Math.min(vec0[2], limit);
+ } else {
+ resultVec[0] = Math.min(vec0[0], limit[0]);
+ resultVec[1] = Math.min(vec0[1], limit[1]);
+ resultVec[2] = Math.min(vec0[2], limit[2]);
+ }
+ return resultVec;
+};
+
+
+/**
+ * Returns true if the components of v0 are equal to the components of v1.
+ *
+ * @param {goog.vec.Vec3.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec3.AnyType} v1 The second vector.
+ * @return {boolean} True if the vectors are equal, false otherwise.
+ */
+goog.vec.Vec3.equals = function(v0, v1) {
+ return v0.length == v1.length && v0[0] == v1[0] && v0[1] == v1[1] &&
+ v0[2] == v1[2];
+};
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Supplies 4 element vectors that are compatible with WebGL.
+ * Each element is a float32 since that is typically the desired size of a
+ * 4-vector in the GPU. The API is structured to avoid unnecessary memory
+ * allocations. The last parameter will typically be the output vector and
+ * an object can be both an input and output parameter to all methods except
+ * where noted.
+ *
+ */
+goog.provide('goog.vec.Vec4');
+
+/** @suppress {extraRequire} */
+goog.require('goog.vec');
+
+/** @typedef {goog.vec.Float32} */ goog.vec.Vec4.Float32;
+/** @typedef {goog.vec.Float64} */ goog.vec.Vec4.Float64;
+/** @typedef {goog.vec.Number} */ goog.vec.Vec4.Number;
+/** @typedef {goog.vec.AnyType} */ goog.vec.Vec4.AnyType;
+
+// The following two types are deprecated - use the above types instead.
+/** @typedef {Float32Array} */ goog.vec.Vec4.Type;
+/** @typedef {goog.vec.ArrayType} */ goog.vec.Vec4.Vec4Like;
+
+
+/**
+ * Creates a 4 element vector of Float32. The array is initialized to zero.
+ *
+ * @return {!goog.vec.Vec4.Float32} The new 3 element array.
+ */
+goog.vec.Vec4.createFloat32 = function() {
+ return new Float32Array(4);
+};
+
+
+/**
+ * Creates a 4 element vector of Float64. The array is initialized to zero.
+ *
+ * @return {!goog.vec.Vec4.Float64} The new 4 element array.
+ */
+goog.vec.Vec4.createFloat64 = function() {
+ return new Float64Array(4);
+};
+
+
+/**
+ * Creates a 4 element vector of Number. The array is initialized to zero.
+ *
+ * @return {!goog.vec.Vec4.Number} The new 4 element array.
+ */
+goog.vec.Vec4.createNumber = function() {
+ var v = new Array(4);
+ goog.vec.Vec4.setFromValues(v, 0, 0, 0, 0);
+ return v;
+};
+
+
+/**
+ * Creates a 4 element vector of Float32Array. The array is initialized to zero.
+ *
+ * @deprecated Use createFloat32.
+ * @return {!goog.vec.Vec4.Type} The new 4 element array.
+ */
+goog.vec.Vec4.create = function() {
+ return new Float32Array(4);
+};
+
+
+/**
+ * Creates a new 4 element vector initialized with the value from the given
+ * array.
+ *
+ * @deprecated Use createFloat32FromArray.
+ * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element array.
+ * @return {!goog.vec.Vec4.Type} The new 4 element array.
+ */
+goog.vec.Vec4.createFromArray = function(vec) {
+ var newVec = goog.vec.Vec4.create();
+ goog.vec.Vec4.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+ * Creates a new 4 element FLoat32 vector initialized with the value from the
+ * given array.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec The source 3 element array.
+ * @return {!goog.vec.Vec4.Float32} The new 3 element array.
+ */
+goog.vec.Vec4.createFloat32FromArray = function(vec) {
+ var newVec = goog.vec.Vec4.createFloat32();
+ goog.vec.Vec4.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+ * Creates a new 4 element Float32 vector initialized with the supplied values.
+ *
+ * @param {number} v0 The value for element at index 0.
+ * @param {number} v1 The value for element at index 1.
+ * @param {number} v2 The value for element at index 2.
+ * @param {number} v3 The value for element at index 3.
+ * @return {!goog.vec.Vec4.Float32} The new vector.
+ */
+goog.vec.Vec4.createFloat32FromValues = function(v0, v1, v2, v3) {
+ var vec = goog.vec.Vec4.createFloat32();
+ goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3);
+ return vec;
+};
+
+
+/**
+ * Creates a clone of the given 4 element Float32 vector.
+ *
+ * @param {goog.vec.Vec4.Float32} vec The source 3 element vector.
+ * @return {!goog.vec.Vec4.Float32} The new cloned vector.
+ */
+goog.vec.Vec4.cloneFloat32 = goog.vec.Vec4.createFloat32FromArray;
+
+
+/**
+ * Creates a new 4 element Float64 vector initialized with the value from the
+ * given array.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec The source 4 element array.
+ * @return {!goog.vec.Vec4.Float64} The new 4 element array.
+ */
+goog.vec.Vec4.createFloat64FromArray = function(vec) {
+ var newVec = goog.vec.Vec4.createFloat64();
+ goog.vec.Vec4.setFromArray(newVec, vec);
+ return newVec;
+};
+
+
+/**
+* Creates a new 4 element Float64 vector initialized with the supplied values.
+*
+* @param {number} v0 The value for element at index 0.
+* @param {number} v1 The value for element at index 1.
+* @param {number} v2 The value for element at index 2.
+* @param {number} v3 The value for element at index 3.
+* @return {!goog.vec.Vec4.Float64} The new vector.
+*/
+goog.vec.Vec4.createFloat64FromValues = function(v0, v1, v2, v3) {
+ var vec = goog.vec.Vec4.createFloat64();
+ goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3);
+ return vec;
+};
+
+
+/**
+ * Creates a clone of the given 4 element vector.
+ *
+ * @param {goog.vec.Vec4.Float64} vec The source 4 element vector.
+ * @return {!goog.vec.Vec4.Float64} The new cloned vector.
+ */
+goog.vec.Vec4.cloneFloat64 = goog.vec.Vec4.createFloat64FromArray;
+
+
+/**
+ * Creates a new 4 element vector initialized with the supplied values.
+ *
+ * @deprecated Use createFloat32FromValues.
+ * @param {number} v0 The value for element at index 0.
+ * @param {number} v1 The value for element at index 1.
+ * @param {number} v2 The value for element at index 2.
+ * @param {number} v3 The value for element at index 3.
+ * @return {!goog.vec.Vec4.Type} The new vector.
+ */
+goog.vec.Vec4.createFromValues = function(v0, v1, v2, v3) {
+ var vec = goog.vec.Vec4.create();
+ goog.vec.Vec4.setFromValues(vec, v0, v1, v2, v3);
+ return vec;
+};
+
+
+/**
+ * Creates a clone of the given 4 element vector.
+ *
+ * @deprecated Use cloneFloat32.
+ * @param {goog.vec.Vec4.Vec4Like} vec The source 4 element vector.
+ * @return {!goog.vec.Vec4.Type} The new cloned vector.
+ */
+goog.vec.Vec4.clone = goog.vec.Vec4.createFromArray;
+
+
+/**
+ * Initializes the vector with the given values.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values.
+ * @param {number} v0 The value for element at index 0.
+ * @param {number} v1 The value for element at index 1.
+ * @param {number} v2 The value for element at index 2.
+ * @param {number} v3 The value for element at index 3.
+ * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.setFromValues = function(vec, v0, v1, v2, v3) {
+ vec[0] = v0;
+ vec[1] = v1;
+ vec[2] = v2;
+ vec[3] = v3;
+ return vec;
+};
+
+
+/**
+ * Initializes the vector with the given array of values.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec The vector to receive the
+ * values.
+ * @param {goog.vec.Vec4.AnyType} values The array of values.
+ * @return {!goog.vec.Vec4.AnyType} Return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.setFromArray = function(vec, values) {
+ vec[0] = values[0];
+ vec[1] = values[1];
+ vec[2] = values[2];
+ vec[3] = values[3];
+ return vec;
+};
+
+
+/**
+ * Performs a component-wise addition of vec0 and vec1 together storing the
+ * result into resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The first addend.
+ * @param {goog.vec.Vec4.AnyType} vec1 The second addend.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to
+ * receive the result. May be vec0 or vec1.
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.add = function(vec0, vec1, resultVec) {
+ resultVec[0] = vec0[0] + vec1[0];
+ resultVec[1] = vec0[1] + vec1[1];
+ resultVec[2] = vec0[2] + vec1[2];
+ resultVec[3] = vec0[3] + vec1[3];
+ return resultVec;
+};
+
+
+/**
+ * Performs a component-wise subtraction of vec1 from vec0 storing the
+ * result into resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The minuend.
+ * @param {goog.vec.Vec4.AnyType} vec1 The subtrahend.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to
+ * receive the result. May be vec0 or vec1.
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.subtract = function(vec0, vec1, resultVec) {
+ resultVec[0] = vec0[0] - vec1[0];
+ resultVec[1] = vec0[1] - vec1[1];
+ resultVec[2] = vec0[2] - vec1[2];
+ resultVec[3] = vec0[3] - vec1[3];
+ return resultVec;
+};
+
+
+/**
+ * Negates vec0, storing the result into resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The vector to negate.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to
+ * receive the result. May be vec0.
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.negate = function(vec0, resultVec) {
+ resultVec[0] = -vec0[0];
+ resultVec[1] = -vec0[1];
+ resultVec[2] = -vec0[2];
+ resultVec[3] = -vec0[3];
+ return resultVec;
+};
+
+
+/**
+ * Takes the absolute value of each component of vec0 storing the result in
+ * resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The source vector.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the result.
+ * May be vec0.
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.abs = function(vec0, resultVec) {
+ resultVec[0] = Math.abs(vec0[0]);
+ resultVec[1] = Math.abs(vec0[1]);
+ resultVec[2] = Math.abs(vec0[2]);
+ resultVec[3] = Math.abs(vec0[3]);
+ return resultVec;
+};
+
+
+/**
+ * Multiplies each component of vec0 with scalar storing the product into
+ * resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The source vector.
+ * @param {number} scalar The value to multiply with each component of vec0.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to
+ * receive the result. May be vec0.
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.scale = function(vec0, scalar, resultVec) {
+ resultVec[0] = vec0[0] * scalar;
+ resultVec[1] = vec0[1] * scalar;
+ resultVec[2] = vec0[2] * scalar;
+ resultVec[3] = vec0[3] * scalar;
+ return resultVec;
+};
+
+
+/**
+ * Returns the magnitudeSquared of the given vector.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The vector.
+ * @return {number} The magnitude of the vector.
+ */
+goog.vec.Vec4.magnitudeSquared = function(vec0) {
+ var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3];
+ return x * x + y * y + z * z + w * w;
+};
+
+
+/**
+ * Returns the magnitude of the given vector.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The vector.
+ * @return {number} The magnitude of the vector.
+ */
+goog.vec.Vec4.magnitude = function(vec0) {
+ var x = vec0[0], y = vec0[1], z = vec0[2], w = vec0[3];
+ return Math.sqrt(x * x + y * y + z * z + w * w);
+};
+
+
+/**
+ * Normalizes the given vector storing the result into resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The vector to normalize.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to
+ * receive the result. May be vec0.
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.normalize = function(vec0, resultVec) {
+ var ilen = 1 / goog.vec.Vec4.magnitude(vec0);
+ resultVec[0] = vec0[0] * ilen;
+ resultVec[1] = vec0[1] * ilen;
+ resultVec[2] = vec0[2] * ilen;
+ resultVec[3] = vec0[3] * ilen;
+ return resultVec;
+};
+
+
+/**
+ * Returns the scalar product of vectors v0 and v1.
+ *
+ * @param {goog.vec.Vec4.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec4.AnyType} v1 The second vector.
+ * @return {number} The scalar product.
+ */
+goog.vec.Vec4.dot = function(v0, v1) {
+ return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2] + v0[3] * v1[3];
+};
+
+
+/**
+ * Linearly interpolate from v0 to v1 according to f. The value of f should be
+ * in the range [0..1] otherwise the results are undefined.
+ *
+ * @param {goog.vec.Vec4.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec4.AnyType} v1 The second vector.
+ * @param {number} f The interpolation factor.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the
+ * results (may be v0 or v1).
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.lerp = function(v0, v1, f, resultVec) {
+ var x = v0[0], y = v0[1], z = v0[2], w = v0[3];
+ resultVec[0] = (v1[0] - x) * f + x;
+ resultVec[1] = (v1[1] - y) * f + y;
+ resultVec[2] = (v1[2] - z) * f + z;
+ resultVec[3] = (v1[3] - w) * f + w;
+ return resultVec;
+};
+
+
+/**
+ * Compares the components of vec0 with the components of another vector or
+ * scalar, storing the larger values in resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The source vector.
+ * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the
+ * results (may be vec0 or limit).
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.max = function(vec0, limit, resultVec) {
+ if (goog.isNumber(limit)) {
+ resultVec[0] = Math.max(vec0[0], limit);
+ resultVec[1] = Math.max(vec0[1], limit);
+ resultVec[2] = Math.max(vec0[2], limit);
+ resultVec[3] = Math.max(vec0[3], limit);
+ } else {
+ resultVec[0] = Math.max(vec0[0], limit[0]);
+ resultVec[1] = Math.max(vec0[1], limit[1]);
+ resultVec[2] = Math.max(vec0[2], limit[2]);
+ resultVec[3] = Math.max(vec0[3], limit[3]);
+ }
+ return resultVec;
+};
+
+
+/**
+ * Compares the components of vec0 with the components of another vector or
+ * scalar, storing the smaller values in resultVec.
+ *
+ * @param {goog.vec.Vec4.AnyType} vec0 The source vector.
+ * @param {goog.vec.Vec4.AnyType|number} limit The limit vector or scalar.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to receive the
+ * results (may be vec0 or limit).
+ * @return {!goog.vec.Vec4.AnyType} Return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Vec4.min = function(vec0, limit, resultVec) {
+ if (goog.isNumber(limit)) {
+ resultVec[0] = Math.min(vec0[0], limit);
+ resultVec[1] = Math.min(vec0[1], limit);
+ resultVec[2] = Math.min(vec0[2], limit);
+ resultVec[3] = Math.min(vec0[3], limit);
+ } else {
+ resultVec[0] = Math.min(vec0[0], limit[0]);
+ resultVec[1] = Math.min(vec0[1], limit[1]);
+ resultVec[2] = Math.min(vec0[2], limit[2]);
+ resultVec[3] = Math.min(vec0[3], limit[3]);
+ }
+ return resultVec;
+};
+
+
+/**
+ * Returns true if the components of v0 are equal to the components of v1.
+ *
+ * @param {goog.vec.Vec4.AnyType} v0 The first vector.
+ * @param {goog.vec.Vec4.AnyType} v1 The second vector.
+ * @return {boolean} True if the vectors are equal, false otherwise.
+ */
+goog.vec.Vec4.equals = function(v0, v1) {
+ return v0.length == v1.length && v0[0] == v1[0] && v0[1] == v1[1] &&
+ v0[2] == v1[2] && v0[3] == v1[3];
+};
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Implements 4x4 matrices and their related functions which are
+ * compatible with WebGL. The API is structured to avoid unnecessary memory
+ * allocations. The last parameter will typically be the output vector and
+ * an object can be both an input and output parameter to all methods except
+ * where noted. Matrix operations follow the mathematical form when multiplying
+ * vectors as follows: resultVec = matrix * vec.
+ *
+ * The matrices are stored in column-major order.
+ *
+ */
+goog.provide('goog.vec.Mat4');
+
+goog.require('goog.vec');
+goog.require('goog.vec.Vec3');
+goog.require('goog.vec.Vec4');
+
+
+/** @typedef {goog.vec.Float32} */ goog.vec.Mat4.Float32;
+/** @typedef {goog.vec.Float64} */ goog.vec.Mat4.Float64;
+/** @typedef {goog.vec.Number} */ goog.vec.Mat4.Number;
+/** @typedef {goog.vec.AnyType} */ goog.vec.Mat4.AnyType;
+
+// The following two types are deprecated - use the above types instead.
+/** @typedef {!Float32Array} */ goog.vec.Mat4.Type;
+/** @typedef {goog.vec.ArrayType} */ goog.vec.Mat4.Mat4Like;
+
+
+/**
+ * Creates the array representation of a 4x4 matrix of Float32.
+ * The use of the array directly instead of a class reduces overhead.
+ * The returned matrix is cleared to all zeros.
+ *
+ * @return {!goog.vec.Mat4.Float32} The new matrix.
+ */
+goog.vec.Mat4.createFloat32 = function() {
+ return new Float32Array(16);
+};
+
+
+/**
+ * Creates the array representation of a 4x4 matrix of Float64.
+ * The returned matrix is cleared to all zeros.
+ *
+ * @return {!goog.vec.Mat4.Float64} The new matrix.
+ */
+goog.vec.Mat4.createFloat64 = function() {
+ return new Float64Array(16);
+};
+
+
+/**
+ * Creates the array representation of a 4x4 matrix of Number.
+ * The returned matrix is cleared to all zeros.
+ *
+ * @return {!goog.vec.Mat4.Number} The new matrix.
+ */
+goog.vec.Mat4.createNumber = function() {
+ var a = new Array(16);
+ goog.vec.Mat4.setFromValues(
+ a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ return a;
+};
+
+
+/**
+ * Creates the array representation of a 4x4 matrix of Float32.
+ * The returned matrix is cleared to all zeros.
+ *
+ * @deprecated Use createFloat32.
+ * @return {!goog.vec.Mat4.Type} The new matrix.
+ */
+goog.vec.Mat4.create = function() {
+ return goog.vec.Mat4.createFloat32();
+};
+
+
+/**
+ * Creates a 4x4 identity matrix of Float32.
+ *
+ * @return {!goog.vec.Mat4.Float32} The new 16 element array.
+ */
+goog.vec.Mat4.createFloat32Identity = function() {
+ var mat = goog.vec.Mat4.createFloat32();
+ mat[0] = mat[5] = mat[10] = mat[15] = 1;
+ return mat;
+};
+
+
+/**
+ * Creates a 4x4 identity matrix of Float64.
+ *
+ * @return {!goog.vec.Mat4.Float64} The new 16 element array.
+ */
+goog.vec.Mat4.createFloat64Identity = function() {
+ var mat = goog.vec.Mat4.createFloat64();
+ mat[0] = mat[5] = mat[10] = mat[15] = 1;
+ return mat;
+};
+
+
+/**
+ * Creates a 4x4 identity matrix of Number.
+ * The returned matrix is cleared to all zeros.
+ *
+ * @return {!goog.vec.Mat4.Number} The new 16 element array.
+ */
+goog.vec.Mat4.createNumberIdentity = function() {
+ var a = new Array(16);
+ goog.vec.Mat4.setFromValues(
+ a, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ return a;
+};
+
+
+/**
+ * Creates the array representation of a 4x4 matrix of Float32.
+ * The returned matrix is cleared to all zeros.
+ *
+ * @deprecated Use createFloat32Identity.
+ * @return {!goog.vec.Mat4.Type} The new 16 element array.
+ */
+goog.vec.Mat4.createIdentity = function() {
+ return goog.vec.Mat4.createFloat32Identity();
+};
+
+
+/**
+ * Creates a 4x4 matrix of Float32 initialized from the given array.
+ *
+ * @param {goog.vec.Mat4.AnyType} matrix The array containing the
+ * matrix values in column major order.
+ * @return {!goog.vec.Mat4.Float32} The new, 16 element array.
+ */
+goog.vec.Mat4.createFloat32FromArray = function(matrix) {
+ var newMatrix = goog.vec.Mat4.createFloat32();
+ goog.vec.Mat4.setFromArray(newMatrix, matrix);
+ return newMatrix;
+};
+
+
+/**
+ * Creates a 4x4 matrix of Float32 initialized from the given values.
+ *
+ * @param {number} v00 The values at (0, 0).
+ * @param {number} v10 The values at (1, 0).
+ * @param {number} v20 The values at (2, 0).
+ * @param {number} v30 The values at (3, 0).
+ * @param {number} v01 The values at (0, 1).
+ * @param {number} v11 The values at (1, 1).
+ * @param {number} v21 The values at (2, 1).
+ * @param {number} v31 The values at (3, 1).
+ * @param {number} v02 The values at (0, 2).
+ * @param {number} v12 The values at (1, 2).
+ * @param {number} v22 The values at (2, 2).
+ * @param {number} v32 The values at (3, 2).
+ * @param {number} v03 The values at (0, 3).
+ * @param {number} v13 The values at (1, 3).
+ * @param {number} v23 The values at (2, 3).
+ * @param {number} v33 The values at (3, 3).
+ * @return {!goog.vec.Mat4.Float32} The new, 16 element array.
+ */
+goog.vec.Mat4.createFloat32FromValues = function(
+ v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, v03, v13, v23,
+ v33) {
+ var newMatrix = goog.vec.Mat4.createFloat32();
+ goog.vec.Mat4.setFromValues(
+ newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32,
+ v03, v13, v23, v33);
+ return newMatrix;
+};
+
+
+/**
+ * Creates a clone of a 4x4 matrix of Float32.
+ *
+ * @param {goog.vec.Mat4.Float32} matrix The source 4x4 matrix.
+ * @return {!goog.vec.Mat4.Float32} The new 4x4 element matrix.
+ */
+goog.vec.Mat4.cloneFloat32 = goog.vec.Mat4.createFloat32FromArray;
+
+
+/**
+ * Creates a 4x4 matrix of Float64 initialized from the given array.
+ *
+ * @param {goog.vec.Mat4.AnyType} matrix The array containing the
+ * matrix values in column major order.
+ * @return {!goog.vec.Mat4.Float64} The new, nine element array.
+ */
+goog.vec.Mat4.createFloat64FromArray = function(matrix) {
+ var newMatrix = goog.vec.Mat4.createFloat64();
+ goog.vec.Mat4.setFromArray(newMatrix, matrix);
+ return newMatrix;
+};
+
+
+/**
+ * Creates a 4x4 matrix of Float64 initialized from the given values.
+ *
+ * @param {number} v00 The values at (0, 0).
+ * @param {number} v10 The values at (1, 0).
+ * @param {number} v20 The values at (2, 0).
+ * @param {number} v30 The values at (3, 0).
+ * @param {number} v01 The values at (0, 1).
+ * @param {number} v11 The values at (1, 1).
+ * @param {number} v21 The values at (2, 1).
+ * @param {number} v31 The values at (3, 1).
+ * @param {number} v02 The values at (0, 2).
+ * @param {number} v12 The values at (1, 2).
+ * @param {number} v22 The values at (2, 2).
+ * @param {number} v32 The values at (3, 2).
+ * @param {number} v03 The values at (0, 3).
+ * @param {number} v13 The values at (1, 3).
+ * @param {number} v23 The values at (2, 3).
+ * @param {number} v33 The values at (3, 3).
+ * @return {!goog.vec.Mat4.Float64} The new, 16 element array.
+ */
+goog.vec.Mat4.createFloat64FromValues = function(
+ v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, v03, v13, v23,
+ v33) {
+ var newMatrix = goog.vec.Mat4.createFloat64();
+ goog.vec.Mat4.setFromValues(
+ newMatrix, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32,
+ v03, v13, v23, v33);
+ return newMatrix;
+};
+
+
+/**
+ * Creates a clone of a 4x4 matrix of Float64.
+ *
+ * @param {goog.vec.Mat4.Float64} matrix The source 4x4 matrix.
+ * @return {!goog.vec.Mat4.Float64} The new 4x4 element matrix.
+ */
+goog.vec.Mat4.cloneFloat64 = goog.vec.Mat4.createFloat64FromArray;
+
+
+/**
+ * Creates a 4x4 matrix of Float32 initialized from the given array.
+ *
+ * @deprecated Use createFloat32FromArray.
+ * @param {goog.vec.Mat4.Mat4Like} matrix The array containing the
+ * matrix values in column major order.
+ * @return {!goog.vec.Mat4.Type} The new, nine element array.
+ */
+goog.vec.Mat4.createFromArray = function(matrix) {
+ var newMatrix = goog.vec.Mat4.createFloat32();
+ goog.vec.Mat4.setFromArray(newMatrix, matrix);
+ return newMatrix;
+};
+
+
+/**
+ * Creates a 4x4 matrix of Float32 initialized from the given values.
+ *
+ * @deprecated Use createFloat32FromValues.
+ * @param {number} v00 The values at (0, 0).
+ * @param {number} v10 The values at (1, 0).
+ * @param {number} v20 The values at (2, 0).
+ * @param {number} v30 The values at (3, 0).
+ * @param {number} v01 The values at (0, 1).
+ * @param {number} v11 The values at (1, 1).
+ * @param {number} v21 The values at (2, 1).
+ * @param {number} v31 The values at (3, 1).
+ * @param {number} v02 The values at (0, 2).
+ * @param {number} v12 The values at (1, 2).
+ * @param {number} v22 The values at (2, 2).
+ * @param {number} v32 The values at (3, 2).
+ * @param {number} v03 The values at (0, 3).
+ * @param {number} v13 The values at (1, 3).
+ * @param {number} v23 The values at (2, 3).
+ * @param {number} v33 The values at (3, 3).
+ * @return {!goog.vec.Mat4.Type} The new, 16 element array.
+ */
+goog.vec.Mat4.createFromValues = function(
+ v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, v03, v13, v23,
+ v33) {
+ return goog.vec.Mat4.createFloat32FromValues(
+ v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, v03, v13, v23,
+ v33);
+};
+
+
+/**
+ * Creates a clone of a 4x4 matrix of Float32.
+ *
+ * @deprecated Use cloneFloat32.
+ * @param {goog.vec.Mat4.Mat4Like} matrix The source 4x4 matrix.
+ * @return {!goog.vec.Mat4.Type} The new 4x4 element matrix.
+ */
+goog.vec.Mat4.clone = goog.vec.Mat4.createFromArray;
+
+
+/**
+ * Retrieves the element at the requested row and column.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix containing the
+ * value to retrieve.
+ * @param {number} row The row index.
+ * @param {number} column The column index.
+ * @return {number} The element value at the requested row, column indices.
+ */
+goog.vec.Mat4.getElement = function(mat, row, column) {
+ return mat[row + column * 4];
+};
+
+
+/**
+ * Sets the element at the requested row and column.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to set the value on.
+ * @param {number} row The row index.
+ * @param {number} column The column index.
+ * @param {number} value The value to set at the requested row, column.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setElement = function(mat, row, column, value) {
+ mat[row + column * 4] = value;
+ return mat;
+};
+
+
+/**
+ * Initializes the matrix from the set of values. Note the values supplied are
+ * in column major order.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the
+ * values.
+ * @param {number} v00 The values at (0, 0).
+ * @param {number} v10 The values at (1, 0).
+ * @param {number} v20 The values at (2, 0).
+ * @param {number} v30 The values at (3, 0).
+ * @param {number} v01 The values at (0, 1).
+ * @param {number} v11 The values at (1, 1).
+ * @param {number} v21 The values at (2, 1).
+ * @param {number} v31 The values at (3, 1).
+ * @param {number} v02 The values at (0, 2).
+ * @param {number} v12 The values at (1, 2).
+ * @param {number} v22 The values at (2, 2).
+ * @param {number} v32 The values at (3, 2).
+ * @param {number} v03 The values at (0, 3).
+ * @param {number} v13 The values at (1, 3).
+ * @param {number} v23 The values at (2, 3).
+ * @param {number} v33 The values at (3, 3).
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setFromValues = function(
+ mat, v00, v10, v20, v30, v01, v11, v21, v31, v02, v12, v22, v32, v03, v13,
+ v23, v33) {
+ mat[0] = v00;
+ mat[1] = v10;
+ mat[2] = v20;
+ mat[3] = v30;
+ mat[4] = v01;
+ mat[5] = v11;
+ mat[6] = v21;
+ mat[7] = v31;
+ mat[8] = v02;
+ mat[9] = v12;
+ mat[10] = v22;
+ mat[11] = v32;
+ mat[12] = v03;
+ mat[13] = v13;
+ mat[14] = v23;
+ mat[15] = v33;
+ return mat;
+};
+
+
+/**
+ * Sets the matrix from the array of values stored in column major order.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {goog.vec.Mat4.AnyType} values The column major ordered
+ * array of values to store in the matrix.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setFromArray = function(mat, values) {
+ mat[0] = values[0];
+ mat[1] = values[1];
+ mat[2] = values[2];
+ mat[3] = values[3];
+ mat[4] = values[4];
+ mat[5] = values[5];
+ mat[6] = values[6];
+ mat[7] = values[7];
+ mat[8] = values[8];
+ mat[9] = values[9];
+ mat[10] = values[10];
+ mat[11] = values[11];
+ mat[12] = values[12];
+ mat[13] = values[13];
+ mat[14] = values[14];
+ mat[15] = values[15];
+ return mat;
+};
+
+
+/**
+ * Sets the matrix from the array of values stored in row major order.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {goog.vec.Mat4.AnyType} values The row major ordered array of
+ * values to store in the matrix.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setFromRowMajorArray = function(mat, values) {
+ mat[0] = values[0];
+ mat[1] = values[4];
+ mat[2] = values[8];
+ mat[3] = values[12];
+
+ mat[4] = values[1];
+ mat[5] = values[5];
+ mat[6] = values[9];
+ mat[7] = values[13];
+
+ mat[8] = values[2];
+ mat[9] = values[6];
+ mat[10] = values[10];
+ mat[11] = values[14];
+
+ mat[12] = values[3];
+ mat[13] = values[7];
+ mat[14] = values[11];
+ mat[15] = values[15];
+
+ return mat;
+};
+
+
+/**
+ * Sets the diagonal values of the matrix from the given values.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {number} v00 The values for (0, 0).
+ * @param {number} v11 The values for (1, 1).
+ * @param {number} v22 The values for (2, 2).
+ * @param {number} v33 The values for (3, 3).
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setDiagonalValues = function(mat, v00, v11, v22, v33) {
+ mat[0] = v00;
+ mat[5] = v11;
+ mat[10] = v22;
+ mat[15] = v33;
+ return mat;
+};
+
+
+/**
+ * Sets the diagonal values of the matrix from the given vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {goog.vec.Vec4.AnyType} vec The vector containing the values.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setDiagonal = function(mat, vec) {
+ mat[0] = vec[0];
+ mat[5] = vec[1];
+ mat[10] = vec[2];
+ mat[15] = vec[3];
+ return mat;
+};
+
+
+/**
+ * Gets the diagonal values of the matrix into the given vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix containing the values.
+ * @param {goog.vec.Vec4.AnyType} vec The vector to receive the values.
+ * @param {number=} opt_diagonal Which diagonal to get. A value of 0 selects the
+ * main diagonal, a positive number selects a super diagonal and a negative
+ * number selects a sub diagonal.
+ * @return {goog.vec.Vec4.AnyType} return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.getDiagonal = function(mat, vec, opt_diagonal) {
+ if (!opt_diagonal) {
+ // This is the most common case, so we avoid the for loop.
+ vec[0] = mat[0];
+ vec[1] = mat[5];
+ vec[2] = mat[10];
+ vec[3] = mat[15];
+ } else {
+ var offset = opt_diagonal > 0 ? 4 * opt_diagonal : -opt_diagonal;
+ for (var i = 0; i < 4 - Math.abs(opt_diagonal); i++) {
+ vec[i] = mat[offset + 5 * i];
+ }
+ }
+ return vec;
+};
+
+
+/**
+ * Sets the specified column with the supplied values.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {number} column The column index to set the values on.
+ * @param {number} v0 The value for row 0.
+ * @param {number} v1 The value for row 1.
+ * @param {number} v2 The value for row 2.
+ * @param {number} v3 The value for row 3.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setColumnValues = function(mat, column, v0, v1, v2, v3) {
+ var i = column * 4;
+ mat[i] = v0;
+ mat[i + 1] = v1;
+ mat[i + 2] = v2;
+ mat[i + 3] = v3;
+ return mat;
+};
+
+
+/**
+ * Sets the specified column with the value from the supplied vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {number} column The column index to set the values on.
+ * @param {goog.vec.Vec4.AnyType} vec The vector of elements for the column.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setColumn = function(mat, column, vec) {
+ var i = column * 4;
+ mat[i] = vec[0];
+ mat[i + 1] = vec[1];
+ mat[i + 2] = vec[2];
+ mat[i + 3] = vec[3];
+ return mat;
+};
+
+
+/**
+ * Retrieves the specified column from the matrix into the given vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values.
+ * @param {number} column The column to get the values from.
+ * @param {goog.vec.Vec4.AnyType} vec The vector of elements to
+ * receive the column.
+ * @return {goog.vec.Vec4.AnyType} return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.getColumn = function(mat, column, vec) {
+ var i = column * 4;
+ vec[0] = mat[i];
+ vec[1] = mat[i + 1];
+ vec[2] = mat[i + 2];
+ vec[3] = mat[i + 3];
+ return vec;
+};
+
+
+/**
+ * Sets the columns of the matrix from the given vectors.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {goog.vec.Vec4.AnyType} vec0 The values for column 0.
+ * @param {goog.vec.Vec4.AnyType} vec1 The values for column 1.
+ * @param {goog.vec.Vec4.AnyType} vec2 The values for column 2.
+ * @param {goog.vec.Vec4.AnyType} vec3 The values for column 3.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setColumns = function(mat, vec0, vec1, vec2, vec3) {
+ goog.vec.Mat4.setColumn(mat, 0, vec0);
+ goog.vec.Mat4.setColumn(mat, 1, vec1);
+ goog.vec.Mat4.setColumn(mat, 2, vec2);
+ goog.vec.Mat4.setColumn(mat, 3, vec3);
+ return mat;
+};
+
+
+/**
+ * Retrieves the column values from the given matrix into the given vectors.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the columns.
+ * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive column 0.
+ * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive column 1.
+ * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive column 2.
+ * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive column 3.
+ */
+goog.vec.Mat4.getColumns = function(mat, vec0, vec1, vec2, vec3) {
+ goog.vec.Mat4.getColumn(mat, 0, vec0);
+ goog.vec.Mat4.getColumn(mat, 1, vec1);
+ goog.vec.Mat4.getColumn(mat, 2, vec2);
+ goog.vec.Mat4.getColumn(mat, 3, vec3);
+};
+
+
+/**
+ * Sets the row values from the supplied values.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {number} row The index of the row to receive the values.
+ * @param {number} v0 The value for column 0.
+ * @param {number} v1 The value for column 1.
+ * @param {number} v2 The value for column 2.
+ * @param {number} v3 The value for column 3.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setRowValues = function(mat, row, v0, v1, v2, v3) {
+ mat[row] = v0;
+ mat[row + 4] = v1;
+ mat[row + 8] = v2;
+ mat[row + 12] = v3;
+ return mat;
+};
+
+
+/**
+ * Sets the row values from the supplied vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the row values.
+ * @param {number} row The index of the row.
+ * @param {goog.vec.Vec4.AnyType} vec The vector containing the values.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setRow = function(mat, row, vec) {
+ mat[row] = vec[0];
+ mat[row + 4] = vec[1];
+ mat[row + 8] = vec[2];
+ mat[row + 12] = vec[3];
+ return mat;
+};
+
+
+/**
+ * Retrieves the row values into the given vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the values.
+ * @param {number} row The index of the row supplying the values.
+ * @param {goog.vec.Vec4.AnyType} vec The vector to receive the row.
+ * @return {goog.vec.Vec4.AnyType} return vec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.getRow = function(mat, row, vec) {
+ vec[0] = mat[row];
+ vec[1] = mat[row + 4];
+ vec[2] = mat[row + 8];
+ vec[3] = mat[row + 12];
+ return vec;
+};
+
+
+/**
+ * Sets the rows of the matrix from the supplied vectors.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to receive the values.
+ * @param {goog.vec.Vec4.AnyType} vec0 The values for row 0.
+ * @param {goog.vec.Vec4.AnyType} vec1 The values for row 1.
+ * @param {goog.vec.Vec4.AnyType} vec2 The values for row 2.
+ * @param {goog.vec.Vec4.AnyType} vec3 The values for row 3.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.setRows = function(mat, vec0, vec1, vec2, vec3) {
+ goog.vec.Mat4.setRow(mat, 0, vec0);
+ goog.vec.Mat4.setRow(mat, 1, vec1);
+ goog.vec.Mat4.setRow(mat, 2, vec2);
+ goog.vec.Mat4.setRow(mat, 3, vec3);
+ return mat;
+};
+
+
+/**
+ * Retrieves the rows of the matrix into the supplied vectors.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to supply the values.
+ * @param {goog.vec.Vec4.AnyType} vec0 The vector to receive row 0.
+ * @param {goog.vec.Vec4.AnyType} vec1 The vector to receive row 1.
+ * @param {goog.vec.Vec4.AnyType} vec2 The vector to receive row 2.
+ * @param {goog.vec.Vec4.AnyType} vec3 The vector to receive row 3.
+ */
+goog.vec.Mat4.getRows = function(mat, vec0, vec1, vec2, vec3) {
+ goog.vec.Mat4.getRow(mat, 0, vec0);
+ goog.vec.Mat4.getRow(mat, 1, vec1);
+ goog.vec.Mat4.getRow(mat, 2, vec2);
+ goog.vec.Mat4.getRow(mat, 3, vec3);
+};
+
+
+/**
+ * Makes the given 4x4 matrix the zero matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @return {!goog.vec.Mat4.AnyType} return mat so operations can be chained.
+ */
+goog.vec.Mat4.makeZero = function(mat) {
+ mat[0] = 0;
+ mat[1] = 0;
+ mat[2] = 0;
+ mat[3] = 0;
+ mat[4] = 0;
+ mat[5] = 0;
+ mat[6] = 0;
+ mat[7] = 0;
+ mat[8] = 0;
+ mat[9] = 0;
+ mat[10] = 0;
+ mat[11] = 0;
+ mat[12] = 0;
+ mat[13] = 0;
+ mat[14] = 0;
+ mat[15] = 0;
+ return mat;
+};
+
+
+/**
+ * Makes the given 4x4 matrix the identity matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @return {goog.vec.Mat4.AnyType} return mat so operations can be chained.
+ */
+goog.vec.Mat4.makeIdentity = function(mat) {
+ mat[0] = 1;
+ mat[1] = 0;
+ mat[2] = 0;
+ mat[3] = 0;
+ mat[4] = 0;
+ mat[5] = 1;
+ mat[6] = 0;
+ mat[7] = 0;
+ mat[8] = 0;
+ mat[9] = 0;
+ mat[10] = 1;
+ mat[11] = 0;
+ mat[12] = 0;
+ mat[13] = 0;
+ mat[14] = 0;
+ mat[15] = 1;
+ return mat;
+};
+
+
+/**
+ * Performs a per-component addition of the matrix mat0 and mat1, storing
+ * the result into resultMat.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat0 The first addend.
+ * @param {goog.vec.Mat4.AnyType} mat1 The second addend.
+ * @param {goog.vec.Mat4.AnyType} resultMat The matrix to
+ * receive the results (may be either mat0 or mat1).
+ * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.addMat = function(mat0, mat1, resultMat) {
+ resultMat[0] = mat0[0] + mat1[0];
+ resultMat[1] = mat0[1] + mat1[1];
+ resultMat[2] = mat0[2] + mat1[2];
+ resultMat[3] = mat0[3] + mat1[3];
+ resultMat[4] = mat0[4] + mat1[4];
+ resultMat[5] = mat0[5] + mat1[5];
+ resultMat[6] = mat0[6] + mat1[6];
+ resultMat[7] = mat0[7] + mat1[7];
+ resultMat[8] = mat0[8] + mat1[8];
+ resultMat[9] = mat0[9] + mat1[9];
+ resultMat[10] = mat0[10] + mat1[10];
+ resultMat[11] = mat0[11] + mat1[11];
+ resultMat[12] = mat0[12] + mat1[12];
+ resultMat[13] = mat0[13] + mat1[13];
+ resultMat[14] = mat0[14] + mat1[14];
+ resultMat[15] = mat0[15] + mat1[15];
+ return resultMat;
+};
+
+
+/**
+ * Performs a per-component subtraction of the matrix mat0 and mat1,
+ * storing the result into resultMat.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat0 The minuend.
+ * @param {goog.vec.Mat4.AnyType} mat1 The subtrahend.
+ * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive
+ * the results (may be either mat0 or mat1).
+ * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.subMat = function(mat0, mat1, resultMat) {
+ resultMat[0] = mat0[0] - mat1[0];
+ resultMat[1] = mat0[1] - mat1[1];
+ resultMat[2] = mat0[2] - mat1[2];
+ resultMat[3] = mat0[3] - mat1[3];
+ resultMat[4] = mat0[4] - mat1[4];
+ resultMat[5] = mat0[5] - mat1[5];
+ resultMat[6] = mat0[6] - mat1[6];
+ resultMat[7] = mat0[7] - mat1[7];
+ resultMat[8] = mat0[8] - mat1[8];
+ resultMat[9] = mat0[9] - mat1[9];
+ resultMat[10] = mat0[10] - mat1[10];
+ resultMat[11] = mat0[11] - mat1[11];
+ resultMat[12] = mat0[12] - mat1[12];
+ resultMat[13] = mat0[13] - mat1[13];
+ resultMat[14] = mat0[14] - mat1[14];
+ resultMat[15] = mat0[15] - mat1[15];
+ return resultMat;
+};
+
+
+/**
+ * Multiplies matrix mat with the given scalar, storing the result
+ * into resultMat.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} scalar The scalar value to multiply to each element of mat.
+ * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive
+ * the results (may be mat).
+ * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.multScalar = function(mat, scalar, resultMat) {
+ resultMat[0] = mat[0] * scalar;
+ resultMat[1] = mat[1] * scalar;
+ resultMat[2] = mat[2] * scalar;
+ resultMat[3] = mat[3] * scalar;
+ resultMat[4] = mat[4] * scalar;
+ resultMat[5] = mat[5] * scalar;
+ resultMat[6] = mat[6] * scalar;
+ resultMat[7] = mat[7] * scalar;
+ resultMat[8] = mat[8] * scalar;
+ resultMat[9] = mat[9] * scalar;
+ resultMat[10] = mat[10] * scalar;
+ resultMat[11] = mat[11] * scalar;
+ resultMat[12] = mat[12] * scalar;
+ resultMat[13] = mat[13] * scalar;
+ resultMat[14] = mat[14] * scalar;
+ resultMat[15] = mat[15] * scalar;
+ return resultMat;
+};
+
+
+/**
+ * Multiplies the two matrices mat0 and mat1 using matrix multiplication,
+ * storing the result into resultMat.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat0 The first (left hand) matrix.
+ * @param {goog.vec.Mat4.AnyType} mat1 The second (right hand) matrix.
+ * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive
+ * the results (may be either mat0 or mat1).
+ * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.multMat = function(mat0, mat1, resultMat) {
+ var a00 = mat0[0], a10 = mat0[1], a20 = mat0[2], a30 = mat0[3];
+ var a01 = mat0[4], a11 = mat0[5], a21 = mat0[6], a31 = mat0[7];
+ var a02 = mat0[8], a12 = mat0[9], a22 = mat0[10], a32 = mat0[11];
+ var a03 = mat0[12], a13 = mat0[13], a23 = mat0[14], a33 = mat0[15];
+
+ var b00 = mat1[0], b10 = mat1[1], b20 = mat1[2], b30 = mat1[3];
+ var b01 = mat1[4], b11 = mat1[5], b21 = mat1[6], b31 = mat1[7];
+ var b02 = mat1[8], b12 = mat1[9], b22 = mat1[10], b32 = mat1[11];
+ var b03 = mat1[12], b13 = mat1[13], b23 = mat1[14], b33 = mat1[15];
+
+ resultMat[0] = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30;
+ resultMat[1] = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30;
+ resultMat[2] = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30;
+ resultMat[3] = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30;
+
+ resultMat[4] = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31;
+ resultMat[5] = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31;
+ resultMat[6] = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31;
+ resultMat[7] = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31;
+
+ resultMat[8] = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32;
+ resultMat[9] = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32;
+ resultMat[10] = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32;
+ resultMat[11] = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32;
+
+ resultMat[12] = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33;
+ resultMat[13] = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33;
+ resultMat[14] = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33;
+ resultMat[15] = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33;
+ return resultMat;
+};
+
+
+/**
+ * Transposes the given matrix mat storing the result into resultMat.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to transpose.
+ * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive
+ * the results (may be mat).
+ * @return {goog.vec.Mat4.AnyType} return resultMat so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.transpose = function(mat, resultMat) {
+ if (resultMat == mat) {
+ var a10 = mat[1], a20 = mat[2], a30 = mat[3];
+ var a21 = mat[6], a31 = mat[7];
+ var a32 = mat[11];
+ resultMat[1] = mat[4];
+ resultMat[2] = mat[8];
+ resultMat[3] = mat[12];
+ resultMat[4] = a10;
+ resultMat[6] = mat[9];
+ resultMat[7] = mat[13];
+ resultMat[8] = a20;
+ resultMat[9] = a21;
+ resultMat[11] = mat[14];
+ resultMat[12] = a30;
+ resultMat[13] = a31;
+ resultMat[14] = a32;
+ } else {
+ resultMat[0] = mat[0];
+ resultMat[1] = mat[4];
+ resultMat[2] = mat[8];
+ resultMat[3] = mat[12];
+
+ resultMat[4] = mat[1];
+ resultMat[5] = mat[5];
+ resultMat[6] = mat[9];
+ resultMat[7] = mat[13];
+
+ resultMat[8] = mat[2];
+ resultMat[9] = mat[6];
+ resultMat[10] = mat[10];
+ resultMat[11] = mat[14];
+
+ resultMat[12] = mat[3];
+ resultMat[13] = mat[7];
+ resultMat[14] = mat[11];
+ resultMat[15] = mat[15];
+ }
+ return resultMat;
+};
+
+
+/**
+ * Computes the determinant of the matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to compute the matrix for.
+ * @return {number} The determinant of the matrix.
+ */
+goog.vec.Mat4.determinant = function(mat) {
+ var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3];
+ var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7];
+ var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11];
+ var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15];
+
+ var a0 = m00 * m11 - m10 * m01;
+ var a1 = m00 * m21 - m20 * m01;
+ var a2 = m00 * m31 - m30 * m01;
+ var a3 = m10 * m21 - m20 * m11;
+ var a4 = m10 * m31 - m30 * m11;
+ var a5 = m20 * m31 - m30 * m21;
+ var b0 = m02 * m13 - m12 * m03;
+ var b1 = m02 * m23 - m22 * m03;
+ var b2 = m02 * m33 - m32 * m03;
+ var b3 = m12 * m23 - m22 * m13;
+ var b4 = m12 * m33 - m32 * m13;
+ var b5 = m22 * m33 - m32 * m23;
+
+ return a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
+};
+
+
+/**
+ * Computes the inverse of mat storing the result into resultMat. If the
+ * inverse is defined, this function returns true, false otherwise.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix to invert.
+ * @param {goog.vec.Mat4.AnyType} resultMat The matrix to receive
+ * the result (may be mat).
+ * @return {boolean} True if the inverse is defined. If false is returned,
+ * resultMat is not modified.
+ */
+goog.vec.Mat4.invert = function(mat, resultMat) {
+ var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3];
+ var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7];
+ var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11];
+ var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15];
+
+ var a0 = m00 * m11 - m10 * m01;
+ var a1 = m00 * m21 - m20 * m01;
+ var a2 = m00 * m31 - m30 * m01;
+ var a3 = m10 * m21 - m20 * m11;
+ var a4 = m10 * m31 - m30 * m11;
+ var a5 = m20 * m31 - m30 * m21;
+ var b0 = m02 * m13 - m12 * m03;
+ var b1 = m02 * m23 - m22 * m03;
+ var b2 = m02 * m33 - m32 * m03;
+ var b3 = m12 * m23 - m22 * m13;
+ var b4 = m12 * m33 - m32 * m13;
+ var b5 = m22 * m33 - m32 * m23;
+
+ var det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
+ if (det == 0) {
+ return false;
+ }
+
+ var idet = 1.0 / det;
+ resultMat[0] = (m11 * b5 - m21 * b4 + m31 * b3) * idet;
+ resultMat[1] = (-m10 * b5 + m20 * b4 - m30 * b3) * idet;
+ resultMat[2] = (m13 * a5 - m23 * a4 + m33 * a3) * idet;
+ resultMat[3] = (-m12 * a5 + m22 * a4 - m32 * a3) * idet;
+ resultMat[4] = (-m01 * b5 + m21 * b2 - m31 * b1) * idet;
+ resultMat[5] = (m00 * b5 - m20 * b2 + m30 * b1) * idet;
+ resultMat[6] = (-m03 * a5 + m23 * a2 - m33 * a1) * idet;
+ resultMat[7] = (m02 * a5 - m22 * a2 + m32 * a1) * idet;
+ resultMat[8] = (m01 * b4 - m11 * b2 + m31 * b0) * idet;
+ resultMat[9] = (-m00 * b4 + m10 * b2 - m30 * b0) * idet;
+ resultMat[10] = (m03 * a4 - m13 * a2 + m33 * a0) * idet;
+ resultMat[11] = (-m02 * a4 + m12 * a2 - m32 * a0) * idet;
+ resultMat[12] = (-m01 * b3 + m11 * b1 - m21 * b0) * idet;
+ resultMat[13] = (m00 * b3 - m10 * b1 + m20 * b0) * idet;
+ resultMat[14] = (-m03 * a3 + m13 * a1 - m23 * a0) * idet;
+ resultMat[15] = (m02 * a3 - m12 * a1 + m22 * a0) * idet;
+ return true;
+};
+
+
+/**
+ * Returns true if the components of mat0 are equal to the components of mat1.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat0 The first matrix.
+ * @param {goog.vec.Mat4.AnyType} mat1 The second matrix.
+ * @return {boolean} True if the the two matrices are equivalent.
+ */
+goog.vec.Mat4.equals = function(mat0, mat1) {
+ return mat0.length == mat1.length && mat0[0] == mat1[0] &&
+ mat0[1] == mat1[1] && mat0[2] == mat1[2] && mat0[3] == mat1[3] &&
+ mat0[4] == mat1[4] && mat0[5] == mat1[5] && mat0[6] == mat1[6] &&
+ mat0[7] == mat1[7] && mat0[8] == mat1[8] && mat0[9] == mat1[9] &&
+ mat0[10] == mat1[10] && mat0[11] == mat1[11] && mat0[12] == mat1[12] &&
+ mat0[13] == mat1[13] && mat0[14] == mat1[14] && mat0[15] == mat1[15];
+};
+
+
+/**
+ * Transforms the given vector with the given matrix storing the resulting,
+ * transformed vector into resultVec. The input vector is multiplied against the
+ * upper 3x4 matrix omitting the projective component.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation.
+ * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform.
+ * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to
+ * receive the results (may be vec).
+ * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.multVec3 = function(mat, vec, resultVec) {
+ var x = vec[0], y = vec[1], z = vec[2];
+ resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + mat[12];
+ resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + mat[13];
+ resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + mat[14];
+ return resultVec;
+};
+
+
+/**
+ * Transforms the given vector with the given matrix storing the resulting,
+ * transformed vector into resultVec. The input vector is multiplied against the
+ * upper 3x3 matrix omitting the projective component and translation
+ * components.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation.
+ * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform.
+ * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector to
+ * receive the results (may be vec).
+ * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.multVec3NoTranslate = function(mat, vec, resultVec) {
+ var x = vec[0], y = vec[1], z = vec[2];
+ resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8];
+ resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9];
+ resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10];
+ return resultVec;
+};
+
+
+/**
+ * Transforms the given vector with the given matrix storing the resulting,
+ * transformed vector into resultVec. The input vector is multiplied against the
+ * full 4x4 matrix with the homogeneous divide applied to reduce the 4 element
+ * vector to a 3 element vector.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation.
+ * @param {goog.vec.Vec3.AnyType} vec The 3 element vector to transform.
+ * @param {goog.vec.Vec3.AnyType} resultVec The 3 element vector
+ * to receive the results (may be vec).
+ * @return {goog.vec.Vec3.AnyType} return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.multVec3Projective = function(mat, vec, resultVec) {
+ var x = vec[0], y = vec[1], z = vec[2];
+ var invw = 1 / (x * mat[3] + y * mat[7] + z * mat[11] + mat[15]);
+ resultVec[0] = (x * mat[0] + y * mat[4] + z * mat[8] + mat[12]) * invw;
+ resultVec[1] = (x * mat[1] + y * mat[5] + z * mat[9] + mat[13]) * invw;
+ resultVec[2] = (x * mat[2] + y * mat[6] + z * mat[10] + mat[14]) * invw;
+ return resultVec;
+};
+
+
+/**
+ * Transforms the given vector with the given matrix storing the resulting,
+ * transformed vector into resultVec.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix supplying the transformation.
+ * @param {goog.vec.Vec4.AnyType} vec The vector to transform.
+ * @param {goog.vec.Vec4.AnyType} resultVec The vector to
+ * receive the results (may be vec).
+ * @return {goog.vec.Vec4.AnyType} return resultVec so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.multVec4 = function(mat, vec, resultVec) {
+ var x = vec[0], y = vec[1], z = vec[2], w = vec[3];
+ resultVec[0] = x * mat[0] + y * mat[4] + z * mat[8] + w * mat[12];
+ resultVec[1] = x * mat[1] + y * mat[5] + z * mat[9] + w * mat[13];
+ resultVec[2] = x * mat[2] + y * mat[6] + z * mat[10] + w * mat[14];
+ resultVec[3] = x * mat[3] + y * mat[7] + z * mat[11] + w * mat[15];
+ return resultVec;
+};
+
+
+/**
+ * Makes the given 4x4 matrix a translation matrix with x, y and z
+ * translation factors.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} x The translation along the x axis.
+ * @param {number} y The translation along the y axis.
+ * @param {number} z The translation along the z axis.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeTranslate = function(mat, x, y, z) {
+ goog.vec.Mat4.makeIdentity(mat);
+ return goog.vec.Mat4.setColumnValues(mat, 3, x, y, z, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix as a scale matrix with x, y and z scale factors.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} x The scale along the x axis.
+ * @param {number} y The scale along the y axis.
+ * @param {number} z The scale along the z axis.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeScale = function(mat, x, y, z) {
+ goog.vec.Mat4.makeIdentity(mat);
+ return goog.vec.Mat4.setDiagonalValues(mat, x, y, z, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix a rotation matrix with the given rotation
+ * angle about the axis defined by the vector (ax, ay, az).
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The rotation angle in radians.
+ * @param {number} ax The x component of the rotation axis.
+ * @param {number} ay The y component of the rotation axis.
+ * @param {number} az The z component of the rotation axis.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeRotate = function(mat, angle, ax, ay, az) {
+ var c = Math.cos(angle);
+ var d = 1 - c;
+ var s = Math.sin(angle);
+
+ return goog.vec.Mat4.setFromValues(
+ mat, ax * ax * d + c, ax * ay * d + az * s, ax * az * d - ay * s, 0,
+
+ ax * ay * d - az * s, ay * ay * d + c, ay * az * d + ax * s, 0,
+
+ ax * az * d + ay * s, ay * az * d - ax * s, az * az * d + c, 0,
+
+ 0, 0, 0, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix a rotation matrix with the given rotation
+ * angle about the X axis.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The rotation angle in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeRotateX = function(mat, angle) {
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+ return goog.vec.Mat4.setFromValues(
+ mat, 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix a rotation matrix with the given rotation
+ * angle about the Y axis.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The rotation angle in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeRotateY = function(mat, angle) {
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+ return goog.vec.Mat4.setFromValues(
+ mat, c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix a rotation matrix with the given rotation
+ * angle about the Z axis.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The rotation angle in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeRotateZ = function(mat, angle) {
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+ return goog.vec.Mat4.setFromValues(
+ mat, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix a perspective projection matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} left The coordinate of the left clipping plane.
+ * @param {number} right The coordinate of the right clipping plane.
+ * @param {number} bottom The coordinate of the bottom clipping plane.
+ * @param {number} top The coordinate of the top clipping plane.
+ * @param {number} near The distance to the near clipping plane.
+ * @param {number} far The distance to the far clipping plane.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeFrustum = function(mat, left, right, bottom, top, near, far) {
+ var x = (2 * near) / (right - left);
+ var y = (2 * near) / (top - bottom);
+ var a = (right + left) / (right - left);
+ var b = (top + bottom) / (top - bottom);
+ var c = -(far + near) / (far - near);
+ var d = -(2 * far * near) / (far - near);
+
+ return goog.vec.Mat4.setFromValues(
+ mat, x, 0, 0, 0, 0, y, 0, 0, a, b, c, -1, 0, 0, d, 0);
+};
+
+
+/**
+ * Makes the given 4x4 matrix perspective projection matrix given a
+ * field of view and aspect ratio.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} fovy The field of view along the y (vertical) axis in
+ * radians.
+ * @param {number} aspect The x (width) to y (height) aspect ratio.
+ * @param {number} near The distance to the near clipping plane.
+ * @param {number} far The distance to the far clipping plane.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makePerspective = function(mat, fovy, aspect, near, far) {
+ var angle = fovy / 2;
+ var dz = far - near;
+ var sinAngle = Math.sin(angle);
+ if (dz == 0 || sinAngle == 0 || aspect == 0) {
+ return mat;
+ }
+
+ var cot = Math.cos(angle) / sinAngle;
+ return goog.vec.Mat4.setFromValues(
+ mat, cot / aspect, 0, 0, 0, 0, cot, 0, 0, 0, 0, -(far + near) / dz, -1, 0,
+ 0, -(2 * near * far) / dz, 0);
+};
+
+
+/**
+ * Makes the given 4x4 matrix an orthographic projection matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} left The coordinate of the left clipping plane.
+ * @param {number} right The coordinate of the right clipping plane.
+ * @param {number} bottom The coordinate of the bottom clipping plane.
+ * @param {number} top The coordinate of the top clipping plane.
+ * @param {number} near The distance to the near clipping plane.
+ * @param {number} far The distance to the far clipping plane.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeOrtho = function(mat, left, right, bottom, top, near, far) {
+ var x = 2 / (right - left);
+ var y = 2 / (top - bottom);
+ var z = -2 / (far - near);
+ var a = -(right + left) / (right - left);
+ var b = -(top + bottom) / (top - bottom);
+ var c = -(far + near) / (far - near);
+
+ return goog.vec.Mat4.setFromValues(
+ mat, x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, a, b, c, 1);
+};
+
+
+/**
+ * Makes the given 4x4 matrix a modelview matrix of a camera so that
+ * the camera is 'looking at' the given center point.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point
+ * (camera origin).
+ * @param {goog.vec.Vec3.AnyType} centerPt The point to aim the camera at.
+ * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that identifies
+ * the up direction for the camera.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeLookAt = function(mat, eyePt, centerPt, worldUpVec) {
+ // Compute the direction vector from the eye point to the center point and
+ // normalize.
+ var fwdVec = goog.vec.Mat4.tmpVec4_[0];
+ goog.vec.Vec3.subtract(centerPt, eyePt, fwdVec);
+ goog.vec.Vec3.normalize(fwdVec, fwdVec);
+ fwdVec[3] = 0;
+
+ // Compute the side vector from the forward vector and the input up vector.
+ var sideVec = goog.vec.Mat4.tmpVec4_[1];
+ goog.vec.Vec3.cross(fwdVec, worldUpVec, sideVec);
+ goog.vec.Vec3.normalize(sideVec, sideVec);
+ sideVec[3] = 0;
+
+ // Now the up vector to form the orthonormal basis.
+ var upVec = goog.vec.Mat4.tmpVec4_[2];
+ goog.vec.Vec3.cross(sideVec, fwdVec, upVec);
+ goog.vec.Vec3.normalize(upVec, upVec);
+ upVec[3] = 0;
+
+ // Update the view matrix with the new orthonormal basis and position the
+ // camera at the given eye point.
+ goog.vec.Vec3.negate(fwdVec, fwdVec);
+ goog.vec.Mat4.setRow(mat, 0, sideVec);
+ goog.vec.Mat4.setRow(mat, 1, upVec);
+ goog.vec.Mat4.setRow(mat, 2, fwdVec);
+ goog.vec.Mat4.setRowValues(mat, 3, 0, 0, 0, 1);
+ goog.vec.Mat4.translate(mat, -eyePt[0], -eyePt[1], -eyePt[2]);
+
+ return mat;
+};
+
+
+/**
+ * Decomposes a matrix into the lookAt vectors eyePt, fwdVec and worldUpVec.
+ * The matrix represents the modelview matrix of a camera. It is the inverse
+ * of lookAt except for the output of the fwdVec instead of centerPt.
+ * The centerPt itself cannot be recovered from a modelview matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {goog.vec.Vec3.AnyType} eyePt The position of the eye point
+ * (camera origin).
+ * @param {goog.vec.Vec3.AnyType} fwdVec The vector describing where
+ * the camera points to.
+ * @param {goog.vec.Vec3.AnyType} worldUpVec The vector that
+ * identifies the up direction for the camera.
+ * @return {boolean} True if the method succeeds, false otherwise.
+ * The method can only fail if the inverse of viewMatrix is not defined.
+ */
+goog.vec.Mat4.toLookAt = function(mat, eyePt, fwdVec, worldUpVec) {
+ // Get eye of the camera.
+ var matInverse = goog.vec.Mat4.tmpMat4_[0];
+ if (!goog.vec.Mat4.invert(mat, matInverse)) {
+ // The input matrix does not have a valid inverse.
+ return false;
+ }
+
+ if (eyePt) {
+ eyePt[0] = matInverse[12];
+ eyePt[1] = matInverse[13];
+ eyePt[2] = matInverse[14];
+ }
+
+ // Get forward vector from the definition of lookAt.
+ if (fwdVec || worldUpVec) {
+ if (!fwdVec) {
+ fwdVec = goog.vec.Mat4.tmpVec3_[0];
+ }
+ fwdVec[0] = -mat[2];
+ fwdVec[1] = -mat[6];
+ fwdVec[2] = -mat[10];
+ // Normalize forward vector.
+ goog.vec.Vec3.normalize(fwdVec, fwdVec);
+ }
+
+ if (worldUpVec) {
+ // Get side vector from the definition of gluLookAt.
+ var side = goog.vec.Mat4.tmpVec3_[1];
+ side[0] = mat[0];
+ side[1] = mat[4];
+ side[2] = mat[8];
+ // Compute up vector as a up = side x forward.
+ goog.vec.Vec3.cross(side, fwdVec, worldUpVec);
+ // Normalize up vector.
+ goog.vec.Vec3.normalize(worldUpVec, worldUpVec);
+ }
+ return true;
+};
+
+
+/**
+ * Makes the given 4x4 matrix a rotation matrix given Euler angles using
+ * the ZXZ convention.
+ * Given the euler angles [theta1, theta2, theta3], the rotation is defined as
+ * rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3),
+ * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi].
+ * rotation_x(theta) means rotation around the X axis of theta radians,
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} theta1 The angle of rotation around the Z axis in radians.
+ * @param {number} theta2 The angle of rotation around the X axis in radians.
+ * @param {number} theta3 The angle of rotation around the Z axis in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.makeEulerZXZ = function(mat, theta1, theta2, theta3) {
+ var c1 = Math.cos(theta1);
+ var s1 = Math.sin(theta1);
+
+ var c2 = Math.cos(theta2);
+ var s2 = Math.sin(theta2);
+
+ var c3 = Math.cos(theta3);
+ var s3 = Math.sin(theta3);
+
+ mat[0] = c1 * c3 - c2 * s1 * s3;
+ mat[1] = c2 * c1 * s3 + c3 * s1;
+ mat[2] = s3 * s2;
+ mat[3] = 0;
+
+ mat[4] = -c1 * s3 - c3 * c2 * s1;
+ mat[5] = c1 * c2 * c3 - s1 * s3;
+ mat[6] = c3 * s2;
+ mat[7] = 0;
+
+ mat[8] = s2 * s1;
+ mat[9] = -c1 * s2;
+ mat[10] = c2;
+ mat[11] = 0;
+
+ mat[12] = 0;
+ mat[13] = 0;
+ mat[14] = 0;
+ mat[15] = 1;
+
+ return mat;
+};
+
+
+/**
+ * Decomposes a rotation matrix into Euler angles using the ZXZ convention so
+ * that rotation = rotation_z(theta1) * rotation_x(theta2) * rotation_z(theta3),
+ * with theta1 in [0, 2 * pi], theta2 in [0, pi] and theta3 in [0, 2 * pi].
+ * rotation_x(theta) means rotation around the X axis of theta radians.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {goog.vec.Vec3.AnyType} euler The ZXZ Euler angles in
+ * radians as [theta1, theta2, theta3].
+ * @param {boolean=} opt_theta2IsNegative Whether theta2 is in [-pi, 0] instead
+ * of the default [0, pi].
+ * @return {goog.vec.Vec4.AnyType} return euler so that operations can be
+ * chained together.
+ */
+goog.vec.Mat4.toEulerZXZ = function(mat, euler, opt_theta2IsNegative) {
+ // There is an ambiguity in the sign of sinTheta2 because of the sqrt.
+ var sinTheta2 = Math.sqrt(mat[2] * mat[2] + mat[6] * mat[6]);
+
+ // By default we explicitely constrain theta2 to be in [0, pi],
+ // so sinTheta2 is always positive. We can change the behavior and specify
+ // theta2 to be negative in [-pi, 0] with opt_Theta2IsNegative.
+ var signTheta2 = opt_theta2IsNegative ? -1 : 1;
+
+ if (sinTheta2 > goog.vec.EPSILON) {
+ euler[2] = Math.atan2(mat[2] * signTheta2, mat[6] * signTheta2);
+ euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]);
+ euler[0] = Math.atan2(mat[8] * signTheta2, -mat[9] * signTheta2);
+ } else {
+ // There is also an arbitrary choice for theta1 = 0 or theta2 = 0 here.
+ // We assume theta1 = 0 as some applications do not allow the camera to roll
+ // (i.e. have theta1 != 0).
+ euler[0] = 0;
+ euler[1] = Math.atan2(sinTheta2 * signTheta2, mat[10]);
+ euler[2] = Math.atan2(mat[1], mat[0]);
+ }
+
+ // Atan2 outputs angles in [-pi, pi] so we bring them back to [0, 2 * pi].
+ euler[0] = (euler[0] + Math.PI * 2) % (Math.PI * 2);
+ euler[2] = (euler[2] + Math.PI * 2) % (Math.PI * 2);
+ // For theta2 we want the angle to be in [0, pi] or [-pi, 0] depending on
+ // signTheta2.
+ euler[1] =
+ ((euler[1] * signTheta2 + Math.PI * 2) % (Math.PI * 2)) * signTheta2;
+
+ return euler;
+};
+
+
+/**
+ * Translates the given matrix by x,y,z. Equvialent to:
+ * goog.vec.Mat4.multMat(
+ * mat,
+ * goog.vec.Mat4.makeTranslate(goog.vec.Mat4.create(), x, y, z),
+ * mat);
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} x The translation along the x axis.
+ * @param {number} y The translation along the y axis.
+ * @param {number} z The translation along the z axis.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.translate = function(mat, x, y, z) {
+ return goog.vec.Mat4.setColumnValues(
+ mat, 3, mat[0] * x + mat[4] * y + mat[8] * z + mat[12],
+ mat[1] * x + mat[5] * y + mat[9] * z + mat[13],
+ mat[2] * x + mat[6] * y + mat[10] * z + mat[14],
+ mat[3] * x + mat[7] * y + mat[11] * z + mat[15]);
+};
+
+
+/**
+ * Scales the given matrix by x,y,z. Equivalent to:
+ * goog.vec.Mat4.multMat(
+ * mat,
+ * goog.vec.Mat4.makeScale(goog.vec.Mat4.create(), x, y, z),
+ * mat);
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} x The x scale factor.
+ * @param {number} y The y scale factor.
+ * @param {number} z The z scale factor.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.scale = function(mat, x, y, z) {
+ return goog.vec.Mat4.setFromValues(
+ mat, mat[0] * x, mat[1] * x, mat[2] * x, mat[3] * x, mat[4] * y,
+ mat[5] * y, mat[6] * y, mat[7] * y, mat[8] * z, mat[9] * z, mat[10] * z,
+ mat[11] * z, mat[12], mat[13], mat[14], mat[15]);
+};
+
+
+/**
+ * Rotate the given matrix by angle about the x,y,z axis. Equivalent to:
+ * goog.vec.Mat4.multMat(
+ * mat,
+ * goog.vec.Mat4.makeRotate(goog.vec.Mat4.create(), angle, x, y, z),
+ * mat);
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The angle in radians.
+ * @param {number} x The x component of the rotation axis.
+ * @param {number} y The y component of the rotation axis.
+ * @param {number} z The z component of the rotation axis.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.rotate = function(mat, angle, x, y, z) {
+ var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3];
+ var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7];
+ var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11];
+ var m03 = mat[12], m13 = mat[13], m23 = mat[14], m33 = mat[15];
+
+ var cosAngle = Math.cos(angle);
+ var sinAngle = Math.sin(angle);
+ var diffCosAngle = 1 - cosAngle;
+ var r00 = x * x * diffCosAngle + cosAngle;
+ var r10 = x * y * diffCosAngle + z * sinAngle;
+ var r20 = x * z * diffCosAngle - y * sinAngle;
+
+ var r01 = x * y * diffCosAngle - z * sinAngle;
+ var r11 = y * y * diffCosAngle + cosAngle;
+ var r21 = y * z * diffCosAngle + x * sinAngle;
+
+ var r02 = x * z * diffCosAngle + y * sinAngle;
+ var r12 = y * z * diffCosAngle - x * sinAngle;
+ var r22 = z * z * diffCosAngle + cosAngle;
+
+ return goog.vec.Mat4.setFromValues(
+ mat, m00 * r00 + m01 * r10 + m02 * r20, m10 * r00 + m11 * r10 + m12 * r20,
+ m20 * r00 + m21 * r10 + m22 * r20, m30 * r00 + m31 * r10 + m32 * r20,
+
+ m00 * r01 + m01 * r11 + m02 * r21, m10 * r01 + m11 * r11 + m12 * r21,
+ m20 * r01 + m21 * r11 + m22 * r21, m30 * r01 + m31 * r11 + m32 * r21,
+
+ m00 * r02 + m01 * r12 + m02 * r22, m10 * r02 + m11 * r12 + m12 * r22,
+ m20 * r02 + m21 * r12 + m22 * r22, m30 * r02 + m31 * r12 + m32 * r22,
+
+ m03, m13, m23, m33);
+};
+
+
+/**
+ * Rotate the given matrix by angle about the x axis. Equivalent to:
+ * goog.vec.Mat4.multMat(
+ * mat,
+ * goog.vec.Mat4.makeRotateX(goog.vec.Mat4.create(), angle),
+ * mat);
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The angle in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.rotateX = function(mat, angle) {
+ var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7];
+ var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11];
+
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+
+ mat[4] = m01 * c + m02 * s;
+ mat[5] = m11 * c + m12 * s;
+ mat[6] = m21 * c + m22 * s;
+ mat[7] = m31 * c + m32 * s;
+ mat[8] = m01 * -s + m02 * c;
+ mat[9] = m11 * -s + m12 * c;
+ mat[10] = m21 * -s + m22 * c;
+ mat[11] = m31 * -s + m32 * c;
+
+ return mat;
+};
+
+
+/**
+ * Rotate the given matrix by angle about the y axis. Equivalent to:
+ * goog.vec.Mat4.multMat(
+ * mat,
+ * goog.vec.Mat4.makeRotateY(goog.vec.Mat4.create(), angle),
+ * mat);
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The angle in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.rotateY = function(mat, angle) {
+ var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3];
+ var m02 = mat[8], m12 = mat[9], m22 = mat[10], m32 = mat[11];
+
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+
+ mat[0] = m00 * c + m02 * -s;
+ mat[1] = m10 * c + m12 * -s;
+ mat[2] = m20 * c + m22 * -s;
+ mat[3] = m30 * c + m32 * -s;
+ mat[8] = m00 * s + m02 * c;
+ mat[9] = m10 * s + m12 * c;
+ mat[10] = m20 * s + m22 * c;
+ mat[11] = m30 * s + m32 * c;
+
+ return mat;
+};
+
+
+/**
+ * Rotate the given matrix by angle about the z axis. Equivalent to:
+ * goog.vec.Mat4.multMat(
+ * mat,
+ * goog.vec.Mat4.makeRotateZ(goog.vec.Mat4.create(), angle),
+ * mat);
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The matrix.
+ * @param {number} angle The angle in radians.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.rotateZ = function(mat, angle) {
+ var m00 = mat[0], m10 = mat[1], m20 = mat[2], m30 = mat[3];
+ var m01 = mat[4], m11 = mat[5], m21 = mat[6], m31 = mat[7];
+
+ var c = Math.cos(angle);
+ var s = Math.sin(angle);
+
+ mat[0] = m00 * c + m01 * s;
+ mat[1] = m10 * c + m11 * s;
+ mat[2] = m20 * c + m21 * s;
+ mat[3] = m30 * c + m31 * s;
+ mat[4] = m00 * -s + m01 * c;
+ mat[5] = m10 * -s + m11 * c;
+ mat[6] = m20 * -s + m21 * c;
+ mat[7] = m30 * -s + m31 * c;
+
+ return mat;
+};
+
+
+/**
+ * Retrieves the translation component of the transformation matrix.
+ *
+ * @param {goog.vec.Mat4.AnyType} mat The transformation matrix.
+ * @param {goog.vec.Vec3.AnyType} translation The vector for storing the
+ * result.
+ * @return {goog.vec.Mat4.AnyType} return mat so that operations can be
+ * chained.
+ */
+goog.vec.Mat4.getTranslation = function(mat, translation) {
+ translation[0] = mat[12];
+ translation[1] = mat[13];
+ translation[2] = mat[14];
+ return translation;
+};
+
+
+/**
+ * @type {!Array<!goog.vec.Vec3.Type>}
+ * @private
+ */
+goog.vec.Mat4.tmpVec3_ =
+ [goog.vec.Vec3.createFloat64(), goog.vec.Vec3.createFloat64()];
+
+
+/**
+ * @type {!Array<!goog.vec.Vec4.Type>}
+ * @private
+ */
+goog.vec.Mat4.tmpVec4_ = [
+ goog.vec.Vec4.createFloat64(), goog.vec.Vec4.createFloat64(),
+ goog.vec.Vec4.createFloat64()
+];
+
+
+/**
+ * @type {!Array<!goog.vec.Mat4.Type>}
+ * @private
+ */
+goog.vec.Mat4.tmpMat4_ = [goog.vec.Mat4.createFloat64()];
+
+goog.provide('ol.geom.flat.transform');
+
+goog.require('goog.vec.Mat4');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @return {Array.<number>} Transformed coordinates.
+ */
+ol.geom.flat.transform.transform2D = function(flatCoordinates, offset, end, stride, transform, opt_dest) {
+ var m00 = goog.vec.Mat4.getElement(transform, 0, 0);
+ var m10 = goog.vec.Mat4.getElement(transform, 1, 0);
+ var m01 = goog.vec.Mat4.getElement(transform, 0, 1);
+ var m11 = goog.vec.Mat4.getElement(transform, 1, 1);
+ var m03 = goog.vec.Mat4.getElement(transform, 0, 3);
+ var m13 = goog.vec.Mat4.getElement(transform, 1, 3);
+ var dest = opt_dest ? opt_dest : [];
+ var i = 0;
+ var j;
+ for (j = offset; j < end; j += stride) {
+ var x = flatCoordinates[j];
+ var y = flatCoordinates[j + 1];
+ dest[i++] = m00 * x + m01 * y + m03;
+ dest[i++] = m10 * x + m11 * y + m13;
+ }
+ if (opt_dest && dest.length != i) {
+ dest.length = i;
+ }
+ return dest;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} angle Angle.
+ * @param {Array.<number>} anchor Rotation anchor point.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @return {Array.<number>} Transformed coordinates.
+ */
+ol.geom.flat.transform.rotate = function(flatCoordinates, offset, end, stride, angle, anchor, opt_dest) {
+ var dest = opt_dest ? opt_dest : [];
+ var cos = Math.cos(angle);
+ var sin = Math.sin(angle);
+ var anchorX = anchor[0];
+ var anchorY = anchor[1];
+ var i = 0;
+ for (var j = offset; j < end; j += stride) {
+ var deltaX = flatCoordinates[j] - anchorX;
+ var deltaY = flatCoordinates[j + 1] - anchorY;
+ dest[i++] = anchorX + deltaX * cos - deltaY * sin;
+ dest[i++] = anchorY + deltaX * sin + deltaY * cos;
+ for (var k = j + 2; k < j + stride; ++k) {
+ dest[i++] = flatCoordinates[k];
+ }
+ }
+ if (opt_dest && dest.length != i) {
+ dest.length = i;
+ }
+ return dest;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} deltaX Delta X.
+ * @param {number} deltaY Delta Y.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @return {Array.<number>} Transformed coordinates.
+ */
+ol.geom.flat.transform.translate = function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) {
+ var dest = opt_dest ? opt_dest : [];
+ var i = 0;
+ var j, k;
+ for (j = offset; j < end; j += stride) {
+ dest[i++] = flatCoordinates[j] + deltaX;
+ dest[i++] = flatCoordinates[j + 1] + deltaY;
+ for (k = j + 2; k < j + stride; ++k) {
+ dest[i++] = flatCoordinates[k];
+ }
+ }
+ if (opt_dest && dest.length != i) {
+ dest.length = i;
+ }
+ return dest;
+};
+
+goog.provide('ol.geom.SimpleGeometry');
+
+goog.require('goog.asserts');
+goog.require('ol.functions');
+goog.require('ol.extent');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.flat.transform');
+goog.require('ol.object');
+
+
+/**
+ * @classdesc
+ * Abstract base class; only used for creating subclasses; do not instantiate
+ * in apps, as cannot be rendered.
+ *
+ * @constructor
+ * @extends {ol.geom.Geometry}
+ * @api stable
+ */
+ol.geom.SimpleGeometry = function() {
+
+ ol.geom.Geometry.call(this);
+
+ /**
+ * @protected
+ * @type {ol.geom.GeometryLayout}
+ */
+ this.layout = ol.geom.GeometryLayout.XY;
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.stride = 2;
+
+ /**
+ * @protected
+ * @type {Array.<number>}
+ */
+ this.flatCoordinates = null;
+
+};
+ol.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry);
+
+
+/**
+ * @param {number} stride Stride.
+ * @private
+ * @return {ol.geom.GeometryLayout} layout Layout.
+ */
+ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) {
+ if (stride == 2) {
+ return ol.geom.GeometryLayout.XY;
+ } else if (stride == 3) {
+ return ol.geom.GeometryLayout.XYZ;
+ } else if (stride == 4) {
+ return ol.geom.GeometryLayout.XYZM;
+ } else {
+ goog.asserts.fail('unsupported stride: ' + stride);
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @return {number} Stride.
+ */
+ol.geom.SimpleGeometry.getStrideForLayout = function(layout) {
+ if (layout == ol.geom.GeometryLayout.XY) {
+ return 2;
+ } else if (layout == ol.geom.GeometryLayout.XYZ) {
+ return 3;
+ } else if (layout == ol.geom.GeometryLayout.XYM) {
+ return 3;
+ } else if (layout == ol.geom.GeometryLayout.XYZM) {
+ return 4;
+ } else {
+ goog.asserts.fail('unsupported layout: ' + layout);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.SimpleGeometry.prototype.containsXY = ol.functions.FALSE;
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) {
+ return ol.extent.createOrUpdateFromFlatCoordinates(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ extent);
+};
+
+
+/**
+ * @return {Array} Coordinates.
+ */
+ol.geom.SimpleGeometry.prototype.getCoordinates = goog.abstractMethod;
+
+
+/**
+ * Return the first coordinate of the geometry.
+ * @return {ol.Coordinate} First coordinate.
+ * @api stable
+ */
+ol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() {
+ return this.flatCoordinates.slice(0, this.stride);
+};
+
+
+/**
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() {
+ return this.flatCoordinates;
+};
+
+
+/**
+ * Return the last coordinate of the geometry.
+ * @return {ol.Coordinate} Last point.
+ * @api stable
+ */
+ol.geom.SimpleGeometry.prototype.getLastCoordinate = function() {
+ return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);
+};
+
+
+/**
+ * Return the {@link ol.geom.GeometryLayout layout} of the geometry.
+ * @return {ol.geom.GeometryLayout} Layout.
+ * @api stable
+ */
+ol.geom.SimpleGeometry.prototype.getLayout = function() {
+ return this.layout;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {
+ if (this.simplifiedGeometryRevision != this.getRevision()) {
+ ol.object.clear(this.simplifiedGeometryCache);
+ this.simplifiedGeometryMaxMinSquaredTolerance = 0;
+ this.simplifiedGeometryRevision = this.getRevision();
+ }
+ // If squaredTolerance is negative or if we know that simplification will not
+ // have any effect then just return this.
+ if (squaredTolerance < 0 ||
+ (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
+ squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {
+ return this;
+ }
+ var key = squaredTolerance.toString();
+ if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
+ return this.simplifiedGeometryCache[key];
+ } else {
+ var simplifiedGeometry =
+ this.getSimplifiedGeometryInternal(squaredTolerance);
+ var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();
+ if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {
+ this.simplifiedGeometryCache[key] = simplifiedGeometry;
+ return simplifiedGeometry;
+ } else {
+ // Simplification did not actually remove any coordinates. We now know
+ // that any calls to getSimplifiedGeometry with a squaredTolerance less
+ // than or equal to the current squaredTolerance will also not have any
+ // effect. This allows us to short circuit simplification (saving CPU
+ // cycles) and prevents the cache of simplified geometries from filling
+ // up with useless identical copies of this geometry (saving memory).
+ this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
+ return this;
+ }
+ }
+};
+
+
+/**
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {ol.geom.SimpleGeometry} Simplified geometry.
+ * @protected
+ */
+ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
+ return this;
+};
+
+
+/**
+ * @return {number} Stride.
+ */
+ol.geom.SimpleGeometry.prototype.getStride = function() {
+ return this.stride;
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @protected
+ */
+ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = function(layout, flatCoordinates) {
+ this.stride = ol.geom.SimpleGeometry.getStrideForLayout(layout);
+ this.layout = layout;
+ this.flatCoordinates = flatCoordinates;
+};
+
+
+/**
+ * @param {Array} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ */
+ol.geom.SimpleGeometry.prototype.setCoordinates = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.GeometryLayout|undefined} layout Layout.
+ * @param {Array} coordinates Coordinates.
+ * @param {number} nesting Nesting.
+ * @protected
+ */
+ol.geom.SimpleGeometry.prototype.setLayout = function(layout, coordinates, nesting) {
+ /** @type {number} */
+ var stride;
+ if (layout) {
+ stride = ol.geom.SimpleGeometry.getStrideForLayout(layout);
+ } else {
+ var i;
+ for (i = 0; i < nesting; ++i) {
+ if (coordinates.length === 0) {
+ this.layout = ol.geom.GeometryLayout.XY;
+ this.stride = 2;
+ return;
+ } else {
+ coordinates = /** @type {Array} */ (coordinates[0]);
+ }
+ }
+ stride = coordinates.length;
+ layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride);
+ }
+ this.layout = layout;
+ this.stride = stride;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) {
+ if (this.flatCoordinates) {
+ transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);
+ this.changed();
+ }
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.geom.SimpleGeometry.prototype.rotate = function(angle, anchor) {
+ var flatCoordinates = this.getFlatCoordinates();
+ if (flatCoordinates) {
+ var stride = this.getStride();
+ ol.geom.flat.transform.rotate(
+ flatCoordinates, 0, flatCoordinates.length,
+ stride, angle, anchor, flatCoordinates);
+ this.changed();
+ }
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) {
+ var flatCoordinates = this.getFlatCoordinates();
+ if (flatCoordinates) {
+ var stride = this.getStride();
+ ol.geom.flat.transform.translate(
+ flatCoordinates, 0, flatCoordinates.length, stride,
+ deltaX, deltaY, flatCoordinates);
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @return {Array.<number>} Transformed flat coordinates.
+ */
+ol.geom.transformSimpleGeometry2D = function(simpleGeometry, transform, opt_dest) {
+ var flatCoordinates = simpleGeometry.getFlatCoordinates();
+ if (!flatCoordinates) {
+ return null;
+ } else {
+ var stride = simpleGeometry.getStride();
+ return ol.geom.flat.transform.transform2D(
+ flatCoordinates, 0, flatCoordinates.length, stride,
+ transform, opt_dest);
+ }
+};
+
+goog.provide('ol.geom.flat.area');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @return {number} Area.
+ */
+ol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) {
+ var twiceArea = 0;
+ var x1 = flatCoordinates[end - stride];
+ var y1 = flatCoordinates[end - stride + 1];
+ for (; offset < end; offset += stride) {
+ var x2 = flatCoordinates[offset];
+ var y2 = flatCoordinates[offset + 1];
+ twiceArea += y1 * x2 - x1 * y2;
+ x1 = x2;
+ y1 = y2;
+ }
+ return twiceArea / 2;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @return {number} Area.
+ */
+ol.geom.flat.area.linearRings = function(flatCoordinates, offset, ends, stride) {
+ var area = 0;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride);
+ offset = end;
+ }
+ return area;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @return {number} Area.
+ */
+ol.geom.flat.area.linearRingss = function(flatCoordinates, offset, endss, stride) {
+ var area = 0;
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ area +=
+ ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride);
+ offset = ends[ends.length - 1];
+ }
+ return area;
+};
+
+goog.provide('ol.geom.flat.closest');
+
+goog.require('goog.asserts');
+goog.require('ol.math');
+
+
+/**
+ * Returns the point on the 2D line segment flatCoordinates[offset1] to
+ * flatCoordinates[offset2] that is closest to the point (x, y). Extra
+ * dimensions are linearly interpolated.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset1 Offset 1.
+ * @param {number} offset2 Offset 2.
+ * @param {number} stride Stride.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {Array.<number>} closestPoint Closest point.
+ */
+ol.geom.flat.closest.point = function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {
+ var x1 = flatCoordinates[offset1];
+ var y1 = flatCoordinates[offset1 + 1];
+ var dx = flatCoordinates[offset2] - x1;
+ var dy = flatCoordinates[offset2 + 1] - y1;
+ var i, offset;
+ if (dx === 0 && dy === 0) {
+ offset = offset1;
+ } else {
+ var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
+ if (t > 1) {
+ offset = offset2;
+ } else if (t > 0) {
+ for (i = 0; i < stride; ++i) {
+ closestPoint[i] = ol.math.lerp(flatCoordinates[offset1 + i],
+ flatCoordinates[offset2 + i], t);
+ }
+ closestPoint.length = stride;
+ return;
+ } else {
+ offset = offset1;
+ }
+ }
+ for (i = 0; i < stride; ++i) {
+ closestPoint[i] = flatCoordinates[offset + i];
+ }
+ closestPoint.length = stride;
+};
+
+
+/**
+ * Return the squared of the largest distance between any pair of consecutive
+ * coordinates.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} maxSquaredDelta Max squared delta.
+ * @return {number} Max squared delta.
+ */
+ol.geom.flat.closest.getMaxSquaredDelta = function(flatCoordinates, offset, end, stride, maxSquaredDelta) {
+ var x1 = flatCoordinates[offset];
+ var y1 = flatCoordinates[offset + 1];
+ for (offset += stride; offset < end; offset += stride) {
+ var x2 = flatCoordinates[offset];
+ var y2 = flatCoordinates[offset + 1];
+ var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2);
+ if (squaredDelta > maxSquaredDelta) {
+ maxSquaredDelta = squaredDelta;
+ }
+ x1 = x2;
+ y1 = y2;
+ }
+ return maxSquaredDelta;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {number} maxSquaredDelta Max squared delta.
+ * @return {number} Max squared delta.
+ */
+ol.geom.flat.closest.getsMaxSquaredDelta = function(flatCoordinates, offset, ends, stride, maxSquaredDelta) {
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta(
+ flatCoordinates, offset, end, stride, maxSquaredDelta);
+ offset = end;
+ }
+ return maxSquaredDelta;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {number} maxSquaredDelta Max squared delta.
+ * @return {number} Max squared delta.
+ */
+ol.geom.flat.closest.getssMaxSquaredDelta = function(flatCoordinates, offset, endss, stride, maxSquaredDelta) {
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta(
+ flatCoordinates, offset, ends, stride, maxSquaredDelta);
+ offset = ends[ends.length - 1];
+ }
+ return maxSquaredDelta;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} maxDelta Max delta.
+ * @param {boolean} isRing Is ring.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {Array.<number>} closestPoint Closest point.
+ * @param {number} minSquaredDistance Minimum squared distance.
+ * @param {Array.<number>=} opt_tmpPoint Temporary point object.
+ * @return {number} Minimum squared distance.
+ */
+ol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end,
+ stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
+ opt_tmpPoint) {
+ if (offset == end) {
+ return minSquaredDistance;
+ }
+ var i, squaredDistance;
+ if (maxDelta === 0) {
+ // All points are identical, so just test the first point.
+ squaredDistance = ol.math.squaredDistance(
+ x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);
+ if (squaredDistance < minSquaredDistance) {
+ for (i = 0; i < stride; ++i) {
+ closestPoint[i] = flatCoordinates[offset + i];
+ }
+ closestPoint.length = stride;
+ return squaredDistance;
+ } else {
+ return minSquaredDistance;
+ }
+ }
+ goog.asserts.assert(maxDelta > 0, 'maxDelta should be larger than 0');
+ var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
+ var index = offset + stride;
+ while (index < end) {
+ ol.geom.flat.closest.point(
+ flatCoordinates, index - stride, index, stride, x, y, tmpPoint);
+ squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);
+ if (squaredDistance < minSquaredDistance) {
+ minSquaredDistance = squaredDistance;
+ for (i = 0; i < stride; ++i) {
+ closestPoint[i] = tmpPoint[i];
+ }
+ closestPoint.length = stride;
+ index += stride;
+ } else {
+ // Skip ahead multiple points, because we know that all the skipped
+ // points cannot be any closer than the closest point we have found so
+ // far. We know this because we know how close the current point is, how
+ // close the closest point we have found so far is, and the maximum
+ // distance between consecutive points. For example, if we're currently
+ // at distance 10, the best we've found so far is 3, and that the maximum
+ // distance between consecutive points is 2, then we'll need to skip at
+ // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of
+ // finding a closer point. We use Math.max(..., 1) to ensure that we
+ // always advance at least one point, to avoid an infinite loop.
+ index += stride * Math.max(
+ ((Math.sqrt(squaredDistance) -
+ Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);
+ }
+ }
+ if (isRing) {
+ // Check the closing segment.
+ ol.geom.flat.closest.point(
+ flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);
+ squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);
+ if (squaredDistance < minSquaredDistance) {
+ minSquaredDistance = squaredDistance;
+ for (i = 0; i < stride; ++i) {
+ closestPoint[i] = tmpPoint[i];
+ }
+ closestPoint.length = stride;
+ }
+ }
+ return minSquaredDistance;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {number} maxDelta Max delta.
+ * @param {boolean} isRing Is ring.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {Array.<number>} closestPoint Closest point.
+ * @param {number} minSquaredDistance Minimum squared distance.
+ * @param {Array.<number>=} opt_tmpPoint Temporary point object.
+ * @return {number} Minimum squared distance.
+ */
+ol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends,
+ stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
+ opt_tmpPoint) {
+ var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ minSquaredDistance = ol.geom.flat.closest.getClosestPoint(
+ flatCoordinates, offset, end, stride,
+ maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
+ offset = end;
+ }
+ return minSquaredDistance;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {number} maxDelta Max delta.
+ * @param {boolean} isRing Is ring.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {Array.<number>} closestPoint Closest point.
+ * @param {number} minSquaredDistance Minimum squared distance.
+ * @param {Array.<number>=} opt_tmpPoint Temporary point object.
+ * @return {number} Minimum squared distance.
+ */
+ol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset,
+ endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
+ opt_tmpPoint) {
+ var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ minSquaredDistance = ol.geom.flat.closest.getsClosestPoint(
+ flatCoordinates, offset, ends, stride,
+ maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
+ offset = ends[ends.length - 1];
+ }
+ return minSquaredDistance;
+};
+
+goog.provide('ol.geom.flat.deflate');
+
+goog.require('goog.asserts');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} stride Stride.
+ * @return {number} offset Offset.
+ */
+ol.geom.flat.deflate.coordinate = function(flatCoordinates, offset, coordinate, stride) {
+ goog.asserts.assert(coordinate.length == stride,
+ 'length of the coordinate array should match stride');
+ var i, ii;
+ for (i = 0, ii = coordinate.length; i < ii; ++i) {
+ flatCoordinates[offset++] = coordinate[i];
+ }
+ return offset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {number} stride Stride.
+ * @return {number} offset Offset.
+ */
+ol.geom.flat.deflate.coordinates = function(flatCoordinates, offset, coordinates, stride) {
+ var i, ii;
+ for (i = 0, ii = coordinates.length; i < ii; ++i) {
+ var coordinate = coordinates[i];
+ goog.asserts.assert(coordinate.length == stride,
+ 'length of coordinate array should match stride');
+ var j;
+ for (j = 0; j < stride; ++j) {
+ flatCoordinates[offset++] = coordinate[j];
+ }
+ }
+ return offset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess.
+ * @param {number} stride Stride.
+ * @param {Array.<number>=} opt_ends Ends.
+ * @return {Array.<number>} Ends.
+ */
+ol.geom.flat.deflate.coordinatess = function(flatCoordinates, offset, coordinatess, stride, opt_ends) {
+ var ends = opt_ends ? opt_ends : [];
+ var i = 0;
+ var j, jj;
+ for (j = 0, jj = coordinatess.length; j < jj; ++j) {
+ var end = ol.geom.flat.deflate.coordinates(
+ flatCoordinates, offset, coordinatess[j], stride);
+ ends[i++] = end;
+ offset = end;
+ }
+ ends.length = i;
+ return ends;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss.
+ * @param {number} stride Stride.
+ * @param {Array.<Array.<number>>=} opt_endss Endss.
+ * @return {Array.<Array.<number>>} Endss.
+ */
+ol.geom.flat.deflate.coordinatesss = function(flatCoordinates, offset, coordinatesss, stride, opt_endss) {
+ var endss = opt_endss ? opt_endss : [];
+ var i = 0;
+ var j, jj;
+ for (j = 0, jj = coordinatesss.length; j < jj; ++j) {
+ var ends = ol.geom.flat.deflate.coordinatess(
+ flatCoordinates, offset, coordinatesss[j], stride, endss[i]);
+ endss[i++] = ends;
+ offset = ends[ends.length - 1];
+ }
+ endss.length = i;
+ return endss;
+};
+
+goog.provide('ol.geom.flat.inflate');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates.
+ * @return {Array.<ol.Coordinate>} Coordinates.
+ */
+ol.geom.flat.inflate.coordinates = function(flatCoordinates, offset, end, stride, opt_coordinates) {
+ var coordinates = opt_coordinates !== undefined ? opt_coordinates : [];
+ var i = 0;
+ var j;
+ for (j = offset; j < end; j += stride) {
+ coordinates[i++] = flatCoordinates.slice(j, j + stride);
+ }
+ coordinates.length = i;
+ return coordinates;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess.
+ * @return {Array.<Array.<ol.Coordinate>>} Coordinatess.
+ */
+ol.geom.flat.inflate.coordinatess = function(flatCoordinates, offset, ends, stride, opt_coordinatess) {
+ var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : [];
+ var i = 0;
+ var j, jj;
+ for (j = 0, jj = ends.length; j < jj; ++j) {
+ var end = ends[j];
+ coordinatess[i++] = ol.geom.flat.inflate.coordinates(
+ flatCoordinates, offset, end, stride, coordinatess[i]);
+ offset = end;
+ }
+ coordinatess.length = i;
+ return coordinatess;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss
+ * Coordinatesss.
+ * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss.
+ */
+ol.geom.flat.inflate.coordinatesss = function(flatCoordinates, offset, endss, stride, opt_coordinatesss) {
+ var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : [];
+ var i = 0;
+ var j, jj;
+ for (j = 0, jj = endss.length; j < jj; ++j) {
+ var ends = endss[j];
+ coordinatesss[i++] = ol.geom.flat.inflate.coordinatess(
+ flatCoordinates, offset, ends, stride, coordinatesss[i]);
+ offset = ends[ends.length - 1];
+ }
+ coordinatesss.length = i;
+ return coordinatesss;
+};
+
+// Based on simplify-js https://github.com/mourner/simplify-js
+// Copyright (c) 2012, Vladimir Agafonkin
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.geom.flat.simplify');
+
+goog.require('ol.math');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {boolean} highQuality Highest quality.
+ * @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @return {Array.<number>} Simplified line string.
+ */
+ol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end,
+ stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {
+ var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ?
+ opt_simplifiedFlatCoordinates : [];
+ if (!highQuality) {
+ end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end,
+ stride, squaredTolerance,
+ simplifiedFlatCoordinates, 0);
+ flatCoordinates = simplifiedFlatCoordinates;
+ offset = 0;
+ stride = 2;
+ }
+ simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
+ flatCoordinates, offset, end, stride, squaredTolerance,
+ simplifiedFlatCoordinates, 0);
+ return simplifiedFlatCoordinates;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end,
+ stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
+ var n = (end - offset) / stride;
+ if (n < 3) {
+ for (; offset < end; offset += stride) {
+ simplifiedFlatCoordinates[simplifiedOffset++] =
+ flatCoordinates[offset];
+ simplifiedFlatCoordinates[simplifiedOffset++] =
+ flatCoordinates[offset + 1];
+ }
+ return simplifiedOffset;
+ }
+ /** @type {Array.<number>} */
+ var markers = new Array(n);
+ markers[0] = 1;
+ markers[n - 1] = 1;
+ /** @type {Array.<number>} */
+ var stack = [offset, end - stride];
+ var index = 0;
+ var i;
+ while (stack.length > 0) {
+ var last = stack.pop();
+ var first = stack.pop();
+ var maxSquaredDistance = 0;
+ var x1 = flatCoordinates[first];
+ var y1 = flatCoordinates[first + 1];
+ var x2 = flatCoordinates[last];
+ var y2 = flatCoordinates[last + 1];
+ for (i = first + stride; i < last; i += stride) {
+ var x = flatCoordinates[i];
+ var y = flatCoordinates[i + 1];
+ var squaredDistance = ol.math.squaredSegmentDistance(
+ x, y, x1, y1, x2, y2);
+ if (squaredDistance > maxSquaredDistance) {
+ index = i;
+ maxSquaredDistance = squaredDistance;
+ }
+ }
+ if (maxSquaredDistance > squaredTolerance) {
+ markers[(index - offset) / stride] = 1;
+ if (first + stride < index) {
+ stack.push(first, index);
+ }
+ if (index + stride < last) {
+ stack.push(index, last);
+ }
+ }
+ }
+ for (i = 0; i < n; ++i) {
+ if (markers[i]) {
+ simplifiedFlatCoordinates[simplifiedOffset++] =
+ flatCoordinates[offset + i * stride];
+ simplifiedFlatCoordinates[simplifiedOffset++] =
+ flatCoordinates[offset + i * stride + 1];
+ }
+ }
+ return simplifiedOffset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @param {Array.<number>} simplifiedEnds Simplified ends.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset,
+ ends, stride, squaredTolerance, simplifiedFlatCoordinates,
+ simplifiedOffset, simplifiedEnds) {
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ simplifiedOffset = ol.geom.flat.simplify.douglasPeucker(
+ flatCoordinates, offset, end, stride, squaredTolerance,
+ simplifiedFlatCoordinates, simplifiedOffset);
+ simplifiedEnds.push(simplifiedOffset);
+ offset = end;
+ }
+ return simplifiedOffset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.douglasPeuckerss = function(
+ flatCoordinates, offset, endss, stride, squaredTolerance,
+ simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ var simplifiedEnds = [];
+ simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers(
+ flatCoordinates, offset, ends, stride, squaredTolerance,
+ simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);
+ simplifiedEndss.push(simplifiedEnds);
+ offset = ends[ends.length - 1];
+ }
+ return simplifiedOffset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end,
+ stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
+ if (end <= offset + stride) {
+ // zero or one point, no simplification possible, so copy and return
+ for (; offset < end; offset += stride) {
+ simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];
+ simplifiedFlatCoordinates[simplifiedOffset++] =
+ flatCoordinates[offset + 1];
+ }
+ return simplifiedOffset;
+ }
+ var x1 = flatCoordinates[offset];
+ var y1 = flatCoordinates[offset + 1];
+ // copy first point
+ simplifiedFlatCoordinates[simplifiedOffset++] = x1;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y1;
+ var x2 = x1;
+ var y2 = y1;
+ for (offset += stride; offset < end; offset += stride) {
+ x2 = flatCoordinates[offset];
+ y2 = flatCoordinates[offset + 1];
+ if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) {
+ // copy point at offset
+ simplifiedFlatCoordinates[simplifiedOffset++] = x2;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y2;
+ x1 = x2;
+ y1 = y2;
+ }
+ }
+ if (x2 != x1 || y2 != y1) {
+ // copy last point
+ simplifiedFlatCoordinates[simplifiedOffset++] = x2;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y2;
+ }
+ return simplifiedOffset;
+};
+
+
+/**
+ * @param {number} value Value.
+ * @param {number} tolerance Tolerance.
+ * @return {number} Rounded value.
+ */
+ol.geom.flat.simplify.snap = function(value, tolerance) {
+ return tolerance * Math.round(value / tolerance);
+};
+
+
+/**
+ * Simplifies a line string using an algorithm designed by Tim Schaub.
+ * Coordinates are snapped to the nearest value in a virtual grid and
+ * consecutive duplicate coordinates are discarded. This effectively preserves
+ * topology as the simplification of any subsection of a line string is
+ * independent of the rest of the line string. This means that, for examples,
+ * the common edge between two polygons will be simplified to the same line
+ * string independently in both polygons. This implementation uses a single
+ * pass over the coordinates and eliminates intermediate collinear points.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} tolerance Tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride,
+ tolerance, simplifiedFlatCoordinates, simplifiedOffset) {
+ // do nothing if the line is empty
+ if (offset == end) {
+ return simplifiedOffset;
+ }
+ // snap the first coordinate (P1)
+ var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
+ var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
+ offset += stride;
+ // add the first coordinate to the output
+ simplifiedFlatCoordinates[simplifiedOffset++] = x1;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y1;
+ // find the next coordinate that does not snap to the same value as the first
+ // coordinate (P2)
+ var x2, y2;
+ do {
+ x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
+ y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
+ offset += stride;
+ if (offset == end) {
+ // all coordinates snap to the same value, the line collapses to a point
+ // push the last snapped value anyway to ensure that the output contains
+ // at least two points
+ // FIXME should we really return at least two points anyway?
+ simplifiedFlatCoordinates[simplifiedOffset++] = x2;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y2;
+ return simplifiedOffset;
+ }
+ } while (x2 == x1 && y2 == y1);
+ while (offset < end) {
+ var x3, y3;
+ // snap the next coordinate (P3)
+ x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
+ y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
+ offset += stride;
+ // skip P3 if it is equal to P2
+ if (x3 == x2 && y3 == y2) {
+ continue;
+ }
+ // calculate the delta between P1 and P2
+ var dx1 = x2 - x1;
+ var dy1 = y2 - y1;
+ // calculate the delta between P3 and P1
+ var dx2 = x3 - x1;
+ var dy2 = y3 - y1;
+ // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from
+ // P1 in the same direction then P2 is on the straight line between P1 and
+ // P3
+ if ((dx1 * dy2 == dy1 * dx2) &&
+ ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&
+ ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) {
+ // discard P2 and set P2 = P3
+ x2 = x3;
+ y2 = y3;
+ continue;
+ }
+ // either P1, P2, and P3 are not colinear, or they are colinear but P3 is
+ // between P3 and P1 or on the opposite half of the line to P2. add P2,
+ // and continue with P1 = P2 and P2 = P3
+ simplifiedFlatCoordinates[simplifiedOffset++] = x2;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y2;
+ x1 = x2;
+ y1 = y2;
+ x2 = x3;
+ y2 = y3;
+ }
+ // add the last point (P2)
+ simplifiedFlatCoordinates[simplifiedOffset++] = x2;
+ simplifiedFlatCoordinates[simplifiedOffset++] = y2;
+ return simplifiedOffset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {number} tolerance Tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @param {Array.<number>} simplifiedEnds Simplified ends.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.quantizes = function(
+ flatCoordinates, offset, ends, stride,
+ tolerance,
+ simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ simplifiedOffset = ol.geom.flat.simplify.quantize(
+ flatCoordinates, offset, end, stride,
+ tolerance,
+ simplifiedFlatCoordinates, simplifiedOffset);
+ simplifiedEnds.push(simplifiedOffset);
+ offset = end;
+ }
+ return simplifiedOffset;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {number} tolerance Tolerance.
+ * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
+ * coordinates.
+ * @param {number} simplifiedOffset Simplified offset.
+ * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.
+ * @return {number} Simplified offset.
+ */
+ol.geom.flat.simplify.quantizess = function(
+ flatCoordinates, offset, endss, stride,
+ tolerance,
+ simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ var simplifiedEnds = [];
+ simplifiedOffset = ol.geom.flat.simplify.quantizes(
+ flatCoordinates, offset, ends, stride,
+ tolerance,
+ simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);
+ simplifiedEndss.push(simplifiedEnds);
+ offset = ends[ends.length - 1];
+ }
+ return simplifiedOffset;
+};
+
+goog.provide('ol.geom.LinearRing');
+
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.area');
+goog.require('ol.geom.flat.closest');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.geom.flat.simplify');
+
+
+/**
+ * @classdesc
+ * Linear ring geometry. Only used as part of polygon; cannot be rendered
+ * on its own.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.LinearRing = function(coordinates, opt_layout) {
+
+ ol.geom.SimpleGeometry.call(this);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDelta_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDeltaRevision_ = -1;
+
+ this.setCoordinates(coordinates, opt_layout);
+
+};
+ol.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry);
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.LinearRing} Clone.
+ * @api stable
+ */
+ol.geom.LinearRing.prototype.clone = function() {
+ var linearRing = new ol.geom.LinearRing(null);
+ linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
+ return linearRing;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.LinearRing.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ if (this.maxDeltaRevision_ != this.getRevision()) {
+ this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
+ this.maxDeltaRevision_ = this.getRevision();
+ }
+ return ol.geom.flat.closest.getClosestPoint(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
+};
+
+
+/**
+ * Return the area of the linear ring on projected plane.
+ * @return {number} Area (on projected plane).
+ * @api stable
+ */
+ol.geom.LinearRing.prototype.getArea = function() {
+ return ol.geom.flat.area.linearRing(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
+};
+
+
+/**
+ * Return the coordinates of the linear ring.
+ * @return {Array.<ol.Coordinate>} Coordinates.
+ * @api stable
+ */
+ol.geom.LinearRing.prototype.getCoordinates = function() {
+ return ol.geom.flat.inflate.coordinates(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.LinearRing.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
+ var simplifiedFlatCoordinates = [];
+ simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ squaredTolerance, simplifiedFlatCoordinates, 0);
+ var simplifiedLinearRing = new ol.geom.LinearRing(null);
+ simplifiedLinearRing.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
+ return simplifiedLinearRing;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.LinearRing.prototype.getType = function() {
+ return ol.geom.GeometryType.LINEAR_RING;
+};
+
+
+/**
+ * Set the coordinates of the linear ring.
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.LinearRing.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
+ } else {
+ this.setLayout(opt_layout, coordinates, 1);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
+ this.flatCoordinates, 0, coordinates, this.stride);
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ */
+ol.geom.LinearRing.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.changed();
+};
+
+goog.provide('ol.geom.Point');
+
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * Point geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {ol.Coordinate} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.Point = function(coordinates, opt_layout) {
+ ol.geom.SimpleGeometry.call(this);
+ this.setCoordinates(coordinates, opt_layout);
+};
+ol.inherits(ol.geom.Point, ol.geom.SimpleGeometry);
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.Point} Clone.
+ * @api stable
+ */
+ol.geom.Point.prototype.clone = function() {
+ var point = new ol.geom.Point(null);
+ point.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
+ return point;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Point.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ var flatCoordinates = this.flatCoordinates;
+ var squaredDistance = ol.math.squaredDistance(
+ x, y, flatCoordinates[0], flatCoordinates[1]);
+ if (squaredDistance < minSquaredDistance) {
+ var stride = this.stride;
+ var i;
+ for (i = 0; i < stride; ++i) {
+ closestPoint[i] = flatCoordinates[i];
+ }
+ closestPoint.length = stride;
+ return squaredDistance;
+ } else {
+ return minSquaredDistance;
+ }
+};
+
+
+/**
+ * Return the coordinate of the point.
+ * @return {ol.Coordinate} Coordinates.
+ * @api stable
+ */
+ol.geom.Point.prototype.getCoordinates = function() {
+ return !this.flatCoordinates ? [] : this.flatCoordinates.slice();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Point.prototype.computeExtent = function(extent) {
+ return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent);
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.Point.prototype.getType = function() {
+ return ol.geom.GeometryType.POINT;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.Point.prototype.intersectsExtent = function(extent) {
+ return ol.extent.containsXY(extent,
+ this.flatCoordinates[0], this.flatCoordinates[1]);
+};
+
+
+/**
+ * Set the coordinate of the point.
+ * @param {ol.Coordinate} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
+ } else {
+ this.setLayout(opt_layout, coordinates, 0);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ this.flatCoordinates.length = ol.geom.flat.deflate.coordinate(
+ this.flatCoordinates, 0, coordinates, this.stride);
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ */
+ol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.changed();
+};
+
+goog.provide('ol.geom.flat.contains');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} Contains extent.
+ */
+ol.geom.flat.contains.linearRingContainsExtent = function(flatCoordinates, offset, end, stride, extent) {
+ var outside = ol.extent.forEachCorner(extent,
+ /**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {boolean} Contains (x, y).
+ */
+ function(coordinate) {
+ return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates,
+ offset, end, stride, coordinate[0], coordinate[1]);
+ });
+ return !outside;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {boolean} Contains (x, y).
+ */
+ol.geom.flat.contains.linearRingContainsXY = function(flatCoordinates, offset, end, stride, x, y) {
+ // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
+ var contains = false;
+ var x1 = flatCoordinates[end - stride];
+ var y1 = flatCoordinates[end - stride + 1];
+ for (; offset < end; offset += stride) {
+ var x2 = flatCoordinates[offset];
+ var y2 = flatCoordinates[offset + 1];
+ var intersect = ((y1 > y) != (y2 > y)) &&
+ (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1);
+ if (intersect) {
+ contains = !contains;
+ }
+ x1 = x2;
+ y1 = y2;
+ }
+ return contains;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {boolean} Contains (x, y).
+ */
+ol.geom.flat.contains.linearRingsContainsXY = function(flatCoordinates, offset, ends, stride, x, y) {
+ goog.asserts.assert(ends.length > 0, 'ends should not be an empty array');
+ if (ends.length === 0) {
+ return false;
+ }
+ if (!ol.geom.flat.contains.linearRingContainsXY(
+ flatCoordinates, offset, ends[0], stride, x, y)) {
+ return false;
+ }
+ var i, ii;
+ for (i = 1, ii = ends.length; i < ii; ++i) {
+ if (ol.geom.flat.contains.linearRingContainsXY(
+ flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {boolean} Contains (x, y).
+ */
+ol.geom.flat.contains.linearRingssContainsXY = function(flatCoordinates, offset, endss, stride, x, y) {
+ goog.asserts.assert(endss.length > 0, 'endss should not be an empty array');
+ if (endss.length === 0) {
+ return false;
+ }
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ if (ol.geom.flat.contains.linearRingsContainsXY(
+ flatCoordinates, offset, ends, stride, x, y)) {
+ return true;
+ }
+ offset = ends[ends.length - 1];
+ }
+ return false;
+};
+
+goog.provide('ol.geom.flat.interiorpoint');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.geom.flat.contains');
+
+
+/**
+ * Calculates a point that is likely to lie in the interior of the linear rings.
+ * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {Array.<number>} flatCenters Flat centers.
+ * @param {number} flatCentersOffset Flat center offset.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @return {Array.<number>} Destination.
+ */
+ol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset,
+ ends, stride, flatCenters, flatCentersOffset, opt_dest) {
+ var i, ii, x, x1, x2, y1, y2;
+ var y = flatCenters[flatCentersOffset + 1];
+ /** @type {Array.<number>} */
+ var intersections = [];
+ // Calculate intersections with the horizontal line
+ var end = ends[0];
+ x1 = flatCoordinates[end - stride];
+ y1 = flatCoordinates[end - stride + 1];
+ for (i = offset; i < end; i += stride) {
+ x2 = flatCoordinates[i];
+ y2 = flatCoordinates[i + 1];
+ if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {
+ x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;
+ intersections.push(x);
+ }
+ x1 = x2;
+ y1 = y2;
+ }
+ // Find the longest segment of the horizontal line that has its center point
+ // inside the linear ring.
+ var pointX = NaN;
+ var maxSegmentLength = -Infinity;
+ intersections.sort(ol.array.numberSafeCompareFunction);
+ x1 = intersections[0];
+ for (i = 1, ii = intersections.length; i < ii; ++i) {
+ x2 = intersections[i];
+ var segmentLength = Math.abs(x2 - x1);
+ if (segmentLength > maxSegmentLength) {
+ x = (x1 + x2) / 2;
+ if (ol.geom.flat.contains.linearRingsContainsXY(
+ flatCoordinates, offset, ends, stride, x, y)) {
+ pointX = x;
+ maxSegmentLength = segmentLength;
+ }
+ }
+ x1 = x2;
+ }
+ if (isNaN(pointX)) {
+ // There is no horizontal line that has its center point inside the linear
+ // ring. Use the center of the the linear ring's extent.
+ pointX = flatCenters[flatCentersOffset];
+ }
+ if (opt_dest) {
+ opt_dest.push(pointX, y);
+ return opt_dest;
+ } else {
+ return [pointX, y];
+ }
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {Array.<number>} flatCenters Flat centers.
+ * @return {Array.<number>} Interior points.
+ */
+ol.geom.flat.interiorpoint.linearRingss = function(flatCoordinates, offset, endss, stride, flatCenters) {
+ goog.asserts.assert(2 * endss.length == flatCenters.length,
+ 'endss.length times 2 should be flatCenters.length');
+ var interiorPoints = [];
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates,
+ offset, ends, stride, flatCenters, 2 * i, interiorPoints);
+ offset = ends[ends.length - 1];
+ }
+ return interiorPoints;
+};
+
+goog.provide('ol.geom.flat.segments');
+
+
+/**
+ * This function calls `callback` for each segment of the flat coordinates
+ * array. If the callback returns a truthy value the function returns that
+ * value immediately. Otherwise the function returns `false`.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
+ * called for each segment.
+ * @param {S=} opt_this The object to be used as the value of 'this'
+ * within callback.
+ * @return {T|boolean} Value.
+ * @template T,S
+ */
+ol.geom.flat.segments.forEach = function(flatCoordinates, offset, end, stride, callback, opt_this) {
+ var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];
+ var point2 = [];
+ var ret;
+ for (; (offset + stride) < end; offset += stride) {
+ point2[0] = flatCoordinates[offset + stride];
+ point2[1] = flatCoordinates[offset + stride + 1];
+ ret = callback.call(opt_this, point1, point2);
+ if (ret) {
+ return ret;
+ }
+ point1[0] = point2[0];
+ point1[1] = point2[1];
+ }
+ return false;
+};
+
+goog.provide('ol.geom.flat.intersectsextent');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.geom.flat.contains');
+goog.require('ol.geom.flat.segments');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} True if the geometry and the extent intersect.
+ */
+ol.geom.flat.intersectsextent.lineString = function(flatCoordinates, offset, end, stride, extent) {
+ var coordinatesExtent = ol.extent.extendFlatCoordinates(
+ ol.extent.createEmpty(), flatCoordinates, offset, end, stride);
+ if (!ol.extent.intersects(extent, coordinatesExtent)) {
+ return false;
+ }
+ if (ol.extent.containsExtent(extent, coordinatesExtent)) {
+ return true;
+ }
+ if (coordinatesExtent[0] >= extent[0] &&
+ coordinatesExtent[2] <= extent[2]) {
+ return true;
+ }
+ if (coordinatesExtent[1] >= extent[1] &&
+ coordinatesExtent[3] <= extent[3]) {
+ return true;
+ }
+ return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,
+ /**
+ * @param {ol.Coordinate} point1 Start point.
+ * @param {ol.Coordinate} point2 End point.
+ * @return {boolean} `true` if the segment and the extent intersect,
+ * `false` otherwise.
+ */
+ function(point1, point2) {
+ return ol.extent.intersectsSegment(extent, point1, point2);
+ });
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} True if the geometry and the extent intersect.
+ */
+ol.geom.flat.intersectsextent.lineStrings = function(flatCoordinates, offset, ends, stride, extent) {
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ if (ol.geom.flat.intersectsextent.lineString(
+ flatCoordinates, offset, ends[i], stride, extent)) {
+ return true;
+ }
+ offset = ends[i];
+ }
+ return false;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} True if the geometry and the extent intersect.
+ */
+ol.geom.flat.intersectsextent.linearRing = function(flatCoordinates, offset, end, stride, extent) {
+ if (ol.geom.flat.intersectsextent.lineString(
+ flatCoordinates, offset, end, stride, extent)) {
+ return true;
+ }
+ if (ol.geom.flat.contains.linearRingContainsXY(
+ flatCoordinates, offset, end, stride, extent[0], extent[1])) {
+ return true;
+ }
+ if (ol.geom.flat.contains.linearRingContainsXY(
+ flatCoordinates, offset, end, stride, extent[0], extent[3])) {
+ return true;
+ }
+ if (ol.geom.flat.contains.linearRingContainsXY(
+ flatCoordinates, offset, end, stride, extent[2], extent[1])) {
+ return true;
+ }
+ if (ol.geom.flat.contains.linearRingContainsXY(
+ flatCoordinates, offset, end, stride, extent[2], extent[3])) {
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} True if the geometry and the extent intersect.
+ */
+ol.geom.flat.intersectsextent.linearRings = function(flatCoordinates, offset, ends, stride, extent) {
+ goog.asserts.assert(ends.length > 0, 'ends should not be an empty array');
+ if (!ol.geom.flat.intersectsextent.linearRing(
+ flatCoordinates, offset, ends[0], stride, extent)) {
+ return false;
+ }
+ if (ends.length === 1) {
+ return true;
+ }
+ var i, ii;
+ for (i = 1, ii = ends.length; i < ii; ++i) {
+ if (ol.geom.flat.contains.linearRingContainsExtent(
+ flatCoordinates, ends[i - 1], ends[i], stride, extent)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @param {ol.Extent} extent Extent.
+ * @return {boolean} True if the geometry and the extent intersect.
+ */
+ol.geom.flat.intersectsextent.linearRingss = function(flatCoordinates, offset, endss, stride, extent) {
+ goog.asserts.assert(endss.length > 0, 'endss should not be an empty array');
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ if (ol.geom.flat.intersectsextent.linearRings(
+ flatCoordinates, offset, ends, stride, extent)) {
+ return true;
+ }
+ offset = ends[ends.length - 1];
+ }
+ return false;
+};
+
+goog.provide('ol.geom.flat.reverse');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ */
+ol.geom.flat.reverse.coordinates = function(flatCoordinates, offset, end, stride) {
+ while (offset < end - stride) {
+ var i;
+ for (i = 0; i < stride; ++i) {
+ var tmp = flatCoordinates[offset + i];
+ flatCoordinates[offset + i] = flatCoordinates[end - stride + i];
+ flatCoordinates[end - stride + i] = tmp;
+ }
+ offset += stride;
+ end -= stride;
+ }
+};
+
+goog.provide('ol.geom.flat.orient');
+
+goog.require('ol');
+goog.require('ol.geom.flat.reverse');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @return {boolean} Is clockwise.
+ */
+ol.geom.flat.orient.linearRingIsClockwise = function(flatCoordinates, offset, end, stride) {
+ // http://tinyurl.com/clockwise-method
+ // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
+ var edge = 0;
+ var x1 = flatCoordinates[end - stride];
+ var y1 = flatCoordinates[end - stride + 1];
+ for (; offset < end; offset += stride) {
+ var x2 = flatCoordinates[offset];
+ var y2 = flatCoordinates[offset + 1];
+ edge += (x2 - x1) * (y2 + y1);
+ x1 = x2;
+ y1 = y2;
+ }
+ return edge > 0;
+};
+
+
+/**
+ * Determines if linear rings are oriented. By default, left-hand orientation
+ * is tested (first ring must be clockwise, remaining rings counter-clockwise).
+ * To test for right-hand orientation, use the `opt_right` argument.
+ *
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Array of end indexes.
+ * @param {number} stride Stride.
+ * @param {boolean=} opt_right Test for right-hand orientation
+ * (counter-clockwise exterior ring and clockwise interior rings).
+ * @return {boolean} Rings are correctly oriented.
+ */
+ol.geom.flat.orient.linearRingsAreOriented = function(flatCoordinates, offset, ends, stride, opt_right) {
+ var right = opt_right !== undefined ? opt_right : false;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
+ flatCoordinates, offset, end, stride);
+ if (i === 0) {
+ if ((right && isClockwise) || (!right && !isClockwise)) {
+ return false;
+ }
+ } else {
+ if ((right && !isClockwise) || (!right && isClockwise)) {
+ return false;
+ }
+ }
+ offset = end;
+ }
+ return true;
+};
+
+
+/**
+ * Determines if linear rings are oriented. By default, left-hand orientation
+ * is tested (first ring must be clockwise, remaining rings counter-clockwise).
+ * To test for right-hand orientation, use the `opt_right` argument.
+ *
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Array of array of end indexes.
+ * @param {number} stride Stride.
+ * @param {boolean=} opt_right Test for right-hand orientation
+ * (counter-clockwise exterior ring and clockwise interior rings).
+ * @return {boolean} Rings are correctly oriented.
+ */
+ol.geom.flat.orient.linearRingssAreOriented = function(flatCoordinates, offset, endss, stride, opt_right) {
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ if (!ol.geom.flat.orient.linearRingsAreOriented(
+ flatCoordinates, offset, endss[i], stride, opt_right)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Orient coordinates in a flat array of linear rings. By default, rings
+ * are oriented following the left-hand rule (clockwise for exterior and
+ * counter-clockwise for interior rings). To orient according to the
+ * right-hand rule, use the `opt_right` argument.
+ *
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {boolean=} opt_right Follow the right-hand rule for orientation.
+ * @return {number} End.
+ */
+ol.geom.flat.orient.orientLinearRings = function(flatCoordinates, offset, ends, stride, opt_right) {
+ var right = opt_right !== undefined ? opt_right : false;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
+ flatCoordinates, offset, end, stride);
+ var reverse = i === 0 ?
+ (right && isClockwise) || (!right && !isClockwise) :
+ (right && !isClockwise) || (!right && isClockwise);
+ if (reverse) {
+ ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride);
+ }
+ offset = end;
+ }
+ return offset;
+};
+
+
+/**
+ * Orient coordinates in a flat array of linear rings. By default, rings
+ * are oriented following the left-hand rule (clockwise for exterior and
+ * counter-clockwise for interior rings). To orient according to the
+ * right-hand rule, use the `opt_right` argument.
+ *
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Array of array of end indexes.
+ * @param {number} stride Stride.
+ * @param {boolean=} opt_right Follow the right-hand rule for orientation.
+ * @return {number} End.
+ */
+ol.geom.flat.orient.orientLinearRingss = function(flatCoordinates, offset, endss, stride, opt_right) {
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ offset = ol.geom.flat.orient.orientLinearRings(
+ flatCoordinates, offset, endss[i], stride, opt_right);
+ }
+ return offset;
+};
+
+goog.provide('ol.geom.Polygon');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LinearRing');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.area');
+goog.require('ol.geom.flat.closest');
+goog.require('ol.geom.flat.contains');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.geom.flat.interiorpoint');
+goog.require('ol.geom.flat.intersectsextent');
+goog.require('ol.geom.flat.orient');
+goog.require('ol.geom.flat.simplify');
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * Polygon geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.Polygon = function(coordinates, opt_layout) {
+
+ ol.geom.SimpleGeometry.call(this);
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.ends_ = [];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.flatInteriorPointRevision_ = -1;
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.flatInteriorPoint_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDelta_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDeltaRevision_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.orientedRevision_ = -1;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.orientedFlatCoordinates_ = null;
+
+ this.setCoordinates(coordinates, opt_layout);
+
+};
+ol.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry);
+
+
+/**
+ * Append the passed linear ring to this polygon.
+ * @param {ol.geom.LinearRing} linearRing Linear ring.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) {
+ goog.asserts.assert(linearRing.getLayout() == this.layout,
+ 'layout of linearRing should match layout');
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = linearRing.getFlatCoordinates().slice();
+ } else {
+ ol.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates());
+ }
+ this.ends_.push(this.flatCoordinates.length);
+ this.changed();
+};
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.Polygon} Clone.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.clone = function() {
+ var polygon = new ol.geom.Polygon(null);
+ polygon.setFlatCoordinates(
+ this.layout, this.flatCoordinates.slice(), this.ends_.slice());
+ return polygon;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Polygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ if (this.maxDeltaRevision_ != this.getRevision()) {
+ this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(
+ this.flatCoordinates, 0, this.ends_, this.stride, 0));
+ this.maxDeltaRevision_ = this.getRevision();
+ }
+ return ol.geom.flat.closest.getsClosestPoint(
+ this.flatCoordinates, 0, this.ends_, this.stride,
+ this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Polygon.prototype.containsXY = function(x, y) {
+ return ol.geom.flat.contains.linearRingsContainsXY(
+ this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);
+};
+
+
+/**
+ * Return the area of the polygon on projected plane.
+ * @return {number} Area (on projected plane).
+ * @api stable
+ */
+ol.geom.Polygon.prototype.getArea = function() {
+ return ol.geom.flat.area.linearRings(
+ this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);
+};
+
+
+/**
+ * Get the coordinate array for this geometry. This array has the structure
+ * of a GeoJSON coordinate array for polygons.
+ *
+ * @param {boolean=} opt_right Orient coordinates according to the right-hand
+ * rule (counter-clockwise for exterior and clockwise for interior rings).
+ * If `false`, coordinates will be oriented according to the left-hand rule
+ * (clockwise for exterior and counter-clockwise for interior rings).
+ * By default, coordinate orientation will depend on how the geometry was
+ * constructed.
+ * @return {Array.<Array.<ol.Coordinate>>} Coordinates.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.getCoordinates = function(opt_right) {
+ var flatCoordinates;
+ if (opt_right !== undefined) {
+ flatCoordinates = this.getOrientedFlatCoordinates().slice();
+ ol.geom.flat.orient.orientLinearRings(
+ flatCoordinates, 0, this.ends_, this.stride, opt_right);
+ } else {
+ flatCoordinates = this.flatCoordinates;
+ }
+
+ return ol.geom.flat.inflate.coordinatess(
+ flatCoordinates, 0, this.ends_, this.stride);
+};
+
+
+/**
+ * @return {Array.<number>} Ends.
+ */
+ol.geom.Polygon.prototype.getEnds = function() {
+ return this.ends_;
+};
+
+
+/**
+ * @return {Array.<number>} Interior point.
+ */
+ol.geom.Polygon.prototype.getFlatInteriorPoint = function() {
+ if (this.flatInteriorPointRevision_ != this.getRevision()) {
+ var flatCenter = ol.extent.getCenter(this.getExtent());
+ this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings(
+ this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,
+ flatCenter, 0);
+ this.flatInteriorPointRevision_ = this.getRevision();
+ }
+ return this.flatInteriorPoint_;
+};
+
+
+/**
+ * Return an interior point of the polygon.
+ * @return {ol.geom.Point} Interior point.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.getInteriorPoint = function() {
+ return new ol.geom.Point(this.getFlatInteriorPoint());
+};
+
+
+/**
+ * Return the number of rings of the polygon, this includes the exterior
+ * ring and any interior rings.
+ *
+ * @return {number} Number of rings.
+ * @api
+ */
+ol.geom.Polygon.prototype.getLinearRingCount = function() {
+ return this.ends_.length;
+};
+
+
+/**
+ * Return the Nth linear ring of the polygon geometry. Return `null` if the
+ * given index is out of range.
+ * The exterior linear ring is available at index `0` and the interior rings
+ * at index `1` and beyond.
+ *
+ * @param {number} index Index.
+ * @return {ol.geom.LinearRing} Linear ring.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.getLinearRing = function(index) {
+ goog.asserts.assert(0 <= index && index < this.ends_.length,
+ 'index should be in between 0 and and length of this.ends_');
+ if (index < 0 || this.ends_.length <= index) {
+ return null;
+ }
+ var linearRing = new ol.geom.LinearRing(null);
+ linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
+ index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));
+ return linearRing;
+};
+
+
+/**
+ * Return the linear rings of the polygon.
+ * @return {Array.<ol.geom.LinearRing>} Linear rings.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.getLinearRings = function() {
+ var layout = this.layout;
+ var flatCoordinates = this.flatCoordinates;
+ var ends = this.ends_;
+ var linearRings = [];
+ var offset = 0;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ var linearRing = new ol.geom.LinearRing(null);
+ linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));
+ linearRings.push(linearRing);
+ offset = end;
+ }
+ return linearRings;
+};
+
+
+/**
+ * @return {Array.<number>} Oriented flat coordinates.
+ */
+ol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() {
+ if (this.orientedRevision_ != this.getRevision()) {
+ var flatCoordinates = this.flatCoordinates;
+ if (ol.geom.flat.orient.linearRingsAreOriented(
+ flatCoordinates, 0, this.ends_, this.stride)) {
+ this.orientedFlatCoordinates_ = flatCoordinates;
+ } else {
+ this.orientedFlatCoordinates_ = flatCoordinates.slice();
+ this.orientedFlatCoordinates_.length =
+ ol.geom.flat.orient.orientLinearRings(
+ this.orientedFlatCoordinates_, 0, this.ends_, this.stride);
+ }
+ this.orientedRevision_ = this.getRevision();
+ }
+ return this.orientedFlatCoordinates_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Polygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
+ var simplifiedFlatCoordinates = [];
+ var simplifiedEnds = [];
+ simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes(
+ this.flatCoordinates, 0, this.ends_, this.stride,
+ Math.sqrt(squaredTolerance),
+ simplifiedFlatCoordinates, 0, simplifiedEnds);
+ var simplifiedPolygon = new ol.geom.Polygon(null);
+ simplifiedPolygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);
+ return simplifiedPolygon;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.Polygon.prototype.getType = function() {
+ return ol.geom.GeometryType.POLYGON;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.Polygon.prototype.intersectsExtent = function(extent) {
+ return ol.geom.flat.intersectsextent.linearRings(
+ this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);
+};
+
+
+/**
+ * Set the coordinates of the polygon.
+ * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);
+ } else {
+ this.setLayout(opt_layout, coordinates, 2);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ var ends = ol.geom.flat.deflate.coordinatess(
+ this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
+ this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {Array.<number>} ends Ends.
+ */
+ol.geom.Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {
+ if (!flatCoordinates) {
+ goog.asserts.assert(ends && ends.length === 0,
+ 'ends must be an empty array');
+ } else if (ends.length === 0) {
+ goog.asserts.assert(flatCoordinates.length === 0,
+ 'flatCoordinates should be an empty array');
+ } else {
+ goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1],
+ 'the length of flatCoordinates should be the last entry of ends');
+ }
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.ends_ = ends;
+ this.changed();
+};
+
+
+/**
+ * Create an approximation of a circle on the surface of a sphere.
+ * @param {ol.Sphere} sphere The sphere.
+ * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees).
+ * @param {number} radius The great-circle distance from the center to
+ * the polygon vertices.
+ * @param {number=} opt_n Optional number of vertices for the resulting
+ * polygon. Default is `32`.
+ * @return {ol.geom.Polygon} The "circular" polygon.
+ * @api stable
+ */
+ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) {
+ var n = opt_n ? opt_n : 32;
+ /** @type {Array.<number>} */
+ var flatCoordinates = [];
+ var i;
+ for (i = 0; i < n; ++i) {
+ ol.array.extend(
+ flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n));
+ }
+ flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);
+ var polygon = new ol.geom.Polygon(null);
+ polygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
+ return polygon;
+};
+
+
+/**
+ * Create a polygon from an extent. The layout used is `XY`.
+ * @param {ol.Extent} extent The extent.
+ * @return {ol.geom.Polygon} The polygon.
+ * @api
+ */
+ol.geom.Polygon.fromExtent = function(extent) {
+ var minX = extent[0];
+ var minY = extent[1];
+ var maxX = extent[2];
+ var maxY = extent[3];
+ var flatCoordinates =
+ [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY];
+ var polygon = new ol.geom.Polygon(null);
+ polygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
+ return polygon;
+};
+
+
+/**
+ * Create a regular polygon from a circle.
+ * @param {ol.geom.Circle} circle Circle geometry.
+ * @param {number=} opt_sides Number of sides of the polygon. Default is 32.
+ * @param {number=} opt_angle Start angle for the first vertex of the polygon in
+ * radians. Default is 0.
+ * @return {ol.geom.Polygon} Polygon geometry.
+ * @api
+ */
+ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) {
+ var sides = opt_sides ? opt_sides : 32;
+ var stride = circle.getStride();
+ var layout = circle.getLayout();
+ var polygon = new ol.geom.Polygon(null, layout);
+ var arrayLength = stride * (sides + 1);
+ var flatCoordinates = new Array(arrayLength);
+ for (var i = 0; i < arrayLength; i++) {
+ flatCoordinates[i] = 0;
+ }
+ var ends = [flatCoordinates.length];
+ polygon.setFlatCoordinates(layout, flatCoordinates, ends);
+ ol.geom.Polygon.makeRegular(
+ polygon, circle.getCenter(), circle.getRadius(), opt_angle);
+ return polygon;
+};
+
+
+/**
+ * Modify the coordinates of a polygon to make it a regular polygon.
+ * @param {ol.geom.Polygon} polygon Polygon geometry.
+ * @param {ol.Coordinate} center Center of the regular polygon.
+ * @param {number} radius Radius of the regular polygon.
+ * @param {number=} opt_angle Start angle for the first vertex of the polygon in
+ * radians. Default is 0.
+ */
+ol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) {
+ var flatCoordinates = polygon.getFlatCoordinates();
+ var layout = polygon.getLayout();
+ var stride = polygon.getStride();
+ var ends = polygon.getEnds();
+ goog.asserts.assert(ends.length === 1, 'only 1 ring is supported');
+ var sides = flatCoordinates.length / stride - 1;
+ var startAngle = opt_angle ? opt_angle : 0;
+ var angle, offset;
+ for (var i = 0; i <= sides; ++i) {
+ offset = i * stride;
+ angle = startAngle + (ol.math.modulo(i, sides) * 2 * Math.PI / sides);
+ flatCoordinates[offset] = center[0] + (radius * Math.cos(angle));
+ flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));
+ }
+ polygon.setFlatCoordinates(layout, flatCoordinates, ends);
+};
+
+goog.provide('ol.View');
+goog.provide('ol.ViewHint');
+goog.provide('ol.ViewProperty');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.CenterConstraint');
+goog.require('ol.Constraints');
+goog.require('ol.Object');
+goog.require('ol.ResolutionConstraint');
+goog.require('ol.RotationConstraint');
+goog.require('ol.coordinate');
+goog.require('ol.extent');
+goog.require('ol.geom.Polygon');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.proj');
+goog.require('ol.proj.METERS_PER_UNIT');
+goog.require('ol.proj.Projection');
+goog.require('ol.proj.Units');
+
+
+/**
+ * @enum {string}
+ */
+ol.ViewProperty = {
+ CENTER: 'center',
+ RESOLUTION: 'resolution',
+ ROTATION: 'rotation'
+};
+
+
+/**
+ * @enum {number}
+ */
+ol.ViewHint = {
+ ANIMATING: 0,
+ INTERACTING: 1
+};
+
+
+/**
+ * @classdesc
+ * An ol.View object represents a simple 2D view of the map.
+ *
+ * This is the object to act upon to change the center, resolution,
+ * and rotation of the map.
+ *
+ * ### The view states
+ *
+ * An `ol.View` is determined by three states: `center`, `resolution`,
+ * and `rotation`. Each state has a corresponding getter and setter, e.g.
+ * `getCenter` and `setCenter` for the `center` state.
+ *
+ * An `ol.View` has a `projection`. The projection determines the
+ * coordinate system of the center, and its units determine the units of the
+ * resolution (projection units per pixel). The default projection is
+ * Spherical Mercator (EPSG:3857).
+ *
+ * ### The constraints
+ *
+ * `setCenter`, `setResolution` and `setRotation` can be used to change the
+ * states of the view. Any value can be passed to the setters. And the value
+ * that is passed to a setter will effectively be the value set in the view,
+ * and returned by the corresponding getter.
+ *
+ * But an `ol.View` object also has a *resolution constraint*, a
+ * *rotation constraint* and a *center constraint*.
+ *
+ * As said above, no constraints are applied when the setters are used to set
+ * new states for the view. Applying constraints is done explicitly through
+ * the use of the `constrain*` functions (`constrainResolution` and
+ * `constrainRotation` and `constrainCenter`).
+ *
+ * The main users of the constraints are the interactions and the
+ * controls. For example, double-clicking on the map changes the view to
+ * the "next" resolution. And releasing the fingers after pinch-zooming
+ * snaps to the closest resolution (with an animation).
+ *
+ * The *resolution constraint* snaps to specific resolutions. It is
+ * determined by the following options: `resolutions`, `maxResolution`,
+ * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three
+ * options are ignored. See documentation for each option for more
+ * information.
+ *
+ * The *rotation constraint* snaps to specific angles. It is determined
+ * by the following options: `enableRotation` and `constrainRotation`.
+ * By default the rotation value is snapped to zero when approaching the
+ * horizontal.
+ *
+ * The *center constraint* is determined by the `extent` option. By
+ * default the center is not constrained at all.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {olx.ViewOptions=} opt_options View options.
+ * @api stable
+ */
+ol.View = function(opt_options) {
+ ol.Object.call(this);
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.hints_ = [0, 0];
+
+ /**
+ * @type {Object.<string, *>}
+ */
+ var properties = {};
+ properties[ol.ViewProperty.CENTER] = options.center !== undefined ?
+ options.center : null;
+
+ /**
+ * @private
+ * @const
+ * @type {ol.proj.Projection}
+ */
+ this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857');
+
+ var resolutionConstraintInfo = ol.View.createResolutionConstraint_(
+ options);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxResolution_ = resolutionConstraintInfo.maxResolution;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.minResolution_ = resolutionConstraintInfo.minResolution;
+
+ /**
+ * @private
+ * @type {Array.<number>|undefined}
+ */
+ this.resolutions_ = options.resolutions;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.minZoom_ = resolutionConstraintInfo.minZoom;
+
+ var centerConstraint = ol.View.createCenterConstraint_(options);
+ var resolutionConstraint = resolutionConstraintInfo.constraint;
+ var rotationConstraint = ol.View.createRotationConstraint_(options);
+
+ /**
+ * @private
+ * @type {ol.Constraints}
+ */
+ this.constraints_ = new ol.Constraints(
+ centerConstraint, resolutionConstraint, rotationConstraint);
+
+ if (options.resolution !== undefined) {
+ properties[ol.ViewProperty.RESOLUTION] = options.resolution;
+ } else if (options.zoom !== undefined) {
+ properties[ol.ViewProperty.RESOLUTION] = this.constrainResolution(
+ this.maxResolution_, options.zoom - this.minZoom_);
+ }
+ properties[ol.ViewProperty.ROTATION] =
+ options.rotation !== undefined ? options.rotation : 0;
+ this.setProperties(properties);
+};
+ol.inherits(ol.View, ol.Object);
+
+
+/**
+ * @param {number} rotation Target rotation.
+ * @param {ol.Coordinate} anchor Rotation anchor.
+ * @return {ol.Coordinate|undefined} Center for rotation and anchor.
+ */
+ol.View.prototype.calculateCenterRotate = function(rotation, anchor) {
+ var center;
+ var currentCenter = this.getCenter();
+ if (currentCenter !== undefined) {
+ center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]];
+ ol.coordinate.rotate(center, rotation - this.getRotation());
+ ol.coordinate.add(center, anchor);
+ }
+ return center;
+};
+
+
+/**
+ * @param {number} resolution Target resolution.
+ * @param {ol.Coordinate} anchor Zoom anchor.
+ * @return {ol.Coordinate|undefined} Center for resolution and anchor.
+ */
+ol.View.prototype.calculateCenterZoom = function(resolution, anchor) {
+ var center;
+ var currentCenter = this.getCenter();
+ var currentResolution = this.getResolution();
+ if (currentCenter !== undefined && currentResolution !== undefined) {
+ var x = anchor[0] -
+ resolution * (anchor[0] - currentCenter[0]) / currentResolution;
+ var y = anchor[1] -
+ resolution * (anchor[1] - currentCenter[1]) / currentResolution;
+ center = [x, y];
+ }
+ return center;
+};
+
+
+/**
+ * Get the constrained center of this view.
+ * @param {ol.Coordinate|undefined} center Center.
+ * @return {ol.Coordinate|undefined} Constrained center.
+ * @api
+ */
+ol.View.prototype.constrainCenter = function(center) {
+ return this.constraints_.center(center);
+};
+
+
+/**
+ * Get the constrained resolution of this view.
+ * @param {number|undefined} resolution Resolution.
+ * @param {number=} opt_delta Delta. Default is `0`.
+ * @param {number=} opt_direction Direction. Default is `0`.
+ * @return {number|undefined} Constrained resolution.
+ * @api
+ */
+ol.View.prototype.constrainResolution = function(
+ resolution, opt_delta, opt_direction) {
+ var delta = opt_delta || 0;
+ var direction = opt_direction || 0;
+ return this.constraints_.resolution(resolution, delta, direction);
+};
+
+
+/**
+ * Get the constrained rotation of this view.
+ * @param {number|undefined} rotation Rotation.
+ * @param {number=} opt_delta Delta. Default is `0`.
+ * @return {number|undefined} Constrained rotation.
+ * @api
+ */
+ol.View.prototype.constrainRotation = function(rotation, opt_delta) {
+ var delta = opt_delta || 0;
+ return this.constraints_.rotation(rotation, delta);
+};
+
+
+/**
+ * Get the view center.
+ * @return {ol.Coordinate|undefined} The center of the view.
+ * @observable
+ * @api stable
+ */
+ol.View.prototype.getCenter = function() {
+ return /** @type {ol.Coordinate|undefined} */ (
+ this.get(ol.ViewProperty.CENTER));
+};
+
+
+/**
+ * @param {Array.<number>=} opt_hints Destination array.
+ * @return {Array.<number>} Hint.
+ */
+ol.View.prototype.getHints = function(opt_hints) {
+ if (opt_hints !== undefined) {
+ opt_hints[0] = this.hints_[0];
+ opt_hints[1] = this.hints_[1];
+ return opt_hints;
+ } else {
+ return this.hints_.slice();
+ }
+};
+
+
+/**
+ * Calculate the extent for the current view state and the passed size.
+ * The size is the pixel dimensions of the box into which the calculated extent
+ * should fit. In most cases you want to get the extent of the entire map,
+ * that is `map.getSize()`.
+ * @param {ol.Size} size Box pixel size.
+ * @return {ol.Extent} Extent.
+ * @api stable
+ */
+ol.View.prototype.calculateExtent = function(size) {
+ var center = this.getCenter();
+ goog.asserts.assert(center, 'The view center is not defined');
+ var resolution = this.getResolution();
+ goog.asserts.assert(resolution !== undefined,
+ 'The view resolution is not defined');
+ var rotation = this.getRotation();
+ goog.asserts.assert(rotation !== undefined,
+ 'The view rotation is not defined');
+
+ return ol.extent.getForViewAndSize(center, resolution, rotation, size);
+};
+
+
+/**
+ * Get the maximum resolution of the view.
+ * @return {number} The maximum resolution of the view.
+ * @api
+ */
+ol.View.prototype.getMaxResolution = function() {
+ return this.maxResolution_;
+};
+
+
+/**
+ * Get the minimum resolution of the view.
+ * @return {number} The minimum resolution of the view.
+ * @api
+ */
+ol.View.prototype.getMinResolution = function() {
+ return this.minResolution_;
+};
+
+
+/**
+ * Get the view projection.
+ * @return {ol.proj.Projection} The projection of the view.
+ * @api stable
+ */
+ol.View.prototype.getProjection = function() {
+ return this.projection_;
+};
+
+
+/**
+ * Get the view resolution.
+ * @return {number|undefined} The resolution of the view.
+ * @observable
+ * @api stable
+ */
+ol.View.prototype.getResolution = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.ViewProperty.RESOLUTION));
+};
+
+
+/**
+ * Get the resolutions for the view. This returns the array of resolutions
+ * passed to the constructor of the {ol.View}, or undefined if none were given.
+ * @return {Array.<number>|undefined} The resolutions of the view.
+ * @api stable
+ */
+ol.View.prototype.getResolutions = function() {
+ return this.resolutions_;
+};
+
+
+/**
+ * Get the resolution for a provided extent (in map units) and size (in pixels).
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Size} size Box pixel size.
+ * @return {number} The resolution at which the provided extent will render at
+ * the given size.
+ */
+ol.View.prototype.getResolutionForExtent = function(extent, size) {
+ var xResolution = ol.extent.getWidth(extent) / size[0];
+ var yResolution = ol.extent.getHeight(extent) / size[1];
+ return Math.max(xResolution, yResolution);
+};
+
+
+/**
+ * Return a function that returns a value between 0 and 1 for a
+ * resolution. Exponential scaling is assumed.
+ * @param {number=} opt_power Power.
+ * @return {function(number): number} Resolution for value function.
+ */
+ol.View.prototype.getResolutionForValueFunction = function(opt_power) {
+ var power = opt_power || 2;
+ var maxResolution = this.maxResolution_;
+ var minResolution = this.minResolution_;
+ var max = Math.log(maxResolution / minResolution) / Math.log(power);
+ return (
+ /**
+ * @param {number} value Value.
+ * @return {number} Resolution.
+ */
+ function(value) {
+ var resolution = maxResolution / Math.pow(power, value * max);
+ goog.asserts.assert(resolution >= minResolution &&
+ resolution <= maxResolution,
+ 'calculated resolution outside allowed bounds (%s <= %s <= %s)',
+ minResolution, resolution, maxResolution);
+ return resolution;
+ });
+};
+
+
+/**
+ * Get the view rotation.
+ * @return {number} The rotation of the view in radians.
+ * @observable
+ * @api stable
+ */
+ol.View.prototype.getRotation = function() {
+ return /** @type {number} */ (this.get(ol.ViewProperty.ROTATION));
+};
+
+
+/**
+ * Return a function that returns a resolution for a value between
+ * 0 and 1. Exponential scaling is assumed.
+ * @param {number=} opt_power Power.
+ * @return {function(number): number} Value for resolution function.
+ */
+ol.View.prototype.getValueForResolutionFunction = function(opt_power) {
+ var power = opt_power || 2;
+ var maxResolution = this.maxResolution_;
+ var minResolution = this.minResolution_;
+ var max = Math.log(maxResolution / minResolution) / Math.log(power);
+ return (
+ /**
+ * @param {number} resolution Resolution.
+ * @return {number} Value.
+ */
+ function(resolution) {
+ var value =
+ (Math.log(maxResolution / resolution) / Math.log(power)) / max;
+ goog.asserts.assert(value >= 0 && value <= 1,
+ 'calculated value (%s) ouside allowed range (0-1)', value);
+ return value;
+ });
+};
+
+
+/**
+ * @return {olx.ViewState} View state.
+ */
+ol.View.prototype.getState = function() {
+ goog.asserts.assert(this.isDef(),
+ 'the view was not defined (had no center and/or resolution)');
+ var center = /** @type {ol.Coordinate} */ (this.getCenter());
+ var projection = this.getProjection();
+ var resolution = /** @type {number} */ (this.getResolution());
+ var rotation = this.getRotation();
+ return /** @type {olx.ViewState} */ ({
+ // Snap center to closest pixel
+ center: [
+ Math.round(center[0] / resolution) * resolution,
+ Math.round(center[1] / resolution) * resolution
+ ],
+ projection: projection !== undefined ? projection : null,
+ resolution: resolution,
+ rotation: rotation
+ });
+};
+
+
+/**
+ * Get the current zoom level. Return undefined if the current
+ * resolution is undefined or not a "constrained resolution".
+ * @return {number|undefined} Zoom.
+ * @api stable
+ */
+ol.View.prototype.getZoom = function() {
+ var offset;
+ var resolution = this.getResolution();
+
+ if (resolution !== undefined) {
+ var res, z = 0;
+ do {
+ res = this.constrainResolution(this.maxResolution_, z);
+ if (res == resolution) {
+ offset = z;
+ break;
+ }
+ ++z;
+ } while (res > this.minResolution_);
+ }
+
+ return offset !== undefined ? this.minZoom_ + offset : offset;
+};
+
+
+/**
+ * Fit the given geometry or extent based on the given map size and border.
+ * The size is pixel dimensions of the box to fit the extent into.
+ * In most cases you will want to use the map size, that is `map.getSize()`.
+ * Takes care of the map angle.
+ * @param {ol.geom.SimpleGeometry|ol.Extent} geometry Geometry.
+ * @param {ol.Size} size Box pixel size.
+ * @param {olx.view.FitOptions=} opt_options Options.
+ * @api
+ */
+ol.View.prototype.fit = function(geometry, size, opt_options) {
+ if (!(geometry instanceof ol.geom.SimpleGeometry)) {
+ goog.asserts.assert(Array.isArray(geometry),
+ 'invalid extent or geometry');
+ goog.asserts.assert(!ol.extent.isEmpty(geometry),
+ 'cannot fit empty extent');
+ geometry = ol.geom.Polygon.fromExtent(geometry);
+ }
+
+ var options = opt_options || {};
+
+ var padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];
+ var constrainResolution = options.constrainResolution !== undefined ?
+ options.constrainResolution : true;
+ var nearest = options.nearest !== undefined ? options.nearest : false;
+ var minResolution;
+ if (options.minResolution !== undefined) {
+ minResolution = options.minResolution;
+ } else if (options.maxZoom !== undefined) {
+ minResolution = this.constrainResolution(
+ this.maxResolution_, options.maxZoom - this.minZoom_, 0);
+ } else {
+ minResolution = 0;
+ }
+ var coords = geometry.getFlatCoordinates();
+
+ // calculate rotated extent
+ var rotation = this.getRotation();
+ goog.asserts.assert(rotation !== undefined, 'rotation was not defined');
+ var cosAngle = Math.cos(-rotation);
+ var sinAngle = Math.sin(-rotation);
+ var minRotX = +Infinity;
+ var minRotY = +Infinity;
+ var maxRotX = -Infinity;
+ var maxRotY = -Infinity;
+ var stride = geometry.getStride();
+ for (var i = 0, ii = coords.length; i < ii; i += stride) {
+ var rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;
+ var rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;
+ minRotX = Math.min(minRotX, rotX);
+ minRotY = Math.min(minRotY, rotY);
+ maxRotX = Math.max(maxRotX, rotX);
+ maxRotY = Math.max(maxRotY, rotY);
+ }
+
+ // calculate resolution
+ var resolution = this.getResolutionForExtent(
+ [minRotX, minRotY, maxRotX, maxRotY],
+ [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]);
+ resolution = isNaN(resolution) ? minResolution :
+ Math.max(resolution, minResolution);
+ if (constrainResolution) {
+ var constrainedResolution = this.constrainResolution(resolution, 0, 0);
+ if (!nearest && constrainedResolution < resolution) {
+ constrainedResolution = this.constrainResolution(
+ constrainedResolution, -1, 0);
+ }
+ resolution = constrainedResolution;
+ }
+ this.setResolution(resolution);
+
+ // calculate center
+ sinAngle = -sinAngle; // go back to original rotation
+ var centerRotX = (minRotX + maxRotX) / 2;
+ var centerRotY = (minRotY + maxRotY) / 2;
+ centerRotX += (padding[1] - padding[3]) / 2 * resolution;
+ centerRotY += (padding[0] - padding[2]) / 2 * resolution;
+ var centerX = centerRotX * cosAngle - centerRotY * sinAngle;
+ var centerY = centerRotY * cosAngle + centerRotX * sinAngle;
+
+ this.setCenter([centerX, centerY]);
+};
+
+
+/**
+ * Center on coordinate and view position.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.Size} size Box pixel size.
+ * @param {ol.Pixel} position Position on the view to center on.
+ * @api
+ */
+ol.View.prototype.centerOn = function(coordinate, size, position) {
+ // calculate rotated position
+ var rotation = this.getRotation();
+ var cosAngle = Math.cos(-rotation);
+ var sinAngle = Math.sin(-rotation);
+ var rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
+ var rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
+ var resolution = this.getResolution();
+ rotX += (size[0] / 2 - position[0]) * resolution;
+ rotY += (position[1] - size[1] / 2) * resolution;
+
+ // go back to original angle
+ sinAngle = -sinAngle; // go back to original rotation
+ var centerX = rotX * cosAngle - rotY * sinAngle;
+ var centerY = rotY * cosAngle + rotX * sinAngle;
+
+ this.setCenter([centerX, centerY]);
+};
+
+
+/**
+ * @return {boolean} Is defined.
+ */
+ol.View.prototype.isDef = function() {
+ return !!this.getCenter() && this.getResolution() !== undefined;
+};
+
+
+/**
+ * Rotate the view around a given coordinate.
+ * @param {number} rotation New rotation value for the view.
+ * @param {ol.Coordinate=} opt_anchor The rotation center.
+ * @api stable
+ */
+ol.View.prototype.rotate = function(rotation, opt_anchor) {
+ if (opt_anchor !== undefined) {
+ var center = this.calculateCenterRotate(rotation, opt_anchor);
+ this.setCenter(center);
+ }
+ this.setRotation(rotation);
+};
+
+
+/**
+ * Set the center of the current view.
+ * @param {ol.Coordinate|undefined} center The center of the view.
+ * @observable
+ * @api stable
+ */
+ol.View.prototype.setCenter = function(center) {
+ this.set(ol.ViewProperty.CENTER, center);
+};
+
+
+/**
+ * @param {ol.ViewHint} hint Hint.
+ * @param {number} delta Delta.
+ * @return {number} New value.
+ */
+ol.View.prototype.setHint = function(hint, delta) {
+ goog.asserts.assert(0 <= hint && hint < this.hints_.length,
+ 'illegal hint (%s), must be between 0 and %s', hint, this.hints_.length);
+ this.hints_[hint] += delta;
+ goog.asserts.assert(this.hints_[hint] >= 0,
+ 'Hint at %s must be positive, was %s', hint, this.hints_[hint]);
+ return this.hints_[hint];
+};
+
+
+/**
+ * Set the resolution for this view.
+ * @param {number|undefined} resolution The resolution of the view.
+ * @observable
+ * @api stable
+ */
+ol.View.prototype.setResolution = function(resolution) {
+ this.set(ol.ViewProperty.RESOLUTION, resolution);
+};
+
+
+/**
+ * Set the rotation for this view.
+ * @param {number} rotation The rotation of the view in radians.
+ * @observable
+ * @api stable
+ */
+ol.View.prototype.setRotation = function(rotation) {
+ this.set(ol.ViewProperty.ROTATION, rotation);
+};
+
+
+/**
+ * Zoom to a specific zoom level.
+ * @param {number} zoom Zoom level.
+ * @api stable
+ */
+ol.View.prototype.setZoom = function(zoom) {
+ var resolution = this.constrainResolution(
+ this.maxResolution_, zoom - this.minZoom_, 0);
+ this.setResolution(resolution);
+};
+
+
+/**
+ * @param {olx.ViewOptions} options View options.
+ * @private
+ * @return {ol.CenterConstraintType} The constraint.
+ */
+ol.View.createCenterConstraint_ = function(options) {
+ if (options.extent !== undefined) {
+ return ol.CenterConstraint.createExtent(options.extent);
+ } else {
+ return ol.CenterConstraint.none;
+ }
+};
+
+
+/**
+ * @private
+ * @param {olx.ViewOptions} options View options.
+ * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number,
+ * minResolution: number}} The constraint.
+ */
+ol.View.createResolutionConstraint_ = function(options) {
+ var resolutionConstraint;
+ var maxResolution;
+ var minResolution;
+
+ // TODO: move these to be ol constants
+ // see https://github.com/openlayers/ol3/issues/2076
+ var defaultMaxZoom = 28;
+ var defaultZoomFactor = 2;
+
+ var minZoom = options.minZoom !== undefined ?
+ options.minZoom : ol.DEFAULT_MIN_ZOOM;
+
+ var maxZoom = options.maxZoom !== undefined ?
+ options.maxZoom : defaultMaxZoom;
+
+ var zoomFactor = options.zoomFactor !== undefined ?
+ options.zoomFactor : defaultZoomFactor;
+
+ if (options.resolutions !== undefined) {
+ var resolutions = options.resolutions;
+ maxResolution = resolutions[0];
+ minResolution = resolutions[resolutions.length - 1];
+ resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions(
+ resolutions);
+ } else {
+ // calculate the default min and max resolution
+ var projection = ol.proj.createProjection(options.projection, 'EPSG:3857');
+ var extent = projection.getExtent();
+ var size = !extent ?
+ // use an extent that can fit the whole world if need be
+ 360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /
+ projection.getMetersPerUnit() :
+ Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent));
+
+ var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow(
+ defaultZoomFactor, ol.DEFAULT_MIN_ZOOM);
+
+ var defaultMinResolution = defaultMaxResolution / Math.pow(
+ defaultZoomFactor, defaultMaxZoom - ol.DEFAULT_MIN_ZOOM);
+
+ // user provided maxResolution takes precedence
+ maxResolution = options.maxResolution;
+ if (maxResolution !== undefined) {
+ minZoom = 0;
+ } else {
+ maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom);
+ }
+
+ // user provided minResolution takes precedence
+ minResolution = options.minResolution;
+ if (minResolution === undefined) {
+ if (options.maxZoom !== undefined) {
+ if (options.maxResolution !== undefined) {
+ minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);
+ } else {
+ minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom);
+ }
+ } else {
+ minResolution = defaultMinResolution;
+ }
+ }
+
+ // given discrete zoom levels, minResolution may be different than provided
+ maxZoom = minZoom + Math.floor(
+ Math.log(maxResolution / minResolution) / Math.log(zoomFactor));
+ minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);
+
+ resolutionConstraint = ol.ResolutionConstraint.createSnapToPower(
+ zoomFactor, maxResolution, maxZoom - minZoom);
+ }
+ return {constraint: resolutionConstraint, maxResolution: maxResolution,
+ minResolution: minResolution, minZoom: minZoom};
+};
+
+
+/**
+ * @private
+ * @param {olx.ViewOptions} options View options.
+ * @return {ol.RotationConstraintType} Rotation constraint.
+ */
+ol.View.createRotationConstraint_ = function(options) {
+ var enableRotation = options.enableRotation !== undefined ?
+ options.enableRotation : true;
+ if (enableRotation) {
+ var constrainRotation = options.constrainRotation;
+ if (constrainRotation === undefined || constrainRotation === true) {
+ return ol.RotationConstraint.createSnapToZero();
+ } else if (constrainRotation === false) {
+ return ol.RotationConstraint.none;
+ } else if (goog.isNumber(constrainRotation)) {
+ return ol.RotationConstraint.createSnapToN(constrainRotation);
+ } else {
+ goog.asserts.fail(
+ 'illegal option for constrainRotation (%s)', constrainRotation);
+ return ol.RotationConstraint.none;
+ }
+ } else {
+ return ol.RotationConstraint.disable;
+ }
+};
+
+goog.provide('ol.easing');
+
+
+/**
+ * Start slow and speed up.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ * @api
+ */
+ol.easing.easeIn = function(t) {
+ return Math.pow(t, 3);
+};
+
+
+/**
+ * Start fast and slow down.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ * @api
+ */
+ol.easing.easeOut = function(t) {
+ return 1 - ol.easing.easeIn(1 - t);
+};
+
+
+/**
+ * Start slow, speed up, and then slow down again.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ * @api
+ */
+ol.easing.inAndOut = function(t) {
+ return 3 * t * t - 2 * t * t * t;
+};
+
+
+/**
+ * Maintain a constant speed over time.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ * @api
+ */
+ol.easing.linear = function(t) {
+ return t;
+};
+
+
+/**
+ * Start slow, speed up, and at the very end slow down again. This has the
+ * same general behavior as {@link ol.easing.inAndOut}, but the final slowdown
+ * is delayed.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ * @api
+ */
+ol.easing.upAndDown = function(t) {
+ if (t < 0.5) {
+ return ol.easing.inAndOut(2 * t);
+ } else {
+ return 1 - ol.easing.inAndOut(2 * (t - 0.5));
+ }
+};
+
+goog.provide('ol.animation');
+
+goog.require('ol');
+goog.require('ol.ViewHint');
+goog.require('ol.coordinate');
+goog.require('ol.easing');
+
+
+/**
+ * Generate an animated transition that will "bounce" the resolution as it
+ * approaches the final value.
+ * @param {olx.animation.BounceOptions} options Bounce options.
+ * @return {ol.PreRenderFunction} Pre-render function.
+ * @api
+ */
+ol.animation.bounce = function(options) {
+ var resolution = options.resolution;
+ var start = options.start ? options.start : Date.now();
+ var duration = options.duration !== undefined ? options.duration : 1000;
+ var easing = options.easing ?
+ options.easing : ol.easing.upAndDown;
+ return (
+ /**
+ * @param {ol.Map} map Map.
+ * @param {?olx.FrameState} frameState Frame state.
+ * @return {boolean} Run this function in the next frame.
+ */
+ function(map, frameState) {
+ if (frameState.time < start) {
+ frameState.animate = true;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else if (frameState.time < start + duration) {
+ var delta = easing((frameState.time - start) / duration);
+ var deltaResolution = resolution - frameState.viewState.resolution;
+ frameState.animate = true;
+ frameState.viewState.resolution += delta * deltaResolution;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else {
+ return false;
+ }
+ });
+};
+
+
+/**
+ * Generate an animated transition while updating the view center.
+ * @param {olx.animation.PanOptions} options Pan options.
+ * @return {ol.PreRenderFunction} Pre-render function.
+ * @api
+ */
+ol.animation.pan = function(options) {
+ var source = options.source;
+ var start = options.start ? options.start : Date.now();
+ var sourceX = source[0];
+ var sourceY = source[1];
+ var duration = options.duration !== undefined ? options.duration : 1000;
+ var easing = options.easing ?
+ options.easing : ol.easing.inAndOut;
+ return (
+ /**
+ * @param {ol.Map} map Map.
+ * @param {?olx.FrameState} frameState Frame state.
+ * @return {boolean} Run this function in the next frame.
+ */
+ function(map, frameState) {
+ if (frameState.time < start) {
+ frameState.animate = true;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else if (frameState.time < start + duration) {
+ var delta = 1 - easing((frameState.time - start) / duration);
+ var deltaX = sourceX - frameState.viewState.center[0];
+ var deltaY = sourceY - frameState.viewState.center[1];
+ frameState.animate = true;
+ frameState.viewState.center[0] += delta * deltaX;
+ frameState.viewState.center[1] += delta * deltaY;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else {
+ return false;
+ }
+ });
+};
+
+
+/**
+ * Generate an animated transition while updating the view rotation.
+ * @param {olx.animation.RotateOptions} options Rotate options.
+ * @return {ol.PreRenderFunction} Pre-render function.
+ * @api
+ */
+ol.animation.rotate = function(options) {
+ var sourceRotation = options.rotation ? options.rotation : 0;
+ var start = options.start ? options.start : Date.now();
+ var duration = options.duration !== undefined ? options.duration : 1000;
+ var easing = options.easing ?
+ options.easing : ol.easing.inAndOut;
+ var anchor = options.anchor ?
+ options.anchor : null;
+
+ return (
+ /**
+ * @param {ol.Map} map Map.
+ * @param {?olx.FrameState} frameState Frame state.
+ * @return {boolean} Run this function in the next frame.
+ */
+ function(map, frameState) {
+ if (frameState.time < start) {
+ frameState.animate = true;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else if (frameState.time < start + duration) {
+ var delta = 1 - easing((frameState.time - start) / duration);
+ var deltaRotation =
+ (sourceRotation - frameState.viewState.rotation) * delta;
+ frameState.animate = true;
+ frameState.viewState.rotation += deltaRotation;
+ if (anchor) {
+ var center = frameState.viewState.center;
+ ol.coordinate.sub(center, anchor);
+ ol.coordinate.rotate(center, deltaRotation);
+ ol.coordinate.add(center, anchor);
+ }
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else {
+ return false;
+ }
+ });
+};
+
+
+/**
+ * Generate an animated transition while updating the view resolution.
+ * @param {olx.animation.ZoomOptions} options Zoom options.
+ * @return {ol.PreRenderFunction} Pre-render function.
+ * @api
+ */
+ol.animation.zoom = function(options) {
+ var sourceResolution = options.resolution;
+ var start = options.start ? options.start : Date.now();
+ var duration = options.duration !== undefined ? options.duration : 1000;
+ var easing = options.easing ?
+ options.easing : ol.easing.inAndOut;
+ return (
+ /**
+ * @param {ol.Map} map Map.
+ * @param {?olx.FrameState} frameState Frame state.
+ * @return {boolean} Run this function in the next frame.
+ */
+ function(map, frameState) {
+ if (frameState.time < start) {
+ frameState.animate = true;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else if (frameState.time < start + duration) {
+ var delta = 1 - easing((frameState.time - start) / duration);
+ var deltaResolution =
+ sourceResolution - frameState.viewState.resolution;
+ frameState.animate = true;
+ frameState.viewState.resolution += delta * deltaResolution;
+ frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
+ return true;
+ } else {
+ return false;
+ }
+ });
+};
+
+goog.provide('ol.TileRange');
+
+goog.require('goog.asserts');
+
+
+/**
+ * A representation of a contiguous block of tiles. A tile range is specified
+ * by its min/max tile coordinates and is inclusive of coordinates.
+ *
+ * @constructor
+ * @param {number} minX Minimum X.
+ * @param {number} maxX Maximum X.
+ * @param {number} minY Minimum Y.
+ * @param {number} maxY Maximum Y.
+ * @struct
+ */
+ol.TileRange = function(minX, maxX, minY, maxY) {
+
+ /**
+ * @type {number}
+ */
+ this.minX = minX;
+
+ /**
+ * @type {number}
+ */
+ this.maxX = maxX;
+
+ /**
+ * @type {number}
+ */
+ this.minY = minY;
+
+ /**
+ * @type {number}
+ */
+ this.maxY = maxY;
+
+};
+
+
+/**
+ * @param {...ol.TileCoord} var_args Tile coordinates.
+ * @return {!ol.TileRange} Bounding tile box.
+ */
+ol.TileRange.boundingTileRange = function(var_args) {
+ var tileCoord0 = /** @type {ol.TileCoord} */ (arguments[0]);
+ var tileCoord0Z = tileCoord0[0];
+ var tileCoord0X = tileCoord0[1];
+ var tileCoord0Y = tileCoord0[2];
+ var tileRange = new ol.TileRange(tileCoord0X, tileCoord0X,
+ tileCoord0Y, tileCoord0Y);
+ var i, ii, tileCoord, tileCoordX, tileCoordY, tileCoordZ;
+ for (i = 1, ii = arguments.length; i < ii; ++i) {
+ tileCoord = /** @type {ol.TileCoord} */ (arguments[i]);
+ tileCoordZ = tileCoord[0];
+ tileCoordX = tileCoord[1];
+ tileCoordY = tileCoord[2];
+ goog.asserts.assert(tileCoordZ == tileCoord0Z,
+ 'passed tilecoords all have the same Z-value');
+ tileRange.minX = Math.min(tileRange.minX, tileCoordX);
+ tileRange.maxX = Math.max(tileRange.maxX, tileCoordX);
+ tileRange.minY = Math.min(tileRange.minY, tileCoordY);
+ tileRange.maxY = Math.max(tileRange.maxY, tileCoordY);
+ }
+ return tileRange;
+};
+
+
+/**
+ * @param {number} minX Minimum X.
+ * @param {number} maxX Maximum X.
+ * @param {number} minY Minimum Y.
+ * @param {number} maxY Maximum Y.
+ * @param {ol.TileRange|undefined} tileRange TileRange.
+ * @return {ol.TileRange} Tile range.
+ */
+ol.TileRange.createOrUpdate = function(minX, maxX, minY, maxY, tileRange) {
+ if (tileRange !== undefined) {
+ tileRange.minX = minX;
+ tileRange.maxX = maxX;
+ tileRange.minY = minY;
+ tileRange.maxY = maxY;
+ return tileRange;
+ } else {
+ return new ol.TileRange(minX, maxX, minY, maxY);
+ }
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @return {boolean} Contains tile coordinate.
+ */
+ol.TileRange.prototype.contains = function(tileCoord) {
+ return this.containsXY(tileCoord[1], tileCoord[2]);
+};
+
+
+/**
+ * @param {ol.TileRange} tileRange Tile range.
+ * @return {boolean} Contains.
+ */
+ol.TileRange.prototype.containsTileRange = function(tileRange) {
+ return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX &&
+ this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;
+};
+
+
+/**
+ * @param {number} x Tile coordinate x.
+ * @param {number} y Tile coordinate y.
+ * @return {boolean} Contains coordinate.
+ */
+ol.TileRange.prototype.containsXY = function(x, y) {
+ return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;
+};
+
+
+/**
+ * @param {ol.TileRange} tileRange Tile range.
+ * @return {boolean} Equals.
+ */
+ol.TileRange.prototype.equals = function(tileRange) {
+ return this.minX == tileRange.minX && this.minY == tileRange.minY &&
+ this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;
+};
+
+
+/**
+ * @param {ol.TileRange} tileRange Tile range.
+ */
+ol.TileRange.prototype.extend = function(tileRange) {
+ if (tileRange.minX < this.minX) {
+ this.minX = tileRange.minX;
+ }
+ if (tileRange.maxX > this.maxX) {
+ this.maxX = tileRange.maxX;
+ }
+ if (tileRange.minY < this.minY) {
+ this.minY = tileRange.minY;
+ }
+ if (tileRange.maxY > this.maxY) {
+ this.maxY = tileRange.maxY;
+ }
+};
+
+
+/**
+ * @return {number} Height.
+ */
+ol.TileRange.prototype.getHeight = function() {
+ return this.maxY - this.minY + 1;
+};
+
+
+/**
+ * @return {ol.Size} Size.
+ */
+ol.TileRange.prototype.getSize = function() {
+ return [this.getWidth(), this.getHeight()];
+};
+
+
+/**
+ * @return {number} Width.
+ */
+ol.TileRange.prototype.getWidth = function() {
+ return this.maxX - this.minX + 1;
+};
+
+
+/**
+ * @param {ol.TileRange} tileRange Tile range.
+ * @return {boolean} Intersects.
+ */
+ol.TileRange.prototype.intersects = function(tileRange) {
+ return this.minX <= tileRange.maxX &&
+ this.maxX >= tileRange.minX &&
+ this.minY <= tileRange.maxY &&
+ this.maxY >= tileRange.minY;
+};
+
+goog.provide('ol.Attribution');
+
+goog.require('ol.TileRange');
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * An attribution for a layer source.
+ *
+ * Example:
+ *
+ * source: new ol.source.OSM({
+ * attributions: [
+ * new ol.Attribution({
+ * html: 'All maps &copy; ' +
+ * '<a href="http://www.opencyclemap.org/">OpenCycleMap</a>'
+ * }),
+ * ol.source.OSM.ATTRIBUTION
+ * ],
+ * ..
+ *
+ * @constructor
+ * @param {olx.AttributionOptions} options Attribution options.
+ * @struct
+ * @api stable
+ */
+ol.Attribution = function(options) {
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.html_ = options.html;
+
+ /**
+ * @private
+ * @type {Object.<string, Array.<ol.TileRange>>}
+ */
+ this.tileRanges_ = options.tileRanges ? options.tileRanges : null;
+
+};
+
+
+/**
+ * Get the attribution markup.
+ * @return {string} The attribution HTML.
+ * @api stable
+ */
+ol.Attribution.prototype.getHTML = function() {
+ return this.html_;
+};
+
+
+/**
+ * @param {Object.<string, ol.TileRange>} tileRanges Tile ranges.
+ * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @param {!ol.proj.Projection} projection Projection.
+ * @return {boolean} Intersects any tile range.
+ */
+ol.Attribution.prototype.intersectsAnyTileRange = function(tileRanges, tileGrid, projection) {
+ if (!this.tileRanges_) {
+ return true;
+ }
+ var i, ii, tileRange, zKey;
+ for (zKey in tileRanges) {
+ if (!(zKey in this.tileRanges_)) {
+ continue;
+ }
+ tileRange = tileRanges[zKey];
+ var testTileRange;
+ for (i = 0, ii = this.tileRanges_[zKey].length; i < ii; ++i) {
+ testTileRange = this.tileRanges_[zKey][i];
+ if (testTileRange.intersects(tileRange)) {
+ return true;
+ }
+ var extentTileRange = tileGrid.getTileRangeForExtentAndZ(
+ ol.tilegrid.extentFromProjection(projection), parseInt(zKey, 10));
+ var width = extentTileRange.getWidth();
+ if (tileRange.minX < extentTileRange.minX ||
+ tileRange.maxX > extentTileRange.maxX) {
+ if (testTileRange.intersects(new ol.TileRange(
+ ol.math.modulo(tileRange.minX, width),
+ ol.math.modulo(tileRange.maxX, width),
+ tileRange.minY, tileRange.maxY))) {
+ return true;
+ }
+ if (tileRange.getWidth() > width &&
+ testTileRange.intersects(extentTileRange)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+};
+
+/**
+ * An implementation of Google Maps' MVCArray.
+ * @see https://developers.google.com/maps/documentation/javascript/reference
+ */
+
+goog.provide('ol.Collection');
+goog.provide('ol.CollectionEvent');
+goog.provide('ol.CollectionEventType');
+
+goog.require('ol.events.Event');
+goog.require('ol.Object');
+
+
+/**
+ * @enum {string}
+ */
+ol.CollectionEventType = {
+ /**
+ * Triggered when an item is added to the collection.
+ * @event ol.CollectionEvent#add
+ * @api stable
+ */
+ ADD: 'add',
+ /**
+ * Triggered when an item is removed from the collection.
+ * @event ol.CollectionEvent#remove
+ * @api stable
+ */
+ REMOVE: 'remove'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.Collection} instances are instances of this
+ * type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.CollectionEvent}
+ * @param {ol.CollectionEventType} type Type.
+ * @param {*=} opt_element Element.
+ * @param {Object=} opt_target Target.
+ */
+ol.CollectionEvent = function(type, opt_element, opt_target) {
+
+ ol.events.Event.call(this, type, opt_target);
+
+ /**
+ * The element that is added to or removed from the collection.
+ * @type {*}
+ * @api stable
+ */
+ this.element = opt_element;
+
+};
+ol.inherits(ol.CollectionEvent, ol.events.Event);
+
+
+/**
+ * @enum {string}
+ */
+ol.CollectionProperty = {
+ LENGTH: 'length'
+};
+
+
+/**
+ * @classdesc
+ * An expanded version of standard JS Array, adding convenience methods for
+ * manipulation. Add and remove changes to the Collection trigger a Collection
+ * event. Note that this does not cover changes to the objects _within_ the
+ * Collection; they trigger events on the appropriate object, not on the
+ * Collection as a whole.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @fires ol.CollectionEvent
+ * @param {!Array.<T>=} opt_array Array.
+ * @template T
+ * @api stable
+ */
+ol.Collection = function(opt_array) {
+
+ ol.Object.call(this);
+
+ /**
+ * @private
+ * @type {!Array.<T>}
+ */
+ this.array_ = opt_array ? opt_array : [];
+
+ this.updateLength_();
+
+};
+ol.inherits(ol.Collection, ol.Object);
+
+
+/**
+ * Remove all elements from the collection.
+ * @api stable
+ */
+ol.Collection.prototype.clear = function() {
+ while (this.getLength() > 0) {
+ this.pop();
+ }
+};
+
+
+/**
+ * Add elements to the collection. This pushes each item in the provided array
+ * to the end of the collection.
+ * @param {!Array.<T>} arr Array.
+ * @return {ol.Collection.<T>} This collection.
+ * @api stable
+ */
+ol.Collection.prototype.extend = function(arr) {
+ var i, ii;
+ for (i = 0, ii = arr.length; i < ii; ++i) {
+ this.push(arr[i]);
+ }
+ return this;
+};
+
+
+/**
+ * Iterate over each element, calling the provided callback.
+ * @param {function(this: S, T, number, Array.<T>): *} f The function to call
+ * for every element. This function takes 3 arguments (the element, the
+ * index and the array). The return value is ignored.
+ * @param {S=} opt_this The object to use as `this` in `f`.
+ * @template S
+ * @api stable
+ */
+ol.Collection.prototype.forEach = function(f, opt_this) {
+ this.array_.forEach(f, opt_this);
+};
+
+
+/**
+ * Get a reference to the underlying Array object. Warning: if the array
+ * is mutated, no events will be dispatched by the collection, and the
+ * collection's "length" property won't be in sync with the actual length
+ * of the array.
+ * @return {!Array.<T>} Array.
+ * @api stable
+ */
+ol.Collection.prototype.getArray = function() {
+ return this.array_;
+};
+
+
+/**
+ * Get the element at the provided index.
+ * @param {number} index Index.
+ * @return {T} Element.
+ * @api stable
+ */
+ol.Collection.prototype.item = function(index) {
+ return this.array_[index];
+};
+
+
+/**
+ * Get the length of this collection.
+ * @return {number} The length of the array.
+ * @observable
+ * @api stable
+ */
+ol.Collection.prototype.getLength = function() {
+ return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH));
+};
+
+
+/**
+ * Insert an element at the provided index.
+ * @param {number} index Index.
+ * @param {T} elem Element.
+ * @api stable
+ */
+ol.Collection.prototype.insertAt = function(index, elem) {
+ this.array_.splice(index, 0, elem);
+ this.updateLength_();
+ this.dispatchEvent(
+ new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this));
+};
+
+
+/**
+ * Remove the last element of the collection and return it.
+ * Return `undefined` if the collection is empty.
+ * @return {T|undefined} Element.
+ * @api stable
+ */
+ol.Collection.prototype.pop = function() {
+ return this.removeAt(this.getLength() - 1);
+};
+
+
+/**
+ * Insert the provided element at the end of the collection.
+ * @param {T} elem Element.
+ * @return {number} Length.
+ * @api stable
+ */
+ol.Collection.prototype.push = function(elem) {
+ var n = this.array_.length;
+ this.insertAt(n, elem);
+ return n;
+};
+
+
+/**
+ * Remove the first occurrence of an element from the collection.
+ * @param {T} elem Element.
+ * @return {T|undefined} The removed element or undefined if none found.
+ * @api stable
+ */
+ol.Collection.prototype.remove = function(elem) {
+ var arr = this.array_;
+ var i, ii;
+ for (i = 0, ii = arr.length; i < ii; ++i) {
+ if (arr[i] === elem) {
+ return this.removeAt(i);
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * Remove the element at the provided index and return it.
+ * Return `undefined` if the collection does not contain this index.
+ * @param {number} index Index.
+ * @return {T|undefined} Value.
+ * @api stable
+ */
+ol.Collection.prototype.removeAt = function(index) {
+ var prev = this.array_[index];
+ this.array_.splice(index, 1);
+ this.updateLength_();
+ this.dispatchEvent(
+ new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this));
+ return prev;
+};
+
+
+/**
+ * Set the element at the provided index.
+ * @param {number} index Index.
+ * @param {T} elem Element.
+ * @api stable
+ */
+ol.Collection.prototype.setAt = function(index, elem) {
+ var n = this.getLength();
+ if (index < n) {
+ var prev = this.array_[index];
+ this.array_[index] = elem;
+ this.dispatchEvent(
+ new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this));
+ this.dispatchEvent(
+ new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this));
+ } else {
+ var j;
+ for (j = n; j < index; ++j) {
+ this.insertAt(j, undefined);
+ }
+ this.insertAt(index, elem);
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.Collection.prototype.updateLength_ = function() {
+ this.set(ol.CollectionProperty.LENGTH, this.array_.length);
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Names of standard colors with their associated hex values.
+ */
+
+goog.provide('goog.color.names');
+
+
+/**
+ * A map that contains a lot of colors that are recognised by various browsers.
+ * This list is way larger than the minimal one dictated by W3C.
+ * The keys of this map are the lowercase "readable" names of the colors, while
+ * the values are the "hex" values.
+ *
+ * @type {!Object<string, string>}
+ */
+goog.color.names = {
+ 'aliceblue': '#f0f8ff',
+ 'antiquewhite': '#faebd7',
+ 'aqua': '#00ffff',
+ 'aquamarine': '#7fffd4',
+ 'azure': '#f0ffff',
+ 'beige': '#f5f5dc',
+ 'bisque': '#ffe4c4',
+ 'black': '#000000',
+ 'blanchedalmond': '#ffebcd',
+ 'blue': '#0000ff',
+ 'blueviolet': '#8a2be2',
+ 'brown': '#a52a2a',
+ 'burlywood': '#deb887',
+ 'cadetblue': '#5f9ea0',
+ 'chartreuse': '#7fff00',
+ 'chocolate': '#d2691e',
+ 'coral': '#ff7f50',
+ 'cornflowerblue': '#6495ed',
+ 'cornsilk': '#fff8dc',
+ 'crimson': '#dc143c',
+ 'cyan': '#00ffff',
+ 'darkblue': '#00008b',
+ 'darkcyan': '#008b8b',
+ 'darkgoldenrod': '#b8860b',
+ 'darkgray': '#a9a9a9',
+ 'darkgreen': '#006400',
+ 'darkgrey': '#a9a9a9',
+ 'darkkhaki': '#bdb76b',
+ 'darkmagenta': '#8b008b',
+ 'darkolivegreen': '#556b2f',
+ 'darkorange': '#ff8c00',
+ 'darkorchid': '#9932cc',
+ 'darkred': '#8b0000',
+ 'darksalmon': '#e9967a',
+ 'darkseagreen': '#8fbc8f',
+ 'darkslateblue': '#483d8b',
+ 'darkslategray': '#2f4f4f',
+ 'darkslategrey': '#2f4f4f',
+ 'darkturquoise': '#00ced1',
+ 'darkviolet': '#9400d3',
+ 'deeppink': '#ff1493',
+ 'deepskyblue': '#00bfff',
+ 'dimgray': '#696969',
+ 'dimgrey': '#696969',
+ 'dodgerblue': '#1e90ff',
+ 'firebrick': '#b22222',
+ 'floralwhite': '#fffaf0',
+ 'forestgreen': '#228b22',
+ 'fuchsia': '#ff00ff',
+ 'gainsboro': '#dcdcdc',
+ 'ghostwhite': '#f8f8ff',
+ 'gold': '#ffd700',
+ 'goldenrod': '#daa520',
+ 'gray': '#808080',
+ 'green': '#008000',
+ 'greenyellow': '#adff2f',
+ 'grey': '#808080',
+ 'honeydew': '#f0fff0',
+ 'hotpink': '#ff69b4',
+ 'indianred': '#cd5c5c',
+ 'indigo': '#4b0082',
+ 'ivory': '#fffff0',
+ 'khaki': '#f0e68c',
+ 'lavender': '#e6e6fa',
+ 'lavenderblush': '#fff0f5',
+ 'lawngreen': '#7cfc00',
+ 'lemonchiffon': '#fffacd',
+ 'lightblue': '#add8e6',
+ 'lightcoral': '#f08080',
+ 'lightcyan': '#e0ffff',
+ 'lightgoldenrodyellow': '#fafad2',
+ 'lightgray': '#d3d3d3',
+ 'lightgreen': '#90ee90',
+ 'lightgrey': '#d3d3d3',
+ 'lightpink': '#ffb6c1',
+ 'lightsalmon': '#ffa07a',
+ 'lightseagreen': '#20b2aa',
+ 'lightskyblue': '#87cefa',
+ 'lightslategray': '#778899',
+ 'lightslategrey': '#778899',
+ 'lightsteelblue': '#b0c4de',
+ 'lightyellow': '#ffffe0',
+ 'lime': '#00ff00',
+ 'limegreen': '#32cd32',
+ 'linen': '#faf0e6',
+ 'magenta': '#ff00ff',
+ 'maroon': '#800000',
+ 'mediumaquamarine': '#66cdaa',
+ 'mediumblue': '#0000cd',
+ 'mediumorchid': '#ba55d3',
+ 'mediumpurple': '#9370db',
+ 'mediumseagreen': '#3cb371',
+ 'mediumslateblue': '#7b68ee',
+ 'mediumspringgreen': '#00fa9a',
+ 'mediumturquoise': '#48d1cc',
+ 'mediumvioletred': '#c71585',
+ 'midnightblue': '#191970',
+ 'mintcream': '#f5fffa',
+ 'mistyrose': '#ffe4e1',
+ 'moccasin': '#ffe4b5',
+ 'navajowhite': '#ffdead',
+ 'navy': '#000080',
+ 'oldlace': '#fdf5e6',
+ 'olive': '#808000',
+ 'olivedrab': '#6b8e23',
+ 'orange': '#ffa500',
+ 'orangered': '#ff4500',
+ 'orchid': '#da70d6',
+ 'palegoldenrod': '#eee8aa',
+ 'palegreen': '#98fb98',
+ 'paleturquoise': '#afeeee',
+ 'palevioletred': '#db7093',
+ 'papayawhip': '#ffefd5',
+ 'peachpuff': '#ffdab9',
+ 'peru': '#cd853f',
+ 'pink': '#ffc0cb',
+ 'plum': '#dda0dd',
+ 'powderblue': '#b0e0e6',
+ 'purple': '#800080',
+ 'red': '#ff0000',
+ 'rosybrown': '#bc8f8f',
+ 'royalblue': '#4169e1',
+ 'saddlebrown': '#8b4513',
+ 'salmon': '#fa8072',
+ 'sandybrown': '#f4a460',
+ 'seagreen': '#2e8b57',
+ 'seashell': '#fff5ee',
+ 'sienna': '#a0522d',
+ 'silver': '#c0c0c0',
+ 'skyblue': '#87ceeb',
+ 'slateblue': '#6a5acd',
+ 'slategray': '#708090',
+ 'slategrey': '#708090',
+ 'snow': '#fffafa',
+ 'springgreen': '#00ff7f',
+ 'steelblue': '#4682b4',
+ 'tan': '#d2b48c',
+ 'teal': '#008080',
+ 'thistle': '#d8bfd8',
+ 'tomato': '#ff6347',
+ 'turquoise': '#40e0d0',
+ 'violet': '#ee82ee',
+ 'wheat': '#f5deb3',
+ 'white': '#ffffff',
+ 'whitesmoke': '#f5f5f5',
+ 'yellow': '#ffff00',
+ 'yellowgreen': '#9acd32'
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities for manipulating arrays.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.array');
+
+goog.require('goog.asserts');
+
+
+/**
+ * @define {boolean} NATIVE_ARRAY_PROTOTYPES indicates whether the code should
+ * rely on Array.prototype functions, if available.
+ *
+ * The Array.prototype functions can be defined by external libraries like
+ * Prototype and setting this flag to false forces closure to use its own
+ * goog.array implementation.
+ *
+ * If your javascript can be loaded by a third party site and you are wary about
+ * relying on the prototype functions, specify
+ * "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler.
+ *
+ * Setting goog.TRUSTED_SITE to false will automatically set
+ * NATIVE_ARRAY_PROTOTYPES to false.
+ */
+goog.define('goog.NATIVE_ARRAY_PROTOTYPES', goog.TRUSTED_SITE);
+
+
+/**
+ * @define {boolean} If true, JSCompiler will use the native implementation of
+ * array functions where appropriate (e.g., {@code Array#filter}) and remove the
+ * unused pure JS implementation.
+ */
+goog.define('goog.array.ASSUME_NATIVE_FUNCTIONS', false);
+
+
+/**
+ * Returns the last element in an array without removing it.
+ * Same as goog.array.last.
+ * @param {IArrayLike<T>|string} array The array.
+ * @return {T} Last item in array.
+ * @template T
+ */
+goog.array.peek = function(array) {
+ return array[array.length - 1];
+};
+
+
+/**
+ * Returns the last element in an array without removing it.
+ * Same as goog.array.peek.
+ * @param {IArrayLike<T>|string} array The array.
+ * @return {T} Last item in array.
+ * @template T
+ */
+goog.array.last = goog.array.peek;
+
+// NOTE(arv): Since most of the array functions are generic it allows you to
+// pass an array-like object. Strings have a length and are considered array-
+// like. However, the 'in' operator does not work on strings so we cannot just
+// use the array path even if the browser supports indexing into strings. We
+// therefore end up splitting the string.
+
+
+/**
+ * Returns the index of the first element of an array with a specified value, or
+ * -1 if the element is not present in the array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-indexof}
+ *
+ * @param {IArrayLike<T>|string} arr The array to be searched.
+ * @param {T} obj The object for which we are searching.
+ * @param {number=} opt_fromIndex The index at which to start the search. If
+ * omitted the search starts at index 0.
+ * @return {number} The index of the first matching array element.
+ * @template T
+ */
+goog.array.indexOf = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.indexOf) ?
+ function(arr, obj, opt_fromIndex) {
+ goog.asserts.assert(arr.length != null);
+
+ return Array.prototype.indexOf.call(arr, obj, opt_fromIndex);
+ } :
+ function(arr, obj, opt_fromIndex) {
+ var fromIndex = opt_fromIndex == null ?
+ 0 :
+ (opt_fromIndex < 0 ? Math.max(0, arr.length + opt_fromIndex) :
+ opt_fromIndex);
+
+ if (goog.isString(arr)) {
+ // Array.prototype.indexOf uses === so only strings should be found.
+ if (!goog.isString(obj) || obj.length != 1) {
+ return -1;
+ }
+ return arr.indexOf(obj, fromIndex);
+ }
+
+ for (var i = fromIndex; i < arr.length; i++) {
+ if (i in arr && arr[i] === obj) return i;
+ }
+ return -1;
+ };
+
+
+/**
+ * Returns the index of the last element of an array with a specified value, or
+ * -1 if the element is not present in the array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-lastindexof}
+ *
+ * @param {!IArrayLike<T>|string} arr The array to be searched.
+ * @param {T} obj The object for which we are searching.
+ * @param {?number=} opt_fromIndex The index at which to start the search. If
+ * omitted the search starts at the end of the array.
+ * @return {number} The index of the last matching array element.
+ * @template T
+ */
+goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.lastIndexOf) ?
+ function(arr, obj, opt_fromIndex) {
+ goog.asserts.assert(arr.length != null);
+
+ // Firefox treats undefined and null as 0 in the fromIndex argument which
+ // leads it to always return -1
+ var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex;
+ return Array.prototype.lastIndexOf.call(arr, obj, fromIndex);
+ } :
+ function(arr, obj, opt_fromIndex) {
+ var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex;
+
+ if (fromIndex < 0) {
+ fromIndex = Math.max(0, arr.length + fromIndex);
+ }
+
+ if (goog.isString(arr)) {
+ // Array.prototype.lastIndexOf uses === so only strings should be found.
+ if (!goog.isString(obj) || obj.length != 1) {
+ return -1;
+ }
+ return arr.lastIndexOf(obj, fromIndex);
+ }
+
+ for (var i = fromIndex; i >= 0; i--) {
+ if (i in arr && arr[i] === obj) return i;
+ }
+ return -1;
+ };
+
+
+/**
+ * Calls a function for each element in an array. Skips holes in the array.
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-foreach}
+ *
+ * @param {IArrayLike<T>|string} arr Array or array like object over
+ * which to iterate.
+ * @param {?function(this: S, T, number, ?): ?} f The function to call for every
+ * element. This function takes 3 arguments (the element, the index and the
+ * array). The return value is ignored.
+ * @param {S=} opt_obj The object to be used as the value of 'this' within f.
+ * @template T,S
+ */
+goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.forEach) ?
+ function(arr, f, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+
+ Array.prototype.forEach.call(arr, f, opt_obj);
+ } :
+ function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = 0; i < l; i++) {
+ if (i in arr2) {
+ f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr);
+ }
+ }
+ };
+
+
+/**
+ * Calls a function for each element in an array, starting from the last
+ * element rather than the first.
+ *
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this: S, T, number, ?): ?} f The function to call for every
+ * element. This function
+ * takes 3 arguments (the element, the index and the array). The return
+ * value is ignored.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within f.
+ * @template T,S
+ */
+goog.array.forEachRight = function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = l - 1; i >= 0; --i) {
+ if (i in arr2) {
+ f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr);
+ }
+ }
+};
+
+
+/**
+ * Calls a function for each element in an array, and if the function returns
+ * true adds the element to a new array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-filter}
+ *
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?):boolean} f The function to call for
+ * every element. This function
+ * takes 3 arguments (the element, the index and the array) and must
+ * return a Boolean. If the return value is true the element is added to the
+ * result array. If it is false the element is not included.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within f.
+ * @return {!Array<T>} a new array in which only elements that passed the test
+ * are present.
+ * @template T,S
+ */
+goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.filter) ?
+ function(arr, f, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+
+ return Array.prototype.filter.call(arr, f, opt_obj);
+ } :
+ function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var res = [];
+ var resLength = 0;
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = 0; i < l; i++) {
+ if (i in arr2) {
+ var val = arr2[i]; // in case f mutates arr2
+ if (f.call(/** @type {?} */ (opt_obj), val, i, arr)) {
+ res[resLength++] = val;
+ }
+ }
+ }
+ return res;
+ };
+
+
+/**
+ * Calls a function for each element in an array and inserts the result into a
+ * new array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-map}
+ *
+ * @param {IArrayLike<VALUE>|string} arr Array or array like object
+ * over which to iterate.
+ * @param {function(this:THIS, VALUE, number, ?): RESULT} f The function to call
+ * for every element. This function takes 3 arguments (the element,
+ * the index and the array) and should return something. The result will be
+ * inserted into a new array.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within f.
+ * @return {!Array<RESULT>} a new array with the results from f.
+ * @template THIS, VALUE, RESULT
+ */
+goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.map) ?
+ function(arr, f, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+
+ return Array.prototype.map.call(arr, f, opt_obj);
+ } :
+ function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var res = new Array(l);
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = 0; i < l; i++) {
+ if (i in arr2) {
+ res[i] = f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr);
+ }
+ }
+ return res;
+ };
+
+
+/**
+ * Passes every element of an array into a function and accumulates the result.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-reduce}
+ *
+ * For example:
+ * var a = [1, 2, 3, 4];
+ * goog.array.reduce(a, function(r, v, i, arr) {return r + v;}, 0);
+ * returns 10
+ *
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {function(this:S, R, T, number, ?) : R} f The function to call for
+ * every element. This function
+ * takes 4 arguments (the function's previous result or the initial value,
+ * the value of the current array element, the current array index, and the
+ * array itself)
+ * function(previousValue, currentValue, index, array).
+ * @param {?} val The initial value to pass into the function on the first call.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within f.
+ * @return {R} Result of evaluating f repeatedly across the values of the array.
+ * @template T,S,R
+ */
+goog.array.reduce = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.reduce) ?
+ function(arr, f, val, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+ if (opt_obj) {
+ f = goog.bind(f, opt_obj);
+ }
+ return Array.prototype.reduce.call(arr, f, val);
+ } :
+ function(arr, f, val, opt_obj) {
+ var rval = val;
+ goog.array.forEach(arr, function(val, index) {
+ rval = f.call(/** @type {?} */ (opt_obj), rval, val, index, arr);
+ });
+ return rval;
+ };
+
+
+/**
+ * Passes every element of an array into a function and accumulates the result,
+ * starting from the last element and working towards the first.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-reduceright}
+ *
+ * For example:
+ * var a = ['a', 'b', 'c'];
+ * goog.array.reduceRight(a, function(r, v, i, arr) {return r + v;}, '');
+ * returns 'cba'
+ *
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, R, T, number, ?) : R} f The function to call for
+ * every element. This function
+ * takes 4 arguments (the function's previous result or the initial value,
+ * the value of the current array element, the current array index, and the
+ * array itself)
+ * function(previousValue, currentValue, index, array).
+ * @param {?} val The initial value to pass into the function on the first call.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within f.
+ * @return {R} Object returned as a result of evaluating f repeatedly across the
+ * values of the array.
+ * @template T,S,R
+ */
+goog.array.reduceRight = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.reduceRight) ?
+ function(arr, f, val, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+ goog.asserts.assert(f != null);
+ if (opt_obj) {
+ f = goog.bind(f, opt_obj);
+ }
+ return Array.prototype.reduceRight.call(arr, f, val);
+ } :
+ function(arr, f, val, opt_obj) {
+ var rval = val;
+ goog.array.forEachRight(arr, function(val, index) {
+ rval = f.call(/** @type {?} */ (opt_obj), rval, val, index, arr);
+ });
+ return rval;
+ };
+
+
+/**
+ * Calls f for each element of an array. If any call returns true, some()
+ * returns true (without checking the remaining elements). If all calls
+ * return false, some() returns false.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-some}
+ *
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call for
+ * for every element. This function takes 3 arguments (the element, the
+ * index and the array) and should return a boolean.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within f.
+ * @return {boolean} true if any element passes the test.
+ * @template T,S
+ */
+goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.some) ?
+ function(arr, f, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+
+ return Array.prototype.some.call(arr, f, opt_obj);
+ } :
+ function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = 0; i < l; i++) {
+ if (i in arr2 && f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr)) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+
+/**
+ * Call f for each element of an array. If all calls return true, every()
+ * returns true. If any call returns false, every() returns false and
+ * does not continue to check the remaining elements.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-every}
+ *
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call for
+ * for every element. This function takes 3 arguments (the element, the
+ * index and the array) and should return a boolean.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within f.
+ * @return {boolean} false if any element fails the test.
+ * @template T,S
+ */
+goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES &&
+ (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.every) ?
+ function(arr, f, opt_obj) {
+ goog.asserts.assert(arr.length != null);
+
+ return Array.prototype.every.call(arr, f, opt_obj);
+ } :
+ function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = 0; i < l; i++) {
+ if (i in arr2 && !f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+
+/**
+ * Counts the array elements that fulfill the predicate, i.e. for which the
+ * callback function returns true. Skips holes in the array.
+ *
+ * @param {!IArrayLike<T>|string} arr Array or array like object
+ * over which to iterate.
+ * @param {function(this: S, T, number, ?): boolean} f The function to call for
+ * every element. Takes 3 arguments (the element, the index and the array).
+ * @param {S=} opt_obj The object to be used as the value of 'this' within f.
+ * @return {number} The number of the matching elements.
+ * @template T,S
+ */
+goog.array.count = function(arr, f, opt_obj) {
+ var count = 0;
+ goog.array.forEach(arr, function(element, index, arr) {
+ if (f.call(/** @type {?} */ (opt_obj), element, index, arr)) {
+ ++count;
+ }
+ }, opt_obj);
+ return count;
+};
+
+
+/**
+ * Search an array for the first element that satisfies a given condition and
+ * return that element.
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ * for every element. This function takes 3 arguments (the element, the
+ * index and the array) and should return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {T|null} The first array element that passes the test, or null if no
+ * element is found.
+ * @template T,S
+ */
+goog.array.find = function(arr, f, opt_obj) {
+ var i = goog.array.findIndex(arr, f, opt_obj);
+ return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i];
+};
+
+
+/**
+ * Search an array for the first element that satisfies a given condition and
+ * return its index.
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call for
+ * every element. This function
+ * takes 3 arguments (the element, the index and the array) and should
+ * return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {number} The index of the first array element that passes the test,
+ * or -1 if no element is found.
+ * @template T,S
+ */
+goog.array.findIndex = function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = 0; i < l; i++) {
+ if (i in arr2 && f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr)) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+
+/**
+ * Search an array (in reverse order) for the last element that satisfies a
+ * given condition and return that element.
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ * for every element. This function
+ * takes 3 arguments (the element, the index and the array) and should
+ * return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {T|null} The last array element that passes the test, or null if no
+ * element is found.
+ * @template T,S
+ */
+goog.array.findRight = function(arr, f, opt_obj) {
+ var i = goog.array.findIndexRight(arr, f, opt_obj);
+ return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i];
+};
+
+
+/**
+ * Search an array (in reverse order) for the last element that satisfies a
+ * given condition and return its index.
+ * @param {IArrayLike<T>|string} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ * for every element. This function
+ * takes 3 arguments (the element, the index and the array) and should
+ * return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {number} The index of the last array element that passes the test,
+ * or -1 if no element is found.
+ * @template T,S
+ */
+goog.array.findIndexRight = function(arr, f, opt_obj) {
+ var l = arr.length; // must be fixed during loop... see docs
+ var arr2 = goog.isString(arr) ? arr.split('') : arr;
+ for (var i = l - 1; i >= 0; i--) {
+ if (i in arr2 && f.call(/** @type {?} */ (opt_obj), arr2[i], i, arr)) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+
+/**
+ * Whether the array contains the given object.
+ * @param {IArrayLike<?>|string} arr The array to test for the presence of the
+ * element.
+ * @param {*} obj The object for which to test.
+ * @return {boolean} true if obj is present.
+ */
+goog.array.contains = function(arr, obj) {
+ return goog.array.indexOf(arr, obj) >= 0;
+};
+
+
+/**
+ * Whether the array is empty.
+ * @param {IArrayLike<?>|string} arr The array to test.
+ * @return {boolean} true if empty.
+ */
+goog.array.isEmpty = function(arr) {
+ return arr.length == 0;
+};
+
+
+/**
+ * Clears the array.
+ * @param {IArrayLike<?>} arr Array or array like object to clear.
+ */
+goog.array.clear = function(arr) {
+ // For non real arrays we don't have the magic length so we delete the
+ // indices.
+ if (!goog.isArray(arr)) {
+ for (var i = arr.length - 1; i >= 0; i--) {
+ delete arr[i];
+ }
+ }
+ arr.length = 0;
+};
+
+
+/**
+ * Pushes an item into an array, if it's not already in the array.
+ * @param {Array<T>} arr Array into which to insert the item.
+ * @param {T} obj Value to add.
+ * @template T
+ */
+goog.array.insert = function(arr, obj) {
+ if (!goog.array.contains(arr, obj)) {
+ arr.push(obj);
+ }
+};
+
+
+/**
+ * Inserts an object at the given index of the array.
+ * @param {IArrayLike<?>} arr The array to modify.
+ * @param {*} obj The object to insert.
+ * @param {number=} opt_i The index at which to insert the object. If omitted,
+ * treated as 0. A negative index is counted from the end of the array.
+ */
+goog.array.insertAt = function(arr, obj, opt_i) {
+ goog.array.splice(arr, opt_i, 0, obj);
+};
+
+
+/**
+ * Inserts at the given index of the array, all elements of another array.
+ * @param {IArrayLike<?>} arr The array to modify.
+ * @param {IArrayLike<?>} elementsToAdd The array of elements to add.
+ * @param {number=} opt_i The index at which to insert the object. If omitted,
+ * treated as 0. A negative index is counted from the end of the array.
+ */
+goog.array.insertArrayAt = function(arr, elementsToAdd, opt_i) {
+ goog.partial(goog.array.splice, arr, opt_i, 0).apply(null, elementsToAdd);
+};
+
+
+/**
+ * Inserts an object into an array before a specified object.
+ * @param {Array<T>} arr The array to modify.
+ * @param {T} obj The object to insert.
+ * @param {T=} opt_obj2 The object before which obj should be inserted. If obj2
+ * is omitted or not found, obj is inserted at the end of the array.
+ * @template T
+ */
+goog.array.insertBefore = function(arr, obj, opt_obj2) {
+ var i;
+ if (arguments.length == 2 || (i = goog.array.indexOf(arr, opt_obj2)) < 0) {
+ arr.push(obj);
+ } else {
+ goog.array.insertAt(arr, obj, i);
+ }
+};
+
+
+/**
+ * Removes the first occurrence of a particular value from an array.
+ * @param {IArrayLike<T>} arr Array from which to remove
+ * value.
+ * @param {T} obj Object to remove.
+ * @return {boolean} True if an element was removed.
+ * @template T
+ */
+goog.array.remove = function(arr, obj) {
+ var i = goog.array.indexOf(arr, obj);
+ var rv;
+ if ((rv = i >= 0)) {
+ goog.array.removeAt(arr, i);
+ }
+ return rv;
+};
+
+
+/**
+ * Removes the last occurrence of a particular value from an array.
+ * @param {!IArrayLike<T>} arr Array from which to remove value.
+ * @param {T} obj Object to remove.
+ * @return {boolean} True if an element was removed.
+ * @template T
+ */
+goog.array.removeLast = function(arr, obj) {
+ var i = goog.array.lastIndexOf(arr, obj);
+ if (i >= 0) {
+ goog.array.removeAt(arr, i);
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * Removes from an array the element at index i
+ * @param {IArrayLike<?>} arr Array or array like object from which to
+ * remove value.
+ * @param {number} i The index to remove.
+ * @return {boolean} True if an element was removed.
+ */
+goog.array.removeAt = function(arr, i) {
+ goog.asserts.assert(arr.length != null);
+
+ // use generic form of splice
+ // splice returns the removed items and if successful the length of that
+ // will be 1
+ return Array.prototype.splice.call(arr, i, 1).length == 1;
+};
+
+
+/**
+ * Removes the first value that satisfies the given condition.
+ * @param {IArrayLike<T>} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ * for every element. This function
+ * takes 3 arguments (the element, the index and the array) and should
+ * return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {boolean} True if an element was removed.
+ * @template T,S
+ */
+goog.array.removeIf = function(arr, f, opt_obj) {
+ var i = goog.array.findIndex(arr, f, opt_obj);
+ if (i >= 0) {
+ goog.array.removeAt(arr, i);
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * Removes all values that satisfy the given condition.
+ * @param {IArrayLike<T>} arr Array or array
+ * like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ * for every element. This function
+ * takes 3 arguments (the element, the index and the array) and should
+ * return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {number} The number of items removed
+ * @template T,S
+ */
+goog.array.removeAllIf = function(arr, f, opt_obj) {
+ var removedCount = 0;
+ goog.array.forEachRight(arr, function(val, index) {
+ if (f.call(/** @type {?} */ (opt_obj), val, index, arr)) {
+ if (goog.array.removeAt(arr, index)) {
+ removedCount++;
+ }
+ }
+ });
+ return removedCount;
+};
+
+
+/**
+ * Returns a new array that is the result of joining the arguments. If arrays
+ * are passed then their items are added, however, if non-arrays are passed they
+ * will be added to the return array as is.
+ *
+ * Note that ArrayLike objects will be added as is, rather than having their
+ * items added.
+ *
+ * goog.array.concat([1, 2], [3, 4]) -> [1, 2, 3, 4]
+ * goog.array.concat(0, [1, 2]) -> [0, 1, 2]
+ * goog.array.concat([1, 2], null) -> [1, 2, null]
+ *
+ * There is bug in all current versions of IE (6, 7 and 8) where arrays created
+ * in an iframe become corrupted soon (not immediately) after the iframe is
+ * destroyed. This is common if loading data via goog.net.IframeIo, for example.
+ * This corruption only affects the concat method which will start throwing
+ * Catastrophic Errors (#-2147418113).
+ *
+ * See http://endoflow.com/scratch/corrupted-arrays.html for a test case.
+ *
+ * Internally goog.array should use this, so that all methods will continue to
+ * work on these broken array objects.
+ *
+ * @param {...*} var_args Items to concatenate. Arrays will have each item
+ * added, while primitives and objects will be added as is.
+ * @return {!Array<?>} The new resultant array.
+ */
+goog.array.concat = function(var_args) {
+ return Array.prototype.concat.apply(Array.prototype, arguments);
+};
+
+
+/**
+ * Returns a new array that contains the contents of all the arrays passed.
+ * @param {...!Array<T>} var_args
+ * @return {!Array<T>}
+ * @template T
+ */
+goog.array.join = function(var_args) {
+ return Array.prototype.concat.apply(Array.prototype, arguments);
+};
+
+
+/**
+ * Converts an object to an array.
+ * @param {IArrayLike<T>|string} object The object to convert to an
+ * array.
+ * @return {!Array<T>} The object converted into an array. If object has a
+ * length property, every property indexed with a non-negative number
+ * less than length will be included in the result. If object does not
+ * have a length property, an empty array will be returned.
+ * @template T
+ */
+goog.array.toArray = function(object) {
+ var length = object.length;
+
+ // If length is not a number the following it false. This case is kept for
+ // backwards compatibility since there are callers that pass objects that are
+ // not array like.
+ if (length > 0) {
+ var rv = new Array(length);
+ for (var i = 0; i < length; i++) {
+ rv[i] = object[i];
+ }
+ return rv;
+ }
+ return [];
+};
+
+
+/**
+ * Does a shallow copy of an array.
+ * @param {IArrayLike<T>|string} arr Array or array-like object to
+ * clone.
+ * @return {!Array<T>} Clone of the input array.
+ * @template T
+ */
+goog.array.clone = goog.array.toArray;
+
+
+/**
+ * Extends an array with another array, element, or "array like" object.
+ * This function operates 'in-place', it does not create a new Array.
+ *
+ * Example:
+ * var a = [];
+ * goog.array.extend(a, [0, 1]);
+ * a; // [0, 1]
+ * goog.array.extend(a, 2);
+ * a; // [0, 1, 2]
+ *
+ * @param {Array<VALUE>} arr1 The array to modify.
+ * @param {...(Array<VALUE>|VALUE)} var_args The elements or arrays of elements
+ * to add to arr1.
+ * @template VALUE
+ */
+goog.array.extend = function(arr1, var_args) {
+ for (var i = 1; i < arguments.length; i++) {
+ var arr2 = arguments[i];
+ if (goog.isArrayLike(arr2)) {
+ var len1 = arr1.length || 0;
+ var len2 = arr2.length || 0;
+ arr1.length = len1 + len2;
+ for (var j = 0; j < len2; j++) {
+ arr1[len1 + j] = arr2[j];
+ }
+ } else {
+ arr1.push(arr2);
+ }
+ }
+};
+
+
+/**
+ * Adds or removes elements from an array. This is a generic version of Array
+ * splice. This means that it might work on other objects similar to arrays,
+ * such as the arguments object.
+ *
+ * @param {IArrayLike<T>} arr The array to modify.
+ * @param {number|undefined} index The index at which to start changing the
+ * array. If not defined, treated as 0.
+ * @param {number} howMany How many elements to remove (0 means no removal. A
+ * value below 0 is treated as zero and so is any other non number. Numbers
+ * are floored).
+ * @param {...T} var_args Optional, additional elements to insert into the
+ * array.
+ * @return {!Array<T>} the removed elements.
+ * @template T
+ */
+goog.array.splice = function(arr, index, howMany, var_args) {
+ goog.asserts.assert(arr.length != null);
+
+ return Array.prototype.splice.apply(arr, goog.array.slice(arguments, 1));
+};
+
+
+/**
+ * Returns a new array from a segment of an array. This is a generic version of
+ * Array slice. This means that it might work on other objects similar to
+ * arrays, such as the arguments object.
+ *
+ * @param {IArrayLike<T>|string} arr The array from
+ * which to copy a segment.
+ * @param {number} start The index of the first element to copy.
+ * @param {number=} opt_end The index after the last element to copy.
+ * @return {!Array<T>} A new array containing the specified segment of the
+ * original array.
+ * @template T
+ */
+goog.array.slice = function(arr, start, opt_end) {
+ goog.asserts.assert(arr.length != null);
+
+ // passing 1 arg to slice is not the same as passing 2 where the second is
+ // null or undefined (in that case the second argument is treated as 0).
+ // we could use slice on the arguments object and then use apply instead of
+ // testing the length
+ if (arguments.length <= 2) {
+ return Array.prototype.slice.call(arr, start);
+ } else {
+ return Array.prototype.slice.call(arr, start, opt_end);
+ }
+};
+
+
+/**
+ * Removes all duplicates from an array (retaining only the first
+ * occurrence of each array element). This function modifies the
+ * array in place and doesn't change the order of the non-duplicate items.
+ *
+ * For objects, duplicates are identified as having the same unique ID as
+ * defined by {@link goog.getUid}.
+ *
+ * Alternatively you can specify a custom hash function that returns a unique
+ * value for each item in the array it should consider unique.
+ *
+ * Runtime: N,
+ * Worstcase space: 2N (no dupes)
+ *
+ * @param {IArrayLike<T>} arr The array from which to remove
+ * duplicates.
+ * @param {Array=} opt_rv An optional array in which to return the results,
+ * instead of performing the removal inplace. If specified, the original
+ * array will remain unchanged.
+ * @param {function(T):string=} opt_hashFn An optional function to use to
+ * apply to every item in the array. This function should return a unique
+ * value for each item in the array it should consider unique.
+ * @template T
+ */
+goog.array.removeDuplicates = function(arr, opt_rv, opt_hashFn) {
+ var returnArray = opt_rv || arr;
+ var defaultHashFn = function(item) {
+ // Prefix each type with a single character representing the type to
+ // prevent conflicting keys (e.g. true and 'true').
+ return goog.isObject(item) ? 'o' + goog.getUid(item) :
+ (typeof item).charAt(0) + item;
+ };
+ var hashFn = opt_hashFn || defaultHashFn;
+
+ var seen = {}, cursorInsert = 0, cursorRead = 0;
+ while (cursorRead < arr.length) {
+ var current = arr[cursorRead++];
+ var key = hashFn(current);
+ if (!Object.prototype.hasOwnProperty.call(seen, key)) {
+ seen[key] = true;
+ returnArray[cursorInsert++] = current;
+ }
+ }
+ returnArray.length = cursorInsert;
+};
+
+
+/**
+ * Searches the specified array for the specified target using the binary
+ * search algorithm. If no opt_compareFn is specified, elements are compared
+ * using <code>goog.array.defaultCompare</code>, which compares the elements
+ * using the built in < and > operators. This will produce the expected
+ * behavior for homogeneous arrays of String(s) and Number(s). The array
+ * specified <b>must</b> be sorted in ascending order (as defined by the
+ * comparison function). If the array is not sorted, results are undefined.
+ * If the array contains multiple instances of the specified target value, any
+ * of these instances may be found.
+ *
+ * Runtime: O(log n)
+ *
+ * @param {IArrayLike<VALUE>} arr The array to be searched.
+ * @param {TARGET} target The sought value.
+ * @param {function(TARGET, VALUE): number=} opt_compareFn Optional comparison
+ * function by which the array is ordered. Should take 2 arguments to
+ * compare, and return a negative number, zero, or a positive number
+ * depending on whether the first argument is less than, equal to, or
+ * greater than the second.
+ * @return {number} Lowest index of the target value if found, otherwise
+ * (-(insertion point) - 1). The insertion point is where the value should
+ * be inserted into arr to preserve the sorted property. Return value >= 0
+ * iff target is found.
+ * @template TARGET, VALUE
+ */
+goog.array.binarySearch = function(arr, target, opt_compareFn) {
+ return goog.array.binarySearch_(
+ arr, opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */,
+ target);
+};
+
+
+/**
+ * Selects an index in the specified array using the binary search algorithm.
+ * The evaluator receives an element and determines whether the desired index
+ * is before, at, or after it. The evaluator must be consistent (formally,
+ * goog.array.map(goog.array.map(arr, evaluator, opt_obj), goog.math.sign)
+ * must be monotonically non-increasing).
+ *
+ * Runtime: O(log n)
+ *
+ * @param {IArrayLike<VALUE>} arr The array to be searched.
+ * @param {function(this:THIS, VALUE, number, ?): number} evaluator
+ * Evaluator function that receives 3 arguments (the element, the index and
+ * the array). Should return a negative number, zero, or a positive number
+ * depending on whether the desired index is before, at, or after the
+ * element passed to it.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this'
+ * within evaluator.
+ * @return {number} Index of the leftmost element matched by the evaluator, if
+ * such exists; otherwise (-(insertion point) - 1). The insertion point is
+ * the index of the first element for which the evaluator returns negative,
+ * or arr.length if no such element exists. The return value is non-negative
+ * iff a match is found.
+ * @template THIS, VALUE
+ */
+goog.array.binarySelect = function(arr, evaluator, opt_obj) {
+ return goog.array.binarySearch_(
+ arr, evaluator, true /* isEvaluator */, undefined /* opt_target */,
+ opt_obj);
+};
+
+
+/**
+ * Implementation of a binary search algorithm which knows how to use both
+ * comparison functions and evaluators. If an evaluator is provided, will call
+ * the evaluator with the given optional data object, conforming to the
+ * interface defined in binarySelect. Otherwise, if a comparison function is
+ * provided, will call the comparison function against the given data object.
+ *
+ * This implementation purposefully does not use goog.bind or goog.partial for
+ * performance reasons.
+ *
+ * Runtime: O(log n)
+ *
+ * @param {IArrayLike<?>} arr The array to be searched.
+ * @param {function(?, ?, ?): number | function(?, ?): number} compareFn
+ * Either an evaluator or a comparison function, as defined by binarySearch
+ * and binarySelect above.
+ * @param {boolean} isEvaluator Whether the function is an evaluator or a
+ * comparison function.
+ * @param {?=} opt_target If the function is a comparison function, then
+ * this is the target to binary search for.
+ * @param {Object=} opt_selfObj If the function is an evaluator, this is an
+ * optional this object for the evaluator.
+ * @return {number} Lowest index of the target value if found, otherwise
+ * (-(insertion point) - 1). The insertion point is where the value should
+ * be inserted into arr to preserve the sorted property. Return value >= 0
+ * iff target is found.
+ * @private
+ */
+goog.array.binarySearch_ = function(
+ arr, compareFn, isEvaluator, opt_target, opt_selfObj) {
+ var left = 0; // inclusive
+ var right = arr.length; // exclusive
+ var found;
+ while (left < right) {
+ var middle = (left + right) >> 1;
+ var compareResult;
+ if (isEvaluator) {
+ compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr);
+ } else {
+ // NOTE(dimvar): To avoid this cast, we'd have to use function overloading
+ // for the type of binarySearch_, which the type system can't express yet.
+ compareResult = /** @type {function(?, ?): number} */ (compareFn)(
+ opt_target, arr[middle]);
+ }
+ if (compareResult > 0) {
+ left = middle + 1;
+ } else {
+ right = middle;
+ // We are looking for the lowest index so we can't return immediately.
+ found = !compareResult;
+ }
+ }
+ // left is the index if found, or the insertion point otherwise.
+ // ~left is a shorthand for -left - 1.
+ return found ? left : ~left;
+};
+
+
+/**
+ * Sorts the specified array into ascending order. If no opt_compareFn is
+ * specified, elements are compared using
+ * <code>goog.array.defaultCompare</code>, which compares the elements using
+ * the built in < and > operators. This will produce the expected behavior
+ * for homogeneous arrays of String(s) and Number(s), unlike the native sort,
+ * but will give unpredictable results for heterogeneous lists of strings and
+ * numbers with different numbers of digits.
+ *
+ * This sort is not guaranteed to be stable.
+ *
+ * Runtime: Same as <code>Array.prototype.sort</code>
+ *
+ * @param {Array<T>} arr The array to be sorted.
+ * @param {?function(T,T):number=} opt_compareFn Optional comparison
+ * function by which the
+ * array is to be ordered. Should take 2 arguments to compare, and return a
+ * negative number, zero, or a positive number depending on whether the
+ * first argument is less than, equal to, or greater than the second.
+ * @template T
+ */
+goog.array.sort = function(arr, opt_compareFn) {
+ // TODO(arv): Update type annotation since null is not accepted.
+ arr.sort(opt_compareFn || goog.array.defaultCompare);
+};
+
+
+/**
+ * Sorts the specified array into ascending order in a stable way. If no
+ * opt_compareFn is specified, elements are compared using
+ * <code>goog.array.defaultCompare</code>, which compares the elements using
+ * the built in < and > operators. This will produce the expected behavior
+ * for homogeneous arrays of String(s) and Number(s).
+ *
+ * Runtime: Same as <code>Array.prototype.sort</code>, plus an additional
+ * O(n) overhead of copying the array twice.
+ *
+ * @param {Array<T>} arr The array to be sorted.
+ * @param {?function(T, T): number=} opt_compareFn Optional comparison function
+ * by which the array is to be ordered. Should take 2 arguments to compare,
+ * and return a negative number, zero, or a positive number depending on
+ * whether the first argument is less than, equal to, or greater than the
+ * second.
+ * @template T
+ */
+goog.array.stableSort = function(arr, opt_compareFn) {
+ var compArr = new Array(arr.length);
+ for (var i = 0; i < arr.length; i++) {
+ compArr[i] = {index: i, value: arr[i]};
+ }
+ var valueCompareFn = opt_compareFn || goog.array.defaultCompare;
+ function stableCompareFn(obj1, obj2) {
+ return valueCompareFn(obj1.value, obj2.value) || obj1.index - obj2.index;
+ }
+ goog.array.sort(compArr, stableCompareFn);
+ for (var i = 0; i < arr.length; i++) {
+ arr[i] = compArr[i].value;
+ }
+};
+
+
+/**
+ * Sort the specified array into ascending order based on item keys
+ * returned by the specified key function.
+ * If no opt_compareFn is specified, the keys are compared in ascending order
+ * using <code>goog.array.defaultCompare</code>.
+ *
+ * Runtime: O(S(f(n)), where S is runtime of <code>goog.array.sort</code>
+ * and f(n) is runtime of the key function.
+ *
+ * @param {Array<T>} arr The array to be sorted.
+ * @param {function(T): K} keyFn Function taking array element and returning
+ * a key used for sorting this element.
+ * @param {?function(K, K): number=} opt_compareFn Optional comparison function
+ * by which the keys are to be ordered. Should take 2 arguments to compare,
+ * and return a negative number, zero, or a positive number depending on
+ * whether the first argument is less than, equal to, or greater than the
+ * second.
+ * @template T,K
+ */
+goog.array.sortByKey = function(arr, keyFn, opt_compareFn) {
+ var keyCompareFn = opt_compareFn || goog.array.defaultCompare;
+ goog.array.sort(
+ arr, function(a, b) { return keyCompareFn(keyFn(a), keyFn(b)); });
+};
+
+
+/**
+ * Sorts an array of objects by the specified object key and compare
+ * function. If no compare function is provided, the key values are
+ * compared in ascending order using <code>goog.array.defaultCompare</code>.
+ * This won't work for keys that get renamed by the compiler. So use
+ * {'foo': 1, 'bar': 2} rather than {foo: 1, bar: 2}.
+ * @param {Array<Object>} arr An array of objects to sort.
+ * @param {string} key The object key to sort by.
+ * @param {Function=} opt_compareFn The function to use to compare key
+ * values.
+ */
+goog.array.sortObjectsByKey = function(arr, key, opt_compareFn) {
+ goog.array.sortByKey(arr, function(obj) { return obj[key]; }, opt_compareFn);
+};
+
+
+/**
+ * Tells if the array is sorted.
+ * @param {!Array<T>} arr The array.
+ * @param {?function(T,T):number=} opt_compareFn Function to compare the
+ * array elements.
+ * Should take 2 arguments to compare, and return a negative number, zero,
+ * or a positive number depending on whether the first argument is less
+ * than, equal to, or greater than the second.
+ * @param {boolean=} opt_strict If true no equal elements are allowed.
+ * @return {boolean} Whether the array is sorted.
+ * @template T
+ */
+goog.array.isSorted = function(arr, opt_compareFn, opt_strict) {
+ var compare = opt_compareFn || goog.array.defaultCompare;
+ for (var i = 1; i < arr.length; i++) {
+ var compareResult = compare(arr[i - 1], arr[i]);
+ if (compareResult > 0 || compareResult == 0 && opt_strict) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Compares two arrays for equality. Two arrays are considered equal if they
+ * have the same length and their corresponding elements are equal according to
+ * the comparison function.
+ *
+ * @param {IArrayLike<?>} arr1 The first array to compare.
+ * @param {IArrayLike<?>} arr2 The second array to compare.
+ * @param {Function=} opt_equalsFn Optional comparison function.
+ * Should take 2 arguments to compare, and return true if the arguments
+ * are equal. Defaults to {@link goog.array.defaultCompareEquality} which
+ * compares the elements using the built-in '===' operator.
+ * @return {boolean} Whether the two arrays are equal.
+ */
+goog.array.equals = function(arr1, arr2, opt_equalsFn) {
+ if (!goog.isArrayLike(arr1) || !goog.isArrayLike(arr2) ||
+ arr1.length != arr2.length) {
+ return false;
+ }
+ var l = arr1.length;
+ var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality;
+ for (var i = 0; i < l; i++) {
+ if (!equalsFn(arr1[i], arr2[i])) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * 3-way array compare function.
+ * @param {!IArrayLike<VALUE>} arr1 The first array to
+ * compare.
+ * @param {!IArrayLike<VALUE>} arr2 The second array to
+ * compare.
+ * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison
+ * function by which the array is to be ordered. Should take 2 arguments to
+ * compare, and return a negative number, zero, or a positive number
+ * depending on whether the first argument is less than, equal to, or
+ * greater than the second.
+ * @return {number} Negative number, zero, or a positive number depending on
+ * whether the first argument is less than, equal to, or greater than the
+ * second.
+ * @template VALUE
+ */
+goog.array.compare3 = function(arr1, arr2, opt_compareFn) {
+ var compare = opt_compareFn || goog.array.defaultCompare;
+ var l = Math.min(arr1.length, arr2.length);
+ for (var i = 0; i < l; i++) {
+ var result = compare(arr1[i], arr2[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return goog.array.defaultCompare(arr1.length, arr2.length);
+};
+
+
+/**
+ * Compares its two arguments for order, using the built in < and >
+ * operators.
+ * @param {VALUE} a The first object to be compared.
+ * @param {VALUE} b The second object to be compared.
+ * @return {number} A negative number, zero, or a positive number as the first
+ * argument is less than, equal to, or greater than the second,
+ * respectively.
+ * @template VALUE
+ */
+goog.array.defaultCompare = function(a, b) {
+ return a > b ? 1 : a < b ? -1 : 0;
+};
+
+
+/**
+ * Compares its two arguments for inverse order, using the built in < and >
+ * operators.
+ * @param {VALUE} a The first object to be compared.
+ * @param {VALUE} b The second object to be compared.
+ * @return {number} A negative number, zero, or a positive number as the first
+ * argument is greater than, equal to, or less than the second,
+ * respectively.
+ * @template VALUE
+ */
+goog.array.inverseDefaultCompare = function(a, b) {
+ return -goog.array.defaultCompare(a, b);
+};
+
+
+/**
+ * Compares its two arguments for equality, using the built in === operator.
+ * @param {*} a The first object to compare.
+ * @param {*} b The second object to compare.
+ * @return {boolean} True if the two arguments are equal, false otherwise.
+ */
+goog.array.defaultCompareEquality = function(a, b) {
+ return a === b;
+};
+
+
+/**
+ * Inserts a value into a sorted array. The array is not modified if the
+ * value is already present.
+ * @param {IArrayLike<VALUE>} array The array to modify.
+ * @param {VALUE} value The object to insert.
+ * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison
+ * function by which the array is ordered. Should take 2 arguments to
+ * compare, and return a negative number, zero, or a positive number
+ * depending on whether the first argument is less than, equal to, or
+ * greater than the second.
+ * @return {boolean} True if an element was inserted.
+ * @template VALUE
+ */
+goog.array.binaryInsert = function(array, value, opt_compareFn) {
+ var index = goog.array.binarySearch(array, value, opt_compareFn);
+ if (index < 0) {
+ goog.array.insertAt(array, value, -(index + 1));
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * Removes a value from a sorted array.
+ * @param {!IArrayLike<VALUE>} array The array to modify.
+ * @param {VALUE} value The object to remove.
+ * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison
+ * function by which the array is ordered. Should take 2 arguments to
+ * compare, and return a negative number, zero, or a positive number
+ * depending on whether the first argument is less than, equal to, or
+ * greater than the second.
+ * @return {boolean} True if an element was removed.
+ * @template VALUE
+ */
+goog.array.binaryRemove = function(array, value, opt_compareFn) {
+ var index = goog.array.binarySearch(array, value, opt_compareFn);
+ return (index >= 0) ? goog.array.removeAt(array, index) : false;
+};
+
+
+/**
+ * Splits an array into disjoint buckets according to a splitting function.
+ * @param {Array<T>} array The array.
+ * @param {function(this:S, T,number,Array<T>):?} sorter Function to call for
+ * every element. This takes 3 arguments (the element, the index and the
+ * array) and must return a valid object key (a string, number, etc), or
+ * undefined, if that object should not be placed in a bucket.
+ * @param {S=} opt_obj The object to be used as the value of 'this' within
+ * sorter.
+ * @return {!Object} An object, with keys being all of the unique return values
+ * of sorter, and values being arrays containing the items for
+ * which the splitter returned that key.
+ * @template T,S
+ */
+goog.array.bucket = function(array, sorter, opt_obj) {
+ var buckets = {};
+
+ for (var i = 0; i < array.length; i++) {
+ var value = array[i];
+ var key = sorter.call(/** @type {?} */ (opt_obj), value, i, array);
+ if (goog.isDef(key)) {
+ // Push the value to the right bucket, creating it if necessary.
+ var bucket = buckets[key] || (buckets[key] = []);
+ bucket.push(value);
+ }
+ }
+
+ return buckets;
+};
+
+
+/**
+ * Creates a new object built from the provided array and the key-generation
+ * function.
+ * @param {IArrayLike<T>} arr Array or array like object over
+ * which to iterate whose elements will be the values in the new object.
+ * @param {?function(this:S, T, number, ?) : string} keyFunc The function to
+ * call for every element. This function takes 3 arguments (the element, the
+ * index and the array) and should return a string that will be used as the
+ * key for the element in the new object. If the function returns the same
+ * key for more than one element, the value for that key is
+ * implementation-defined.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ * within keyFunc.
+ * @return {!Object<T>} The new object.
+ * @template T,S
+ */
+goog.array.toObject = function(arr, keyFunc, opt_obj) {
+ var ret = {};
+ goog.array.forEach(arr, function(element, index) {
+ ret[keyFunc.call(/** @type {?} */ (opt_obj), element, index, arr)] =
+ element;
+ });
+ return ret;
+};
+
+
+/**
+ * Creates a range of numbers in an arithmetic progression.
+ *
+ * Range takes 1, 2, or 3 arguments:
+ * <pre>
+ * range(5) is the same as range(0, 5, 1) and produces [0, 1, 2, 3, 4]
+ * range(2, 5) is the same as range(2, 5, 1) and produces [2, 3, 4]
+ * range(-2, -5, -1) produces [-2, -3, -4]
+ * range(-2, -5, 1) produces [], since stepping by 1 wouldn't ever reach -5.
+ * </pre>
+ *
+ * @param {number} startOrEnd The starting value of the range if an end argument
+ * is provided. Otherwise, the start value is 0, and this is the end value.
+ * @param {number=} opt_end The optional end value of the range.
+ * @param {number=} opt_step The step size between range values. Defaults to 1
+ * if opt_step is undefined or 0.
+ * @return {!Array<number>} An array of numbers for the requested range. May be
+ * an empty array if adding the step would not converge toward the end
+ * value.
+ */
+goog.array.range = function(startOrEnd, opt_end, opt_step) {
+ var array = [];
+ var start = 0;
+ var end = startOrEnd;
+ var step = opt_step || 1;
+ if (opt_end !== undefined) {
+ start = startOrEnd;
+ end = opt_end;
+ }
+
+ if (step * (end - start) < 0) {
+ // Sign mismatch: start + step will never reach the end value.
+ return [];
+ }
+
+ if (step > 0) {
+ for (var i = start; i < end; i += step) {
+ array.push(i);
+ }
+ } else {
+ for (var i = start; i > end; i += step) {
+ array.push(i);
+ }
+ }
+ return array;
+};
+
+
+/**
+ * Returns an array consisting of the given value repeated N times.
+ *
+ * @param {VALUE} value The value to repeat.
+ * @param {number} n The repeat count.
+ * @return {!Array<VALUE>} An array with the repeated value.
+ * @template VALUE
+ */
+goog.array.repeat = function(value, n) {
+ var array = [];
+ for (var i = 0; i < n; i++) {
+ array[i] = value;
+ }
+ return array;
+};
+
+
+/**
+ * Returns an array consisting of every argument with all arrays
+ * expanded in-place recursively.
+ *
+ * @param {...*} var_args The values to flatten.
+ * @return {!Array<?>} An array containing the flattened values.
+ */
+goog.array.flatten = function(var_args) {
+ var CHUNK_SIZE = 8192;
+
+ var result = [];
+ for (var i = 0; i < arguments.length; i++) {
+ var element = arguments[i];
+ if (goog.isArray(element)) {
+ for (var c = 0; c < element.length; c += CHUNK_SIZE) {
+ var chunk = goog.array.slice(element, c, c + CHUNK_SIZE);
+ var recurseResult = goog.array.flatten.apply(null, chunk);
+ for (var r = 0; r < recurseResult.length; r++) {
+ result.push(recurseResult[r]);
+ }
+ }
+ } else {
+ result.push(element);
+ }
+ }
+ return result;
+};
+
+
+/**
+ * Rotates an array in-place. After calling this method, the element at
+ * index i will be the element previously at index (i - n) %
+ * array.length, for all values of i between 0 and array.length - 1,
+ * inclusive.
+ *
+ * For example, suppose list comprises [t, a, n, k, s]. After invoking
+ * rotate(array, 1) (or rotate(array, -4)), array will comprise [s, t, a, n, k].
+ *
+ * @param {!Array<T>} array The array to rotate.
+ * @param {number} n The amount to rotate.
+ * @return {!Array<T>} The array.
+ * @template T
+ */
+goog.array.rotate = function(array, n) {
+ goog.asserts.assert(array.length != null);
+
+ if (array.length) {
+ n %= array.length;
+ if (n > 0) {
+ Array.prototype.unshift.apply(array, array.splice(-n, n));
+ } else if (n < 0) {
+ Array.prototype.push.apply(array, array.splice(0, -n));
+ }
+ }
+ return array;
+};
+
+
+/**
+ * Moves one item of an array to a new position keeping the order of the rest
+ * of the items. Example use case: keeping a list of JavaScript objects
+ * synchronized with the corresponding list of DOM elements after one of the
+ * elements has been dragged to a new position.
+ * @param {!IArrayLike<?>} arr The array to modify.
+ * @param {number} fromIndex Index of the item to move between 0 and
+ * {@code arr.length - 1}.
+ * @param {number} toIndex Target index between 0 and {@code arr.length - 1}.
+ */
+goog.array.moveItem = function(arr, fromIndex, toIndex) {
+ goog.asserts.assert(fromIndex >= 0 && fromIndex < arr.length);
+ goog.asserts.assert(toIndex >= 0 && toIndex < arr.length);
+ // Remove 1 item at fromIndex.
+ var removedItems = Array.prototype.splice.call(arr, fromIndex, 1);
+ // Insert the removed item at toIndex.
+ Array.prototype.splice.call(arr, toIndex, 0, removedItems[0]);
+ // We don't use goog.array.insertAt and goog.array.removeAt, because they're
+ // significantly slower than splice.
+};
+
+
+/**
+ * Creates a new array for which the element at position i is an array of the
+ * ith element of the provided arrays. The returned array will only be as long
+ * as the shortest array provided; additional values are ignored. For example,
+ * the result of zipping [1, 2] and [3, 4, 5] is [[1,3], [2, 4]].
+ *
+ * This is similar to the zip() function in Python. See {@link
+ * http://docs.python.org/library/functions.html#zip}
+ *
+ * @param {...!IArrayLike<?>} var_args Arrays to be combined.
+ * @return {!Array<!Array<?>>} A new array of arrays created from
+ * provided arrays.
+ */
+goog.array.zip = function(var_args) {
+ if (!arguments.length) {
+ return [];
+ }
+ var result = [];
+ var minLen = arguments[0].length;
+ for (var i = 1; i < arguments.length; i++) {
+ if (arguments[i].length < minLen) {
+ minLen = arguments[i].length;
+ }
+ }
+ for (var i = 0; i < minLen; i++) {
+ var value = [];
+ for (var j = 0; j < arguments.length; j++) {
+ value.push(arguments[j][i]);
+ }
+ result.push(value);
+ }
+ return result;
+};
+
+
+/**
+ * Shuffles the values in the specified array using the Fisher-Yates in-place
+ * shuffle (also known as the Knuth Shuffle). By default, calls Math.random()
+ * and so resets the state of that random number generator. Similarly, may reset
+ * the state of the any other specified random number generator.
+ *
+ * Runtime: O(n)
+ *
+ * @param {!Array<?>} arr The array to be shuffled.
+ * @param {function():number=} opt_randFn Optional random function to use for
+ * shuffling.
+ * Takes no arguments, and returns a random number on the interval [0, 1).
+ * Defaults to Math.random() using JavaScript's built-in Math library.
+ */
+goog.array.shuffle = function(arr, opt_randFn) {
+ var randFn = opt_randFn || Math.random;
+
+ for (var i = arr.length - 1; i > 0; i--) {
+ // Choose a random array index in [0, i] (inclusive with i).
+ var j = Math.floor(randFn() * (i + 1));
+
+ var tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
+};
+
+
+/**
+ * Returns a new array of elements from arr, based on the indexes of elements
+ * provided by index_arr. For example, the result of index copying
+ * ['a', 'b', 'c'] with index_arr [1,0,0,2] is ['b', 'a', 'a', 'c'].
+ *
+ * @param {!Array<T>} arr The array to get a indexed copy from.
+ * @param {!Array<number>} index_arr An array of indexes to get from arr.
+ * @return {!Array<T>} A new array of elements from arr in index_arr order.
+ * @template T
+ */
+goog.array.copyByIndex = function(arr, index_arr) {
+ var result = [];
+ goog.array.forEach(index_arr, function(index) { result.push(arr[index]); });
+ return result;
+};
+
+
+/**
+ * Maps each element of the input array into zero or more elements of the output
+ * array.
+ *
+ * @param {!IArrayLike<VALUE>|string} arr Array or array like object
+ * over which to iterate.
+ * @param {function(this:THIS, VALUE, number, ?): !Array<RESULT>} f The function
+ * to call for every element. This function takes 3 arguments (the element,
+ * the index and the array) and should return an array. The result will be
+ * used to extend a new array.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within f.
+ * @return {!Array<RESULT>} a new array with the concatenation of all arrays
+ * returned from f.
+ * @template THIS, VALUE, RESULT
+ */
+goog.array.concatMap = function(arr, f, opt_obj) {
+ return goog.array.concat.apply([], goog.array.map(arr, f, opt_obj));
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Additional mathematical functions.
+ */
+
+goog.provide('goog.math');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+
+
+/**
+ * Returns a random integer greater than or equal to 0 and less than {@code a}.
+ * @param {number} a The upper bound for the random integer (exclusive).
+ * @return {number} A random integer N such that 0 <= N < a.
+ */
+goog.math.randomInt = function(a) {
+ return Math.floor(Math.random() * a);
+};
+
+
+/**
+ * Returns a random number greater than or equal to {@code a} and less than
+ * {@code b}.
+ * @param {number} a The lower bound for the random number (inclusive).
+ * @param {number} b The upper bound for the random number (exclusive).
+ * @return {number} A random number N such that a <= N < b.
+ */
+goog.math.uniformRandom = function(a, b) {
+ return a + Math.random() * (b - a);
+};
+
+
+/**
+ * Takes a number and clamps it to within the provided bounds.
+ * @param {number} value The input number.
+ * @param {number} min The minimum value to return.
+ * @param {number} max The maximum value to return.
+ * @return {number} The input number if it is within bounds, or the nearest
+ * number within the bounds.
+ */
+goog.math.clamp = function(value, min, max) {
+ return Math.min(Math.max(value, min), max);
+};
+
+
+/**
+ * The % operator in JavaScript returns the remainder of a / b, but differs from
+ * some other languages in that the result will have the same sign as the
+ * dividend. For example, -1 % 8 == -1, whereas in some other languages
+ * (such as Python) the result would be 7. This function emulates the more
+ * correct modulo behavior, which is useful for certain applications such as
+ * calculating an offset index in a circular list.
+ *
+ * @param {number} a The dividend.
+ * @param {number} b The divisor.
+ * @return {number} a % b where the result is between 0 and b (either 0 <= x < b
+ * or b < x <= 0, depending on the sign of b).
+ */
+goog.math.modulo = function(a, b) {
+ var r = a % b;
+ // If r and b differ in sign, add b to wrap the result to the correct sign.
+ return (r * b < 0) ? r + b : r;
+};
+
+
+/**
+ * Performs linear interpolation between values a and b. Returns the value
+ * between a and b proportional to x (when x is between 0 and 1. When x is
+ * outside this range, the return value is a linear extrapolation).
+ * @param {number} a A number.
+ * @param {number} b A number.
+ * @param {number} x The proportion between a and b.
+ * @return {number} The interpolated value between a and b.
+ */
+goog.math.lerp = function(a, b, x) {
+ return a + x * (b - a);
+};
+
+
+/**
+ * Tests whether the two values are equal to each other, within a certain
+ * tolerance to adjust for floating point errors.
+ * @param {number} a A number.
+ * @param {number} b A number.
+ * @param {number=} opt_tolerance Optional tolerance range. Defaults
+ * to 0.000001. If specified, should be greater than 0.
+ * @return {boolean} Whether {@code a} and {@code b} are nearly equal.
+ */
+goog.math.nearlyEquals = function(a, b, opt_tolerance) {
+ return Math.abs(a - b) <= (opt_tolerance || 0.000001);
+};
+
+
+// TODO(user): Rename to normalizeAngle, retaining old name as deprecated
+// alias.
+/**
+ * Normalizes an angle to be in range [0-360). Angles outside this range will
+ * be normalized to be the equivalent angle with that range.
+ * @param {number} angle Angle in degrees.
+ * @return {number} Standardized angle.
+ */
+goog.math.standardAngle = function(angle) {
+ return goog.math.modulo(angle, 360);
+};
+
+
+/**
+ * Normalizes an angle to be in range [0-2*PI). Angles outside this range will
+ * be normalized to be the equivalent angle with that range.
+ * @param {number} angle Angle in radians.
+ * @return {number} Standardized angle.
+ */
+goog.math.standardAngleInRadians = function(angle) {
+ return goog.math.modulo(angle, 2 * Math.PI);
+};
+
+
+/**
+ * Converts degrees to radians.
+ * @param {number} angleDegrees Angle in degrees.
+ * @return {number} Angle in radians.
+ */
+goog.math.toRadians = function(angleDegrees) {
+ return angleDegrees * Math.PI / 180;
+};
+
+
+/**
+ * Converts radians to degrees.
+ * @param {number} angleRadians Angle in radians.
+ * @return {number} Angle in degrees.
+ */
+goog.math.toDegrees = function(angleRadians) {
+ return angleRadians * 180 / Math.PI;
+};
+
+
+/**
+ * For a given angle and radius, finds the X portion of the offset.
+ * @param {number} degrees Angle in degrees (zero points in +X direction).
+ * @param {number} radius Radius.
+ * @return {number} The x-distance for the angle and radius.
+ */
+goog.math.angleDx = function(degrees, radius) {
+ return radius * Math.cos(goog.math.toRadians(degrees));
+};
+
+
+/**
+ * For a given angle and radius, finds the Y portion of the offset.
+ * @param {number} degrees Angle in degrees (zero points in +X direction).
+ * @param {number} radius Radius.
+ * @return {number} The y-distance for the angle and radius.
+ */
+goog.math.angleDy = function(degrees, radius) {
+ return radius * Math.sin(goog.math.toRadians(degrees));
+};
+
+
+/**
+ * Computes the angle between two points (x1,y1) and (x2,y2).
+ * Angle zero points in the +X direction, 90 degrees points in the +Y
+ * direction (down) and from there we grow clockwise towards 360 degrees.
+ * @param {number} x1 x of first point.
+ * @param {number} y1 y of first point.
+ * @param {number} x2 x of second point.
+ * @param {number} y2 y of second point.
+ * @return {number} Standardized angle in degrees of the vector from
+ * x1,y1 to x2,y2.
+ */
+goog.math.angle = function(x1, y1, x2, y2) {
+ return goog.math.standardAngle(
+ goog.math.toDegrees(Math.atan2(y2 - y1, x2 - x1)));
+};
+
+
+/**
+ * Computes the difference between startAngle and endAngle (angles in degrees).
+ * @param {number} startAngle Start angle in degrees.
+ * @param {number} endAngle End angle in degrees.
+ * @return {number} The number of degrees that when added to
+ * startAngle will result in endAngle. Positive numbers mean that the
+ * direction is clockwise. Negative numbers indicate a counter-clockwise
+ * direction.
+ * The shortest route (clockwise vs counter-clockwise) between the angles
+ * is used.
+ * When the difference is 180 degrees, the function returns 180 (not -180)
+ * angleDifference(30, 40) is 10, and angleDifference(40, 30) is -10.
+ * angleDifference(350, 10) is 20, and angleDifference(10, 350) is -20.
+ */
+goog.math.angleDifference = function(startAngle, endAngle) {
+ var d =
+ goog.math.standardAngle(endAngle) - goog.math.standardAngle(startAngle);
+ if (d > 180) {
+ d = d - 360;
+ } else if (d <= -180) {
+ d = 360 + d;
+ }
+ return d;
+};
+
+
+/**
+ * Returns the sign of a number as per the "sign" or "signum" function.
+ * @param {number} x The number to take the sign of.
+ * @return {number} -1 when negative, 1 when positive, 0 when 0. Preserves
+ * signed zeros and NaN.
+ */
+goog.math.sign = Math.sign || function(x) {
+ if (x > 0) {
+ return 1;
+ }
+ if (x < 0) {
+ return -1;
+ }
+ return x; // Preserves signed zeros and NaN.
+};
+
+
+/**
+ * JavaScript implementation of Longest Common Subsequence problem.
+ * http://en.wikipedia.org/wiki/Longest_common_subsequence
+ *
+ * Returns the longest possible array that is subarray of both of given arrays.
+ *
+ * @param {IArrayLike<S>} array1 First array of objects.
+ * @param {IArrayLike<T>} array2 Second array of objects.
+ * @param {Function=} opt_compareFn Function that acts as a custom comparator
+ * for the array ojects. Function should return true if objects are equal,
+ * otherwise false.
+ * @param {Function=} opt_collectorFn Function used to decide what to return
+ * as a result subsequence. It accepts 2 arguments: index of common element
+ * in the first array and index in the second. The default function returns
+ * element from the first array.
+ * @return {!Array<S|T>} A list of objects that are common to both arrays
+ * such that there is no common subsequence with size greater than the
+ * length of the list.
+ * @template S,T
+ */
+goog.math.longestCommonSubsequence = function(
+ array1, array2, opt_compareFn, opt_collectorFn) {
+
+ var compare = opt_compareFn || function(a, b) { return a == b; };
+
+ var collect = opt_collectorFn || function(i1, i2) { return array1[i1]; };
+
+ var length1 = array1.length;
+ var length2 = array2.length;
+
+ var arr = [];
+ for (var i = 0; i < length1 + 1; i++) {
+ arr[i] = [];
+ arr[i][0] = 0;
+ }
+
+ for (var j = 0; j < length2 + 1; j++) {
+ arr[0][j] = 0;
+ }
+
+ for (i = 1; i <= length1; i++) {
+ for (j = 1; j <= length2; j++) {
+ if (compare(array1[i - 1], array2[j - 1])) {
+ arr[i][j] = arr[i - 1][j - 1] + 1;
+ } else {
+ arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]);
+ }
+ }
+ }
+
+ // Backtracking
+ var result = [];
+ var i = length1, j = length2;
+ while (i > 0 && j > 0) {
+ if (compare(array1[i - 1], array2[j - 1])) {
+ result.unshift(collect(i - 1, j - 1));
+ i--;
+ j--;
+ } else {
+ if (arr[i - 1][j] > arr[i][j - 1]) {
+ i--;
+ } else {
+ j--;
+ }
+ }
+ }
+
+ return result;
+};
+
+
+/**
+ * Returns the sum of the arguments.
+ * @param {...number} var_args Numbers to add.
+ * @return {number} The sum of the arguments (0 if no arguments were provided,
+ * {@code NaN} if any of the arguments is not a valid number).
+ */
+goog.math.sum = function(var_args) {
+ return /** @type {number} */ (
+ goog.array.reduce(
+ arguments, function(sum, value) { return sum + value; }, 0));
+};
+
+
+/**
+ * Returns the arithmetic mean of the arguments.
+ * @param {...number} var_args Numbers to average.
+ * @return {number} The average of the arguments ({@code NaN} if no arguments
+ * were provided or any of the arguments is not a valid number).
+ */
+goog.math.average = function(var_args) {
+ return goog.math.sum.apply(null, arguments) / arguments.length;
+};
+
+
+/**
+ * Returns the unbiased sample variance of the arguments. For a definition,
+ * see e.g. http://en.wikipedia.org/wiki/Variance
+ * @param {...number} var_args Number samples to analyze.
+ * @return {number} The unbiased sample variance of the arguments (0 if fewer
+ * than two samples were provided, or {@code NaN} if any of the samples is
+ * not a valid number).
+ */
+goog.math.sampleVariance = function(var_args) {
+ var sampleSize = arguments.length;
+ if (sampleSize < 2) {
+ return 0;
+ }
+
+ var mean = goog.math.average.apply(null, arguments);
+ var variance =
+ goog.math.sum.apply(null, goog.array.map(arguments, function(val) {
+ return Math.pow(val - mean, 2);
+ })) / (sampleSize - 1);
+
+ return variance;
+};
+
+
+/**
+ * Returns the sample standard deviation of the arguments. For a definition of
+ * sample standard deviation, see e.g.
+ * http://en.wikipedia.org/wiki/Standard_deviation
+ * @param {...number} var_args Number samples to analyze.
+ * @return {number} The sample standard deviation of the arguments (0 if fewer
+ * than two samples were provided, or {@code NaN} if any of the samples is
+ * not a valid number).
+ */
+goog.math.standardDeviation = function(var_args) {
+ return Math.sqrt(goog.math.sampleVariance.apply(null, arguments));
+};
+
+
+/**
+ * Returns whether the supplied number represents an integer, i.e. that is has
+ * no fractional component. No range-checking is performed on the number.
+ * @param {number} num The number to test.
+ * @return {boolean} Whether {@code num} is an integer.
+ */
+goog.math.isInt = function(num) {
+ return isFinite(num) && num % 1 == 0;
+};
+
+
+/**
+ * Returns whether the supplied number is finite and not NaN.
+ * @param {number} num The number to test.
+ * @return {boolean} Whether {@code num} is a finite number.
+ */
+goog.math.isFiniteNumber = function(num) {
+ return isFinite(num) && !isNaN(num);
+};
+
+
+/**
+ * @param {number} num The number to test.
+ * @return {boolean} Whether it is negative zero.
+ */
+goog.math.isNegativeZero = function(num) {
+ return num == 0 && 1 / num < 0;
+};
+
+
+/**
+ * Returns the precise value of floor(log10(num)).
+ * Simpler implementations didn't work because of floating point rounding
+ * errors. For example
+ * <ul>
+ * <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3.
+ * <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15.
+ * <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1.
+ * </ul>
+ * @param {number} num A floating point number.
+ * @return {number} Its logarithm to base 10 rounded down to the nearest
+ * integer if num > 0. -Infinity if num == 0. NaN if num < 0.
+ */
+goog.math.log10Floor = function(num) {
+ if (num > 0) {
+ var x = Math.round(Math.log(num) * Math.LOG10E);
+ return x - (parseFloat('1e' + x) > num ? 1 : 0);
+ }
+ return num == 0 ? -Infinity : NaN;
+};
+
+
+/**
+ * A tweaked variant of {@code Math.floor} which tolerates if the passed number
+ * is infinitesimally smaller than the closest integer. It often happens with
+ * the results of floating point calculations because of the finite precision
+ * of the intermediate results. For example {@code Math.floor(Math.log(1000) /
+ * Math.LN10) == 2}, not 3 as one would expect.
+ * @param {number} num A number.
+ * @param {number=} opt_epsilon An infinitesimally small positive number, the
+ * rounding error to tolerate.
+ * @return {number} The largest integer less than or equal to {@code num}.
+ */
+goog.math.safeFloor = function(num, opt_epsilon) {
+ goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0);
+ return Math.floor(num + (opt_epsilon || 2e-15));
+};
+
+
+/**
+ * A tweaked variant of {@code Math.ceil}. See {@code goog.math.safeFloor} for
+ * details.
+ * @param {number} num A number.
+ * @param {number=} opt_epsilon An infinitesimally small positive number, the
+ * rounding error to tolerate.
+ * @return {number} The smallest integer greater than or equal to {@code num}.
+ */
+goog.math.safeCeil = function(num, opt_epsilon) {
+ goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0);
+ return Math.ceil(num - (opt_epsilon || 2e-15));
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities related to color and color conversion.
+ */
+
+goog.provide('goog.color');
+goog.provide('goog.color.Hsl');
+goog.provide('goog.color.Hsv');
+goog.provide('goog.color.Rgb');
+
+goog.require('goog.color.names');
+goog.require('goog.math');
+
+
+/**
+ * RGB color representation. An array containing three elements [r, g, b],
+ * each an integer in [0, 255], representing the red, green, and blue components
+ * of the color respectively.
+ * @typedef {Array<number>}
+ */
+goog.color.Rgb;
+
+
+/**
+ * HSV color representation. An array containing three elements [h, s, v]:
+ * h (hue) must be an integer in [0, 360], cyclic.
+ * s (saturation) must be a number in [0, 1].
+ * v (value/brightness) must be an integer in [0, 255].
+ * @typedef {Array<number>}
+ */
+goog.color.Hsv;
+
+
+/**
+ * HSL color representation. An array containing three elements [h, s, l]:
+ * h (hue) must be an integer in [0, 360], cyclic.
+ * s (saturation) must be a number in [0, 1].
+ * l (lightness) must be a number in [0, 1].
+ * @typedef {Array<number>}
+ */
+goog.color.Hsl;
+
+
+/**
+ * Parses a color out of a string.
+ * @param {string} str Color in some format.
+ * @return {{hex: string, type: string}} 'hex' is a string containing a hex
+ * representation of the color, 'type' is a string containing the type
+ * of color format passed in ('hex', 'rgb', 'named').
+ */
+goog.color.parse = function(str) {
+ var result = {};
+ str = String(str);
+
+ var maybeHex = goog.color.prependHashIfNecessaryHelper(str);
+ if (goog.color.isValidHexColor_(maybeHex)) {
+ result.hex = goog.color.normalizeHex(maybeHex);
+ result.type = 'hex';
+ return result;
+ } else {
+ var rgb = goog.color.isValidRgbColor_(str);
+ if (rgb.length) {
+ result.hex = goog.color.rgbArrayToHex(rgb);
+ result.type = 'rgb';
+ return result;
+ } else if (goog.color.names) {
+ var hex = goog.color.names[str.toLowerCase()];
+ if (hex) {
+ result.hex = hex;
+ result.type = 'named';
+ return result;
+ }
+ }
+ }
+ throw Error(str + ' is not a valid color string');
+};
+
+
+/**
+ * Determines if the given string can be parsed as a color.
+ * {@see goog.color.parse}.
+ * @param {string} str Potential color string.
+ * @return {boolean} True if str is in a format that can be parsed to a color.
+ */
+goog.color.isValidColor = function(str) {
+ var maybeHex = goog.color.prependHashIfNecessaryHelper(str);
+ return !!(
+ goog.color.isValidHexColor_(maybeHex) ||
+ goog.color.isValidRgbColor_(str).length ||
+ goog.color.names && goog.color.names[str.toLowerCase()]);
+};
+
+
+/**
+ * Parses red, green, blue components out of a valid rgb color string.
+ * Throws Error if the color string is invalid.
+ * @param {string} str RGB representation of a color.
+ * {@see goog.color.isValidRgbColor_}.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.parseRgb = function(str) {
+ var rgb = goog.color.isValidRgbColor_(str);
+ if (!rgb.length) {
+ throw Error(str + ' is not a valid RGB color');
+ }
+ return rgb;
+};
+
+
+/**
+ * Converts a hex representation of a color to RGB.
+ * @param {string} hexColor Color to convert.
+ * @return {string} string of the form 'rgb(R,G,B)' which can be used in
+ * styles.
+ */
+goog.color.hexToRgbStyle = function(hexColor) {
+ return goog.color.rgbStyle_(goog.color.hexToRgb(hexColor));
+};
+
+
+/**
+ * Regular expression for extracting the digits in a hex color triplet.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.hexTripletRe_ = /#(.)(.)(.)/;
+
+
+/**
+ * Normalize an hex representation of a color
+ * @param {string} hexColor an hex color string.
+ * @return {string} hex color in the format '#rrggbb' with all lowercase
+ * literals.
+ */
+goog.color.normalizeHex = function(hexColor) {
+ if (!goog.color.isValidHexColor_(hexColor)) {
+ throw Error("'" + hexColor + "' is not a valid hex color");
+ }
+ if (hexColor.length == 4) { // of the form #RGB
+ hexColor = hexColor.replace(goog.color.hexTripletRe_, '#$1$1$2$2$3$3');
+ }
+ return hexColor.toLowerCase();
+};
+
+
+/**
+ * Converts a hex representation of a color to RGB.
+ * @param {string} hexColor Color to convert.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hexToRgb = function(hexColor) {
+ hexColor = goog.color.normalizeHex(hexColor);
+ var r = parseInt(hexColor.substr(1, 2), 16);
+ var g = parseInt(hexColor.substr(3, 2), 16);
+ var b = parseInt(hexColor.substr(5, 2), 16);
+
+ return [r, g, b];
+};
+
+
+/**
+ * Converts a color from RGB to hex representation.
+ * @param {number} r Amount of red, int between 0 and 255.
+ * @param {number} g Amount of green, int between 0 and 255.
+ * @param {number} b Amount of blue, int between 0 and 255.
+ * @return {string} hex representation of the color.
+ */
+goog.color.rgbToHex = function(r, g, b) {
+ r = Number(r);
+ g = Number(g);
+ b = Number(b);
+ if (r != (r & 255) || g != (g & 255) || b != (b & 255)) {
+ throw Error('"(' + r + ',' + g + ',' + b + '") is not a valid RGB color');
+ }
+ var hexR = goog.color.prependZeroIfNecessaryHelper(r.toString(16));
+ var hexG = goog.color.prependZeroIfNecessaryHelper(g.toString(16));
+ var hexB = goog.color.prependZeroIfNecessaryHelper(b.toString(16));
+ return '#' + hexR + hexG + hexB;
+};
+
+
+/**
+ * Converts a color from RGB to hex representation.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {string} hex representation of the color.
+ */
+goog.color.rgbArrayToHex = function(rgb) {
+ return goog.color.rgbToHex(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Converts a color from RGB color space to HSL color space.
+ * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}.
+ * @param {number} r Value of red, in [0, 255].
+ * @param {number} g Value of green, in [0, 255].
+ * @param {number} b Value of blue, in [0, 255].
+ * @return {!goog.color.Hsl} hsl representation of the color.
+ */
+goog.color.rgbToHsl = function(r, g, b) {
+ // First must normalize r, g, b to be between 0 and 1.
+ var normR = r / 255;
+ var normG = g / 255;
+ var normB = b / 255;
+ var max = Math.max(normR, normG, normB);
+ var min = Math.min(normR, normG, normB);
+ var h = 0;
+ var s = 0;
+
+ // Luminosity is the average of the max and min rgb color intensities.
+ var l = 0.5 * (max + min);
+
+ // The hue and saturation are dependent on which color intensity is the max.
+ // If max and min are equal, the color is gray and h and s should be 0.
+ if (max != min) {
+ if (max == normR) {
+ h = 60 * (normG - normB) / (max - min);
+ } else if (max == normG) {
+ h = 60 * (normB - normR) / (max - min) + 120;
+ } else if (max == normB) {
+ h = 60 * (normR - normG) / (max - min) + 240;
+ }
+
+ if (0 < l && l <= 0.5) {
+ s = (max - min) / (2 * l);
+ } else {
+ s = (max - min) / (2 - 2 * l);
+ }
+ }
+
+ // Make sure the hue falls between 0 and 360.
+ return [Math.round(h + 360) % 360, s, l];
+};
+
+
+/**
+ * Converts a color from RGB color space to HSL color space.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {!goog.color.Hsl} hsl representation of the color.
+ */
+goog.color.rgbArrayToHsl = function(rgb) {
+ return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Helper for hslToRgb.
+ * @param {number} v1 Helper variable 1.
+ * @param {number} v2 Helper variable 2.
+ * @param {number} vH Helper variable 3.
+ * @return {number} Appropriate RGB value, given the above.
+ * @private
+ */
+goog.color.hueToRgb_ = function(v1, v2, vH) {
+ if (vH < 0) {
+ vH += 1;
+ } else if (vH > 1) {
+ vH -= 1;
+ }
+ if ((6 * vH) < 1) {
+ return (v1 + (v2 - v1) * 6 * vH);
+ } else if (2 * vH < 1) {
+ return v2;
+ } else if (3 * vH < 2) {
+ return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6);
+ }
+ return v1;
+};
+
+
+/**
+ * Converts a color from HSL color space to RGB color space.
+ * Modified from {@link http://www.easyrgb.com/math.html}
+ * @param {number} h Hue, in [0, 360].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} l Luminosity, in [0, 1].
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hslToRgb = function(h, s, l) {
+ var r = 0;
+ var g = 0;
+ var b = 0;
+ var normH = h / 360; // normalize h to fall in [0, 1]
+
+ if (s == 0) {
+ r = g = b = l * 255;
+ } else {
+ var temp1 = 0;
+ var temp2 = 0;
+ if (l < 0.5) {
+ temp2 = l * (1 + s);
+ } else {
+ temp2 = l + s - (s * l);
+ }
+ temp1 = 2 * l - temp2;
+ r = 255 * goog.color.hueToRgb_(temp1, temp2, normH + (1 / 3));
+ g = 255 * goog.color.hueToRgb_(temp1, temp2, normH);
+ b = 255 * goog.color.hueToRgb_(temp1, temp2, normH - (1 / 3));
+ }
+
+ return [Math.round(r), Math.round(g), Math.round(b)];
+};
+
+
+/**
+ * Converts a color from HSL color space to RGB color space.
+ * @param {goog.color.Hsl} hsl hsl representation of the color.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hslArrayToRgb = function(hsl) {
+ return goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]);
+};
+
+
+/**
+ * Helper for isValidHexColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.validHexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i;
+
+
+/**
+ * Checks if a string is a valid hex color. We expect strings of the format
+ * #RRGGBB (ex: #1b3d5f) or #RGB (ex: #3CA == #33CCAA).
+ * @param {string} str String to check.
+ * @return {boolean} Whether the string is a valid hex color.
+ * @private
+ */
+goog.color.isValidHexColor_ = function(str) {
+ return goog.color.validHexColorRe_.test(str);
+};
+
+
+/**
+ * Helper for isNormalizedHexColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.normalizedHexColorRe_ = /^#[0-9a-f]{6}$/;
+
+
+/**
+ * Checks if a string is a normalized hex color.
+ * We expect strings of the format #RRGGBB (ex: #1b3d5f)
+ * using only lowercase letters.
+ * @param {string} str String to check.
+ * @return {boolean} Whether the string is a normalized hex color.
+ * @private
+ */
+goog.color.isNormalizedHexColor_ = function(str) {
+ return goog.color.normalizedHexColorRe_.test(str);
+};
+
+
+/**
+ * Regular expression for matching and capturing RGB style strings. Helper for
+ * isValidRgbColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.rgbColorRe_ =
+ /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;
+
+
+/**
+ * Checks if a string is a valid rgb color. We expect strings of the format
+ * '(r, g, b)', or 'rgb(r, g, b)', where each color component is an int in
+ * [0, 255].
+ * @param {string} str String to check.
+ * @return {!goog.color.Rgb} the rgb representation of the color if it is
+ * a valid color, or the empty array otherwise.
+ * @private
+ */
+goog.color.isValidRgbColor_ = function(str) {
+ // Each component is separate (rather than using a repeater) so we can
+ // capture the match. Also, we explicitly set each component to be either 0,
+ // or start with a non-zero, to prevent octal numbers from slipping through.
+ var regExpResultArray = str.match(goog.color.rgbColorRe_);
+ if (regExpResultArray) {
+ var r = Number(regExpResultArray[1]);
+ var g = Number(regExpResultArray[2]);
+ var b = Number(regExpResultArray[3]);
+ if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
+ return [r, g, b];
+ }
+ }
+ return [];
+};
+
+
+/**
+ * Takes a hex value and prepends a zero if it's a single digit.
+ * Small helper method for use by goog.color and friends.
+ * @param {string} hex Hex value to prepend if single digit.
+ * @return {string} hex value prepended with zero if it was single digit,
+ * otherwise the same value that was passed in.
+ */
+goog.color.prependZeroIfNecessaryHelper = function(hex) {
+ return hex.length == 1 ? '0' + hex : hex;
+};
+
+
+/**
+ * Takes a string a prepends a '#' sign if one doesn't exist.
+ * Small helper method for use by goog.color and friends.
+ * @param {string} str String to check.
+ * @return {string} The value passed in, prepended with a '#' if it didn't
+ * already have one.
+ */
+goog.color.prependHashIfNecessaryHelper = function(str) {
+ return str.charAt(0) == '#' ? str : '#' + str;
+};
+
+
+/**
+ * Takes an array of [r, g, b] and converts it into a string appropriate for
+ * CSS styles.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {string} string of the form 'rgb(r,g,b)'.
+ * @private
+ */
+goog.color.rgbStyle_ = function(rgb) {
+ return 'rgb(' + rgb.join(',') + ')';
+};
+
+
+/**
+ * Converts an HSV triplet to an RGB array. V is brightness because b is
+ * reserved for blue in RGB.
+ * @param {number} h Hue value in [0, 360].
+ * @param {number} s Saturation value in [0, 1].
+ * @param {number} brightness brightness in [0, 255].
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hsvToRgb = function(h, s, brightness) {
+ var red = 0;
+ var green = 0;
+ var blue = 0;
+ if (s == 0) {
+ red = brightness;
+ green = brightness;
+ blue = brightness;
+ } else {
+ var sextant = Math.floor(h / 60);
+ var remainder = (h / 60) - sextant;
+ var val1 = brightness * (1 - s);
+ var val2 = brightness * (1 - (s * remainder));
+ var val3 = brightness * (1 - (s * (1 - remainder)));
+ switch (sextant) {
+ case 1:
+ red = val2;
+ green = brightness;
+ blue = val1;
+ break;
+ case 2:
+ red = val1;
+ green = brightness;
+ blue = val3;
+ break;
+ case 3:
+ red = val1;
+ green = val2;
+ blue = brightness;
+ break;
+ case 4:
+ red = val3;
+ green = val1;
+ blue = brightness;
+ break;
+ case 5:
+ red = brightness;
+ green = val1;
+ blue = val2;
+ break;
+ case 6:
+ case 0:
+ red = brightness;
+ green = val3;
+ blue = val1;
+ break;
+ }
+ }
+
+ return [Math.floor(red), Math.floor(green), Math.floor(blue)];
+};
+
+
+/**
+ * Converts from RGB values to an array of HSV values.
+ * @param {number} red Red value in [0, 255].
+ * @param {number} green Green value in [0, 255].
+ * @param {number} blue Blue value in [0, 255].
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.rgbToHsv = function(red, green, blue) {
+
+ var max = Math.max(Math.max(red, green), blue);
+ var min = Math.min(Math.min(red, green), blue);
+ var hue;
+ var saturation;
+ var value = max;
+ if (min == max) {
+ hue = 0;
+ saturation = 0;
+ } else {
+ var delta = (max - min);
+ saturation = delta / max;
+
+ if (red == max) {
+ hue = (green - blue) / delta;
+ } else if (green == max) {
+ hue = 2 + ((blue - red) / delta);
+ } else {
+ hue = 4 + ((red - green) / delta);
+ }
+ hue *= 60;
+ if (hue < 0) {
+ hue += 360;
+ }
+ if (hue > 360) {
+ hue -= 360;
+ }
+ }
+
+ return [hue, saturation, value];
+};
+
+
+/**
+ * Converts from an array of RGB values to an array of HSV values.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.rgbArrayToHsv = function(rgb) {
+ return goog.color.rgbToHsv(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Converts an HSV triplet to an RGB array.
+ * @param {goog.color.Hsv} hsv hsv representation of the color.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hsvArrayToRgb = function(hsv) {
+ return goog.color.hsvToRgb(hsv[0], hsv[1], hsv[2]);
+};
+
+
+/**
+ * Converts a hex representation of a color to HSL.
+ * @param {string} hex Color to convert.
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.hexToHsl = function(hex) {
+ var rgb = goog.color.hexToRgb(hex);
+ return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Converts from h,s,l values to a hex string
+ * @param {number} h Hue, in [0, 360].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} l Luminosity, in [0, 1].
+ * @return {string} hex representation of the color.
+ */
+goog.color.hslToHex = function(h, s, l) {
+ return goog.color.rgbArrayToHex(goog.color.hslToRgb(h, s, l));
+};
+
+
+/**
+ * Converts from an hsl array to a hex string
+ * @param {goog.color.Hsl} hsl hsl representation of the color.
+ * @return {string} hex representation of the color.
+ */
+goog.color.hslArrayToHex = function(hsl) {
+ return goog.color.rgbArrayToHex(goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]));
+};
+
+
+/**
+ * Converts a hex representation of a color to HSV
+ * @param {string} hex Color to convert.
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.hexToHsv = function(hex) {
+ return goog.color.rgbArrayToHsv(goog.color.hexToRgb(hex));
+};
+
+
+/**
+ * Converts from h,s,v values to a hex string
+ * @param {number} h Hue, in [0, 360].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} v Value, in [0, 255].
+ * @return {string} hex representation of the color.
+ */
+goog.color.hsvToHex = function(h, s, v) {
+ return goog.color.rgbArrayToHex(goog.color.hsvToRgb(h, s, v));
+};
+
+
+/**
+ * Converts from an HSV array to a hex string
+ * @param {goog.color.Hsv} hsv hsv representation of the color.
+ * @return {string} hex representation of the color.
+ */
+goog.color.hsvArrayToHex = function(hsv) {
+ return goog.color.hsvToHex(hsv[0], hsv[1], hsv[2]);
+};
+
+
+/**
+ * Calculates the Euclidean distance between two color vectors on an HSL sphere.
+ * A demo of the sphere can be found at:
+ * http://en.wikipedia.org/wiki/HSL_color_space
+ * In short, a vector for color (H, S, L) in this system can be expressed as
+ * (S*L'*cos(2*PI*H), S*L'*sin(2*PI*H), L), where L' = abs(L - 0.5), and we
+ * simply calculate the 1-2 distance using these coordinates
+ * @param {goog.color.Hsl} hsl1 First color in hsl representation.
+ * @param {goog.color.Hsl} hsl2 Second color in hsl representation.
+ * @return {number} Distance between the two colors, in the range [0, 1].
+ */
+goog.color.hslDistance = function(hsl1, hsl2) {
+ var sl1, sl2;
+ if (hsl1[2] <= 0.5) {
+ sl1 = hsl1[1] * hsl1[2];
+ } else {
+ sl1 = hsl1[1] * (1.0 - hsl1[2]);
+ }
+
+ if (hsl2[2] <= 0.5) {
+ sl2 = hsl2[1] * hsl2[2];
+ } else {
+ sl2 = hsl2[1] * (1.0 - hsl2[2]);
+ }
+
+ var h1 = hsl1[0] / 360.0;
+ var h2 = hsl2[0] / 360.0;
+ var dh = (h1 - h2) * 2.0 * Math.PI;
+ return (hsl1[2] - hsl2[2]) * (hsl1[2] - hsl2[2]) + sl1 * sl1 + sl2 * sl2 -
+ 2 * sl1 * sl2 * Math.cos(dh);
+};
+
+
+/**
+ * Blend two colors together, using the specified factor to indicate the weight
+ * given to the first color
+ * @param {goog.color.Rgb} rgb1 First color represented in rgb.
+ * @param {goog.color.Rgb} rgb2 Second color represented in rgb.
+ * @param {number} factor The weight to be given to rgb1 over rgb2. Values
+ * should be in the range [0, 1]. If less than 0, factor will be set to 0.
+ * If greater than 1, factor will be set to 1.
+ * @return {!goog.color.Rgb} Combined color represented in rgb.
+ */
+goog.color.blend = function(rgb1, rgb2, factor) {
+ factor = goog.math.clamp(factor, 0, 1);
+
+ return [
+ Math.round(factor * rgb1[0] + (1.0 - factor) * rgb2[0]),
+ Math.round(factor * rgb1[1] + (1.0 - factor) * rgb2[1]),
+ Math.round(factor * rgb1[2] + (1.0 - factor) * rgb2[2])
+ ];
+};
+
+
+/**
+ * Adds black to the specified color, darkening it
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while
+ * 1 will return black. If less than 0, factor will be set to 0. If greater
+ * than 1, factor will be set to 1.
+ * @return {!goog.color.Rgb} Combined rgb color.
+ */
+goog.color.darken = function(rgb, factor) {
+ var black = [0, 0, 0];
+ return goog.color.blend(black, rgb, factor);
+};
+
+
+/**
+ * Adds white to the specified color, lightening it
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while
+ * 1 will return white. If less than 0, factor will be set to 0. If greater
+ * than 1, factor will be set to 1.
+ * @return {!goog.color.Rgb} Combined rgb color.
+ */
+goog.color.lighten = function(rgb, factor) {
+ var white = [255, 255, 255];
+ return goog.color.blend(white, rgb, factor);
+};
+
+
+/**
+ * Find the "best" (highest-contrast) of the suggested colors for the prime
+ * color. Uses W3C formula for judging readability and visual accessibility:
+ * http://www.w3.org/TR/AERT#color-contrast
+ * @param {goog.color.Rgb} prime Color represented as a rgb array.
+ * @param {Array<goog.color.Rgb>} suggestions Array of colors,
+ * each representing a rgb array.
+ * @return {!goog.color.Rgb} Highest-contrast color represented by an array..
+ */
+goog.color.highContrast = function(prime, suggestions) {
+ var suggestionsWithDiff = [];
+ for (var i = 0; i < suggestions.length; i++) {
+ suggestionsWithDiff.push({
+ color: suggestions[i],
+ diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) +
+ goog.color.colorDiff_(suggestions[i], prime)
+ });
+ }
+ suggestionsWithDiff.sort(function(a, b) { return b.diff - a.diff; });
+ return suggestionsWithDiff[0].color;
+};
+
+
+/**
+ * Calculate brightness of a color according to YIQ formula (brightness is Y).
+ * More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for
+ * goog.color.highContrast()
+ * @param {goog.color.Rgb} rgb Color represented by a rgb array.
+ * @return {number} brightness (Y).
+ * @private
+ */
+goog.color.yiqBrightness_ = function(rgb) {
+ return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000);
+};
+
+
+/**
+ * Calculate difference in brightness of two colors. Helper method for
+ * goog.color.highContrast()
+ * @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
+ * @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
+ * @return {number} Brightness difference.
+ * @private
+ */
+goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) {
+ return Math.abs(
+ goog.color.yiqBrightness_(rgb1) - goog.color.yiqBrightness_(rgb2));
+};
+
+
+/**
+ * Calculate color difference between two colors. Helper method for
+ * goog.color.highContrast()
+ * @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
+ * @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
+ * @return {number} Color difference.
+ * @private
+ */
+goog.color.colorDiff_ = function(rgb1, rgb2) {
+ return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) +
+ Math.abs(rgb1[2] - rgb2[2]);
+};
+
+// We can't use goog.color or goog.color.alpha because they interally use a hex
+// string representation that encodes each channel in a single byte. This
+// causes occasional loss of precision and rounding errors, especially in the
+// alpha channel.
+
+goog.provide('ol.color');
+
+goog.require('goog.asserts');
+goog.require('goog.color');
+goog.require('goog.color.names');
+goog.require('ol');
+goog.require('ol.math');
+
+
+/**
+ * This RegExp matches # followed by 3 or 6 hex digits.
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.color.hexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i;
+
+
+/**
+ * @see goog.color.rgbColorRe_
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.color.rgbColorRe_ =
+ /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;
+
+
+/**
+ * @see goog.color.alpha.rgbaColorRe_
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.color.rgbaColorRe_ =
+ /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;
+
+
+/**
+ * Return the color as an array. This function maintains a cache of calculated
+ * arrays which means the result should not be modified.
+ * @param {ol.Color|string} color Color.
+ * @return {ol.Color} Color.
+ * @api
+ */
+ol.color.asArray = function(color) {
+ if (Array.isArray(color)) {
+ return color;
+ } else {
+ goog.asserts.assert(typeof color === 'string', 'Color should be a string');
+ return ol.color.fromString(color);
+ }
+};
+
+
+/**
+ * Return the color as an rgba string.
+ * @param {ol.Color|string} color Color.
+ * @return {string} Rgba string.
+ * @api
+ */
+ol.color.asString = function(color) {
+ if (typeof color === 'string') {
+ return color;
+ } else {
+ goog.asserts.assert(Array.isArray(color), 'Color should be an array');
+ return ol.color.toString(color);
+ }
+};
+
+
+/**
+ * @param {string} s String.
+ * @return {ol.Color} Color.
+ */
+ol.color.fromString = (
+ function() {
+
+ // We maintain a small cache of parsed strings. To provide cheap LRU-like
+ // semantics, whenever the cache grows too large we simply delete an
+ // arbitrary 25% of the entries.
+
+ /**
+ * @const
+ * @type {number}
+ */
+ var MAX_CACHE_SIZE = 1024;
+
+ /**
+ * @type {Object.<string, ol.Color>}
+ */
+ var cache = {};
+
+ /**
+ * @type {number}
+ */
+ var cacheSize = 0;
+
+ return (
+ /**
+ * @param {string} s String.
+ * @return {ol.Color} Color.
+ */
+ function(s) {
+ var color;
+ if (cache.hasOwnProperty(s)) {
+ color = cache[s];
+ } else {
+ if (cacheSize >= MAX_CACHE_SIZE) {
+ var i = 0;
+ var key;
+ for (key in cache) {
+ if ((i++ & 3) === 0) {
+ delete cache[key];
+ --cacheSize;
+ }
+ }
+ }
+ color = ol.color.fromStringInternal_(s);
+ cache[s] = color;
+ ++cacheSize;
+ }
+ return color;
+ });
+
+ })();
+
+
+/**
+ * @param {string} s String.
+ * @private
+ * @return {ol.Color} Color.
+ */
+ol.color.fromStringInternal_ = function(s) {
+
+ var isHex = false;
+ if (ol.ENABLE_NAMED_COLORS && goog.color.names.hasOwnProperty(s)) {
+ s = goog.color.names[s];
+ isHex = true;
+ }
+
+ var r, g, b, a, color, match;
+ if (isHex || (match = ol.color.hexColorRe_.exec(s))) { // hex
+ var n = s.length - 1; // number of hex digits
+ goog.asserts.assert(n == 3 || n == 6,
+ 'Color string length should be 3 or 6');
+ var d = n == 3 ? 1 : 2; // number of digits per channel
+ r = parseInt(s.substr(1 + 0 * d, d), 16);
+ g = parseInt(s.substr(1 + 1 * d, d), 16);
+ b = parseInt(s.substr(1 + 2 * d, d), 16);
+ if (d == 1) {
+ r = (r << 4) + r;
+ g = (g << 4) + g;
+ b = (b << 4) + b;
+ }
+ a = 1;
+ color = [r, g, b, a];
+ goog.asserts.assert(ol.color.isValid(color),
+ 'Color should be a valid color');
+ return color;
+ } else if ((match = ol.color.rgbaColorRe_.exec(s))) { // rgba()
+ r = Number(match[1]);
+ g = Number(match[2]);
+ b = Number(match[3]);
+ a = Number(match[4]);
+ color = [r, g, b, a];
+ return ol.color.normalize(color, color);
+ } else if ((match = ol.color.rgbColorRe_.exec(s))) { // rgb()
+ r = Number(match[1]);
+ g = Number(match[2]);
+ b = Number(match[3]);
+ color = [r, g, b, 1];
+ return ol.color.normalize(color, color);
+ } else {
+ goog.asserts.fail(s + ' is not a valid color');
+ }
+
+};
+
+
+/**
+ * @param {ol.Color} color Color.
+ * @return {boolean} Is valid.
+ */
+ol.color.isValid = function(color) {
+ return 0 <= color[0] && color[0] < 256 &&
+ 0 <= color[1] && color[1] < 256 &&
+ 0 <= color[2] && color[2] < 256 &&
+ 0 <= color[3] && color[3] <= 1;
+};
+
+
+/**
+ * @param {ol.Color} color Color.
+ * @param {ol.Color=} opt_color Color.
+ * @return {ol.Color} Clamped color.
+ */
+ol.color.normalize = function(color, opt_color) {
+ var result = opt_color || [];
+ result[0] = ol.math.clamp((color[0] + 0.5) | 0, 0, 255);
+ result[1] = ol.math.clamp((color[1] + 0.5) | 0, 0, 255);
+ result[2] = ol.math.clamp((color[2] + 0.5) | 0, 0, 255);
+ result[3] = ol.math.clamp(color[3], 0, 1);
+ return result;
+};
+
+
+/**
+ * @param {ol.Color} color Color.
+ * @return {string} String.
+ */
+ol.color.toString = function(color) {
+ var r = color[0];
+ if (r != (r | 0)) {
+ r = (r + 0.5) | 0;
+ }
+ var g = color[1];
+ if (g != (g | 0)) {
+ g = (g + 0.5) | 0;
+ }
+ var b = color[2];
+ if (b != (b | 0)) {
+ b = (b + 0.5) | 0;
+ }
+ var a = color[3] === undefined ? 1 : color[3];
+ return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+};
+
+goog.provide('ol.colorlike');
+
+goog.require('ol.color');
+
+
+/**
+ * @param {ol.Color|ol.ColorLike} color Color.
+ * @return {ol.ColorLike} The color as an ol.ColorLike
+ * @api
+ */
+ol.colorlike.asColorLike = function(color) {
+ if (ol.colorlike.isColorLike(color)) {
+ return /** @type {string|CanvasPattern|CanvasGradient} */ (color);
+ } else {
+ return ol.color.asString(/** @type {ol.Color} */ (color));
+ }
+};
+
+
+/**
+ * @param {?} color The value that is potentially an ol.ColorLike
+ * @return {boolean} Whether the color is an ol.ColorLike
+ */
+ol.colorlike.isColorLike = function(color) {
+ return (
+ typeof color === 'string' ||
+ color instanceof CanvasPattern ||
+ color instanceof CanvasGradient
+ );
+};
+
+// Copyright 2013 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities used by goog.labs.userAgent tools. These functions
+ * should not be used outside of goog.labs.userAgent.*.
+ *
+ *
+ * @author nnaze@google.com (Nathan Naze)
+ */
+
+goog.provide('goog.labs.userAgent.util');
+
+goog.require('goog.string');
+
+
+/**
+ * Gets the native userAgent string from navigator if it exists.
+ * If navigator or navigator.userAgent string is missing, returns an empty
+ * string.
+ * @return {string}
+ * @private
+ */
+goog.labs.userAgent.util.getNativeUserAgentString_ = function() {
+ var navigator = goog.labs.userAgent.util.getNavigator_();
+ if (navigator) {
+ var userAgent = navigator.userAgent;
+ if (userAgent) {
+ return userAgent;
+ }
+ }
+ return '';
+};
+
+
+/**
+ * Getter for the native navigator.
+ * This is a separate function so it can be stubbed out in testing.
+ * @return {Navigator}
+ * @private
+ */
+goog.labs.userAgent.util.getNavigator_ = function() {
+ return goog.global.navigator;
+};
+
+
+/**
+ * A possible override for applications which wish to not check
+ * navigator.userAgent but use a specified value for detection instead.
+ * @private {string}
+ */
+goog.labs.userAgent.util.userAgent_ =
+ goog.labs.userAgent.util.getNativeUserAgentString_();
+
+
+/**
+ * Applications may override browser detection on the built in
+ * navigator.userAgent object by setting this string. Set to null to use the
+ * browser object instead.
+ * @param {?string=} opt_userAgent The User-Agent override.
+ */
+goog.labs.userAgent.util.setUserAgent = function(opt_userAgent) {
+ goog.labs.userAgent.util.userAgent_ =
+ opt_userAgent || goog.labs.userAgent.util.getNativeUserAgentString_();
+};
+
+
+/**
+ * @return {string} The user agent string.
+ */
+goog.labs.userAgent.util.getUserAgent = function() {
+ return goog.labs.userAgent.util.userAgent_;
+};
+
+
+/**
+ * @param {string} str
+ * @return {boolean} Whether the user agent contains the given string, ignoring
+ * case.
+ */
+goog.labs.userAgent.util.matchUserAgent = function(str) {
+ var userAgent = goog.labs.userAgent.util.getUserAgent();
+ return goog.string.contains(userAgent, str);
+};
+
+
+/**
+ * @param {string} str
+ * @return {boolean} Whether the user agent contains the given string.
+ */
+goog.labs.userAgent.util.matchUserAgentIgnoreCase = function(str) {
+ var userAgent = goog.labs.userAgent.util.getUserAgent();
+ return goog.string.caseInsensitiveContains(userAgent, str);
+};
+
+
+/**
+ * Parses the user agent into tuples for each section.
+ * @param {string} userAgent
+ * @return {!Array<!Array<string>>} Tuples of key, version, and the contents
+ * of the parenthetical.
+ */
+goog.labs.userAgent.util.extractVersionTuples = function(userAgent) {
+ // Matches each section of a user agent string.
+ // Example UA:
+ // Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us)
+ // AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405
+ // This has three version tuples: Mozilla, AppleWebKit, and Mobile.
+
+ var versionRegExp = new RegExp(
+ // Key. Note that a key may have a space.
+ // (i.e. 'Mobile Safari' in 'Mobile Safari/5.0')
+ '(\\w[\\w ]+)' +
+
+ '/' + // slash
+ '([^\\s]+)' + // version (i.e. '5.0b')
+ '\\s*' + // whitespace
+ '(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched.
+ 'g');
+
+ var data = [];
+ var match;
+
+ // Iterate and collect the version tuples. Each iteration will be the
+ // next regex match.
+ while (match = versionRegExp.exec(userAgent)) {
+ data.push([
+ match[1], // key
+ match[2], // value
+ // || undefined as this is not undefined in IE7 and IE8
+ match[3] || undefined // info
+ ]);
+ }
+
+ return data;
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities for manipulating objects/maps/hashes.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.object');
+
+
+/**
+ * Whether two values are not observably distinguishable. This
+ * correctly detects that 0 is not the same as -0 and two NaNs are
+ * practically equivalent.
+ *
+ * The implementation is as suggested by harmony:egal proposal.
+ *
+ * @param {*} v The first value to compare.
+ * @param {*} v2 The second value to compare.
+ * @return {boolean} Whether two values are not observably distinguishable.
+ * @see http://wiki.ecmascript.org/doku.php?id=harmony:egal
+ */
+goog.object.is = function(v, v2) {
+ if (v === v2) {
+ // 0 === -0, but they are not identical.
+ // We need the cast because the compiler requires that v2 is a
+ // number (although 1/v2 works with non-number). We cast to ? to
+ // stop the compiler from type-checking this statement.
+ return v !== 0 || 1 / v === 1 / /** @type {?} */ (v2);
+ }
+
+ // NaN is non-reflexive: NaN !== NaN, although they are identical.
+ return v !== v && v2 !== v2;
+};
+
+
+/**
+ * Calls a function for each element in an object/map/hash.
+ *
+ * @param {Object<K,V>} obj The object over which to iterate.
+ * @param {function(this:T,V,?,Object<K,V>):?} f The function to call
+ * for every element. This function takes 3 arguments (the value, the
+ * key and the object) and the return value is ignored.
+ * @param {T=} opt_obj This is used as the 'this' object within f.
+ * @template T,K,V
+ */
+goog.object.forEach = function(obj, f, opt_obj) {
+ for (var key in obj) {
+ f.call(/** @type {?} */ (opt_obj), obj[key], key, obj);
+ }
+};
+
+
+/**
+ * Calls a function for each element in an object/map/hash. If that call returns
+ * true, adds the element to a new object.
+ *
+ * @param {Object<K,V>} obj The object over which to iterate.
+ * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to call
+ * for every element. This
+ * function takes 3 arguments (the value, the key and the object)
+ * and should return a boolean. If the return value is true the
+ * element is added to the result object. If it is false the
+ * element is not included.
+ * @param {T=} opt_obj This is used as the 'this' object within f.
+ * @return {!Object<K,V>} a new object in which only elements that passed the
+ * test are present.
+ * @template T,K,V
+ */
+goog.object.filter = function(obj, f, opt_obj) {
+ var res = {};
+ for (var key in obj) {
+ if (f.call(/** @type {?} */ (opt_obj), obj[key], key, obj)) {
+ res[key] = obj[key];
+ }
+ }
+ return res;
+};
+
+
+/**
+ * For every element in an object/map/hash calls a function and inserts the
+ * result into a new object.
+ *
+ * @param {Object<K,V>} obj The object over which to iterate.
+ * @param {function(this:T,V,?,Object<K,V>):R} f The function to call
+ * for every element. This function
+ * takes 3 arguments (the value, the key and the object)
+ * and should return something. The result will be inserted
+ * into a new object.
+ * @param {T=} opt_obj This is used as the 'this' object within f.
+ * @return {!Object<K,R>} a new object with the results from f.
+ * @template T,K,V,R
+ */
+goog.object.map = function(obj, f, opt_obj) {
+ var res = {};
+ for (var key in obj) {
+ res[key] = f.call(/** @type {?} */ (opt_obj), obj[key], key, obj);
+ }
+ return res;
+};
+
+
+/**
+ * Calls a function for each element in an object/map/hash. If any
+ * call returns true, returns true (without checking the rest). If
+ * all calls return false, returns false.
+ *
+ * @param {Object<K,V>} obj The object to check.
+ * @param {function(this:T,V,?,Object<K,V>):boolean} f The function to
+ * call for every element. This function
+ * takes 3 arguments (the value, the key and the object) and should
+ * return a boolean.
+ * @param {T=} opt_obj This is used as the 'this' object within f.
+ * @return {boolean} true if any element passes the test.
+ * @template T,K,V
+ */
+goog.object.some = function(obj, f, opt_obj) {
+ for (var key in obj) {
+ if (f.call(/** @type {?} */ (opt_obj), obj[key], key, obj)) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Calls a function for each element in an object/map/hash. If
+ * all calls return true, returns true. If any call returns false, returns
+ * false at this point and does not continue to check the remaining elements.
+ *
+ * @param {Object<K,V>} obj The object to check.
+ * @param {?function(this:T,V,?,Object<K,V>):boolean} f The function to
+ * call for every element. This function
+ * takes 3 arguments (the value, the key and the object) and should
+ * return a boolean.
+ * @param {T=} opt_obj This is used as the 'this' object within f.
+ * @return {boolean} false if any element fails the test.
+ * @template T,K,V
+ */
+goog.object.every = function(obj, f, opt_obj) {
+ for (var key in obj) {
+ if (!f.call(/** @type {?} */ (opt_obj), obj[key], key, obj)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Returns the number of key-value pairs in the object map.
+ *
+ * @param {Object} obj The object for which to get the number of key-value
+ * pairs.
+ * @return {number} The number of key-value pairs in the object map.
+ */
+goog.object.getCount = function(obj) {
+ var rv = 0;
+ for (var key in obj) {
+ rv++;
+ }
+ return rv;
+};
+
+
+/**
+ * Returns one key from the object map, if any exists.
+ * For map literals the returned key will be the first one in most of the
+ * browsers (a know exception is Konqueror).
+ *
+ * @param {Object} obj The object to pick a key from.
+ * @return {string|undefined} The key or undefined if the object is empty.
+ */
+goog.object.getAnyKey = function(obj) {
+ for (var key in obj) {
+ return key;
+ }
+};
+
+
+/**
+ * Returns one value from the object map, if any exists.
+ * For map literals the returned value will be the first one in most of the
+ * browsers (a know exception is Konqueror).
+ *
+ * @param {Object<K,V>} obj The object to pick a value from.
+ * @return {V|undefined} The value or undefined if the object is empty.
+ * @template K,V
+ */
+goog.object.getAnyValue = function(obj) {
+ for (var key in obj) {
+ return obj[key];
+ }
+};
+
+
+/**
+ * Whether the object/hash/map contains the given object as a value.
+ * An alias for goog.object.containsValue(obj, val).
+ *
+ * @param {Object<K,V>} obj The object in which to look for val.
+ * @param {V} val The object for which to check.
+ * @return {boolean} true if val is present.
+ * @template K,V
+ */
+goog.object.contains = function(obj, val) {
+ return goog.object.containsValue(obj, val);
+};
+
+
+/**
+ * Returns the values of the object/map/hash.
+ *
+ * @param {Object<K,V>} obj The object from which to get the values.
+ * @return {!Array<V>} The values in the object/map/hash.
+ * @template K,V
+ */
+goog.object.getValues = function(obj) {
+ var res = [];
+ var i = 0;
+ for (var key in obj) {
+ res[i++] = obj[key];
+ }
+ return res;
+};
+
+
+/**
+ * Returns the keys of the object/map/hash.
+ *
+ * @param {Object} obj The object from which to get the keys.
+ * @return {!Array<string>} Array of property keys.
+ */
+goog.object.getKeys = function(obj) {
+ var res = [];
+ var i = 0;
+ for (var key in obj) {
+ res[i++] = key;
+ }
+ return res;
+};
+
+
+/**
+ * Get a value from an object multiple levels deep. This is useful for
+ * pulling values from deeply nested objects, such as JSON responses.
+ * Example usage: getValueByKeys(jsonObj, 'foo', 'entries', 3)
+ *
+ * @param {!Object} obj An object to get the value from. Can be array-like.
+ * @param {...(string|number|!IArrayLike<number|string>)}
+ * var_args A number of keys
+ * (as strings, or numbers, for array-like objects). Can also be
+ * specified as a single array of keys.
+ * @return {*} The resulting value. If, at any point, the value for a key
+ * is undefined, returns undefined.
+ */
+goog.object.getValueByKeys = function(obj, var_args) {
+ var isArrayLike = goog.isArrayLike(var_args);
+ var keys = isArrayLike ? var_args : arguments;
+
+ // Start with the 2nd parameter for the variable parameters syntax.
+ for (var i = isArrayLike ? 0 : 1; i < keys.length; i++) {
+ obj = obj[keys[i]];
+ if (!goog.isDef(obj)) {
+ break;
+ }
+ }
+
+ return obj;
+};
+
+
+/**
+ * Whether the object/map/hash contains the given key.
+ *
+ * @param {Object} obj The object in which to look for key.
+ * @param {?} key The key for which to check.
+ * @return {boolean} true If the map contains the key.
+ */
+goog.object.containsKey = function(obj, key) {
+ return obj !== null && key in obj;
+};
+
+
+/**
+ * Whether the object/map/hash contains the given value. This is O(n).
+ *
+ * @param {Object<K,V>} obj The object in which to look for val.
+ * @param {V} val The value for which to check.
+ * @return {boolean} true If the map contains the value.
+ * @template K,V
+ */
+goog.object.containsValue = function(obj, val) {
+ for (var key in obj) {
+ if (obj[key] == val) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Searches an object for an element that satisfies the given condition and
+ * returns its key.
+ * @param {Object<K,V>} obj The object to search in.
+ * @param {function(this:T,V,string,Object<K,V>):boolean} f The
+ * function to call for every element. Takes 3 arguments (the value,
+ * the key and the object) and should return a boolean.
+ * @param {T=} opt_this An optional "this" context for the function.
+ * @return {string|undefined} The key of an element for which the function
+ * returns true or undefined if no such element is found.
+ * @template T,K,V
+ */
+goog.object.findKey = function(obj, f, opt_this) {
+ for (var key in obj) {
+ if (f.call(/** @type {?} */ (opt_this), obj[key], key, obj)) {
+ return key;
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * Searches an object for an element that satisfies the given condition and
+ * returns its value.
+ * @param {Object<K,V>} obj The object to search in.
+ * @param {function(this:T,V,string,Object<K,V>):boolean} f The function
+ * to call for every element. Takes 3 arguments (the value, the key
+ * and the object) and should return a boolean.
+ * @param {T=} opt_this An optional "this" context for the function.
+ * @return {V} The value of an element for which the function returns true or
+ * undefined if no such element is found.
+ * @template T,K,V
+ */
+goog.object.findValue = function(obj, f, opt_this) {
+ var key = goog.object.findKey(obj, f, opt_this);
+ return key && obj[key];
+};
+
+
+/**
+ * Whether the object/map/hash is empty.
+ *
+ * @param {Object} obj The object to test.
+ * @return {boolean} true if obj is empty.
+ */
+goog.object.isEmpty = function(obj) {
+ for (var key in obj) {
+ return false;
+ }
+ return true;
+};
+
+
+/**
+ * Removes all key value pairs from the object/map/hash.
+ *
+ * @param {Object} obj The object to clear.
+ */
+goog.object.clear = function(obj) {
+ for (var i in obj) {
+ delete obj[i];
+ }
+};
+
+
+/**
+ * Removes a key-value pair based on the key.
+ *
+ * @param {Object} obj The object from which to remove the key.
+ * @param {?} key The key to remove.
+ * @return {boolean} Whether an element was removed.
+ */
+goog.object.remove = function(obj, key) {
+ var rv;
+ if (rv = key in /** @type {!Object} */ (obj)) {
+ delete obj[key];
+ }
+ return rv;
+};
+
+
+/**
+ * Adds a key-value pair to the object. Throws an exception if the key is
+ * already in use. Use set if you want to change an existing pair.
+ *
+ * @param {Object<K,V>} obj The object to which to add the key-value pair.
+ * @param {string} key The key to add.
+ * @param {V} val The value to add.
+ * @template K,V
+ */
+goog.object.add = function(obj, key, val) {
+ if (obj !== null && key in obj) {
+ throw Error('The object already contains the key "' + key + '"');
+ }
+ goog.object.set(obj, key, val);
+};
+
+
+/**
+ * Returns the value for the given key.
+ *
+ * @param {Object<K,V>} obj The object from which to get the value.
+ * @param {string} key The key for which to get the value.
+ * @param {R=} opt_val The value to return if no item is found for the given
+ * key (default is undefined).
+ * @return {V|R|undefined} The value for the given key.
+ * @template K,V,R
+ */
+goog.object.get = function(obj, key, opt_val) {
+ if (obj !== null && key in obj) {
+ return obj[key];
+ }
+ return opt_val;
+};
+
+
+/**
+ * Adds a key-value pair to the object/map/hash.
+ *
+ * @param {Object<K,V>} obj The object to which to add the key-value pair.
+ * @param {string} key The key to add.
+ * @param {V} value The value to add.
+ * @template K,V
+ */
+goog.object.set = function(obj, key, value) {
+ obj[key] = value;
+};
+
+
+/**
+ * Adds a key-value pair to the object/map/hash if it doesn't exist yet.
+ *
+ * @param {Object<K,V>} obj The object to which to add the key-value pair.
+ * @param {string} key The key to add.
+ * @param {V} value The value to add if the key wasn't present.
+ * @return {V} The value of the entry at the end of the function.
+ * @template K,V
+ */
+goog.object.setIfUndefined = function(obj, key, value) {
+ return key in /** @type {!Object} */ (obj) ? obj[key] : (obj[key] = value);
+};
+
+
+/**
+ * Sets a key and value to an object if the key is not set. The value will be
+ * the return value of the given function. If the key already exists, the
+ * object will not be changed and the function will not be called (the function
+ * will be lazily evaluated -- only called if necessary).
+ *
+ * This function is particularly useful for use with a map used a as a cache.
+ *
+ * @param {!Object<K,V>} obj The object to which to add the key-value pair.
+ * @param {string} key The key to add.
+ * @param {function():V} f The value to add if the key wasn't present.
+ * @return {V} The value of the entry at the end of the function.
+ * @template K,V
+ */
+goog.object.setWithReturnValueIfNotSet = function(obj, key, f) {
+ if (key in obj) {
+ return obj[key];
+ }
+
+ var val = f();
+ obj[key] = val;
+ return val;
+};
+
+
+/**
+ * Compares two objects for equality using === on the values.
+ *
+ * @param {!Object<K,V>} a
+ * @param {!Object<K,V>} b
+ * @return {boolean}
+ * @template K,V
+ */
+goog.object.equals = function(a, b) {
+ for (var k in a) {
+ if (!(k in b) || a[k] !== b[k]) {
+ return false;
+ }
+ }
+ for (var k in b) {
+ if (!(k in a)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Returns a shallow clone of the object.
+ *
+ * @param {Object<K,V>} obj Object to clone.
+ * @return {!Object<K,V>} Clone of the input object.
+ * @template K,V
+ */
+goog.object.clone = function(obj) {
+ // We cannot use the prototype trick because a lot of methods depend on where
+ // the actual key is set.
+
+ var res = {};
+ for (var key in obj) {
+ res[key] = obj[key];
+ }
+ return res;
+ // We could also use goog.mixin but I wanted this to be independent from that.
+};
+
+
+/**
+ * Clones a value. The input may be an Object, Array, or basic type. Objects and
+ * arrays will be cloned recursively.
+ *
+ * WARNINGS:
+ * <code>goog.object.unsafeClone</code> does not detect reference loops. Objects
+ * that refer to themselves will cause infinite recursion.
+ *
+ * <code>goog.object.unsafeClone</code> is unaware of unique identifiers, and
+ * copies UIDs created by <code>getUid</code> into cloned results.
+ *
+ * @param {*} obj The value to clone.
+ * @return {*} A clone of the input value.
+ */
+goog.object.unsafeClone = function(obj) {
+ var type = goog.typeOf(obj);
+ if (type == 'object' || type == 'array') {
+ if (goog.isFunction(obj.clone)) {
+ return obj.clone();
+ }
+ var clone = type == 'array' ? [] : {};
+ for (var key in obj) {
+ clone[key] = goog.object.unsafeClone(obj[key]);
+ }
+ return clone;
+ }
+
+ return obj;
+};
+
+
+/**
+ * Returns a new object in which all the keys and values are interchanged
+ * (keys become values and values become keys). If multiple keys map to the
+ * same value, the chosen transposed value is implementation-dependent.
+ *
+ * @param {Object} obj The object to transpose.
+ * @return {!Object} The transposed object.
+ */
+goog.object.transpose = function(obj) {
+ var transposed = {};
+ for (var key in obj) {
+ transposed[obj[key]] = key;
+ }
+ return transposed;
+};
+
+
+/**
+ * The names of the fields that are defined on Object.prototype.
+ * @type {Array<string>}
+ * @private
+ */
+goog.object.PROTOTYPE_FIELDS_ = [
+ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
+ 'toLocaleString', 'toString', 'valueOf'
+];
+
+
+/**
+ * Extends an object with another object.
+ * This operates 'in-place'; it does not create a new Object.
+ *
+ * Example:
+ * var o = {};
+ * goog.object.extend(o, {a: 0, b: 1});
+ * o; // {a: 0, b: 1}
+ * goog.object.extend(o, {b: 2, c: 3});
+ * o; // {a: 0, b: 2, c: 3}
+ *
+ * @param {Object} target The object to modify. Existing properties will be
+ * overwritten if they are also present in one of the objects in
+ * {@code var_args}.
+ * @param {...Object} var_args The objects from which values will be copied.
+ */
+goog.object.extend = function(target, var_args) {
+ var key, source;
+ for (var i = 1; i < arguments.length; i++) {
+ source = arguments[i];
+ for (key in source) {
+ target[key] = source[key];
+ }
+
+ // For IE the for-in-loop does not contain any properties that are not
+ // enumerable on the prototype object (for example isPrototypeOf from
+ // Object.prototype) and it will also not include 'replace' on objects that
+ // extend String and change 'replace' (not that it is common for anyone to
+ // extend anything except Object).
+
+ for (var j = 0; j < goog.object.PROTOTYPE_FIELDS_.length; j++) {
+ key = goog.object.PROTOTYPE_FIELDS_[j];
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+};
+
+
+/**
+ * Creates a new object built from the key-value pairs provided as arguments.
+ * @param {...*} var_args If only one argument is provided and it is an array
+ * then this is used as the arguments, otherwise even arguments are used as
+ * the property names and odd arguments are used as the property values.
+ * @return {!Object} The new object.
+ * @throws {Error} If there are uneven number of arguments or there is only one
+ * non array argument.
+ */
+goog.object.create = function(var_args) {
+ var argLength = arguments.length;
+ if (argLength == 1 && goog.isArray(arguments[0])) {
+ return goog.object.create.apply(null, arguments[0]);
+ }
+
+ if (argLength % 2) {
+ throw Error('Uneven number of arguments');
+ }
+
+ var rv = {};
+ for (var i = 0; i < argLength; i += 2) {
+ rv[arguments[i]] = arguments[i + 1];
+ }
+ return rv;
+};
+
+
+/**
+ * Creates a new object where the property names come from the arguments but
+ * the value is always set to true
+ * @param {...*} var_args If only one argument is provided and it is an array
+ * then this is used as the arguments, otherwise the arguments are used
+ * as the property names.
+ * @return {!Object} The new object.
+ */
+goog.object.createSet = function(var_args) {
+ var argLength = arguments.length;
+ if (argLength == 1 && goog.isArray(arguments[0])) {
+ return goog.object.createSet.apply(null, arguments[0]);
+ }
+
+ var rv = {};
+ for (var i = 0; i < argLength; i++) {
+ rv[arguments[i]] = true;
+ }
+ return rv;
+};
+
+
+/**
+ * Creates an immutable view of the underlying object, if the browser
+ * supports immutable objects.
+ *
+ * In default mode, writes to this view will fail silently. In strict mode,
+ * they will throw an error.
+ *
+ * @param {!Object<K,V>} obj An object.
+ * @return {!Object<K,V>} An immutable view of that object, or the
+ * original object if this browser does not support immutables.
+ * @template K,V
+ */
+goog.object.createImmutableView = function(obj) {
+ var result = obj;
+ if (Object.isFrozen && !Object.isFrozen(obj)) {
+ result = Object.create(obj);
+ Object.freeze(result);
+ }
+ return result;
+};
+
+
+/**
+ * @param {!Object} obj An object.
+ * @return {boolean} Whether this is an immutable view of the object.
+ */
+goog.object.isImmutableView = function(obj) {
+ return !!Object.isFrozen && Object.isFrozen(obj);
+};
+
+// Copyright 2013 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Closure user agent detection (Browser).
+ * @see <a href="http://www.useragentstring.com/">User agent strings</a>
+ * For more information on rendering engine, platform, or device see the other
+ * sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform,
+ * goog.labs.userAgent.device respectively.)
+ *
+ * @author martone@google.com (Andy Martone)
+ */
+
+goog.provide('goog.labs.userAgent.browser');
+
+goog.require('goog.array');
+goog.require('goog.labs.userAgent.util');
+goog.require('goog.object');
+goog.require('goog.string');
+
+
+// TODO(nnaze): Refactor to remove excessive exclusion logic in matching
+// functions.
+
+
+/**
+ * @return {boolean} Whether the user's browser is Opera. Note: Chromium
+ * based Opera (Opera 15+) is detected as Chrome to avoid unnecessary
+ * special casing.
+ * @private
+ */
+goog.labs.userAgent.browser.matchOpera_ = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Opera');
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is IE.
+ * @private
+ */
+goog.labs.userAgent.browser.matchIE_ = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Trident') ||
+ goog.labs.userAgent.util.matchUserAgent('MSIE');
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is Edge.
+ * @private
+ */
+goog.labs.userAgent.browser.matchEdge_ = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Edge');
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is Firefox.
+ * @private
+ */
+goog.labs.userAgent.browser.matchFirefox_ = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Firefox');
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is Safari.
+ * @private
+ */
+goog.labs.userAgent.browser.matchSafari_ = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Safari') &&
+ !(goog.labs.userAgent.browser.matchChrome_() ||
+ goog.labs.userAgent.browser.matchCoast_() ||
+ goog.labs.userAgent.browser.matchOpera_() ||
+ goog.labs.userAgent.browser.matchEdge_() ||
+ goog.labs.userAgent.browser.isSilk() ||
+ goog.labs.userAgent.util.matchUserAgent('Android'));
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based
+ * iOS browser).
+ * @private
+ */
+goog.labs.userAgent.browser.matchCoast_ = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Coast');
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is iOS Webview.
+ * @private
+ */
+goog.labs.userAgent.browser.matchIosWebview_ = function() {
+ // iOS Webview does not show up as Chrome or Safari. Also check for Opera's
+ // WebKit-based iOS browser, Coast.
+ return (goog.labs.userAgent.util.matchUserAgent('iPad') ||
+ goog.labs.userAgent.util.matchUserAgent('iPhone')) &&
+ !goog.labs.userAgent.browser.matchSafari_() &&
+ !goog.labs.userAgent.browser.matchChrome_() &&
+ !goog.labs.userAgent.browser.matchCoast_() &&
+ goog.labs.userAgent.util.matchUserAgent('AppleWebKit');
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is Chrome.
+ * @private
+ */
+goog.labs.userAgent.browser.matchChrome_ = function() {
+ return (goog.labs.userAgent.util.matchUserAgent('Chrome') ||
+ goog.labs.userAgent.util.matchUserAgent('CriOS')) &&
+ !goog.labs.userAgent.browser.matchEdge_();
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is the Android browser.
+ * @private
+ */
+goog.labs.userAgent.browser.matchAndroidBrowser_ = function() {
+ // Android can appear in the user agent string for Chrome on Android.
+ // This is not the Android standalone browser if it does.
+ return goog.labs.userAgent.util.matchUserAgent('Android') &&
+ !(goog.labs.userAgent.browser.isChrome() ||
+ goog.labs.userAgent.browser.isFirefox() ||
+ goog.labs.userAgent.browser.isOpera() ||
+ goog.labs.userAgent.browser.isSilk());
+};
+
+
+/**
+ * @return {boolean} Whether the user's browser is Opera.
+ */
+goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is IE.
+ */
+goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is Edge.
+ */
+goog.labs.userAgent.browser.isEdge = goog.labs.userAgent.browser.matchEdge_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is Firefox.
+ */
+goog.labs.userAgent.browser.isFirefox =
+ goog.labs.userAgent.browser.matchFirefox_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is Safari.
+ */
+goog.labs.userAgent.browser.isSafari = goog.labs.userAgent.browser.matchSafari_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based
+ * iOS browser).
+ */
+goog.labs.userAgent.browser.isCoast = goog.labs.userAgent.browser.matchCoast_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is iOS Webview.
+ */
+goog.labs.userAgent.browser.isIosWebview =
+ goog.labs.userAgent.browser.matchIosWebview_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is Chrome.
+ */
+goog.labs.userAgent.browser.isChrome = goog.labs.userAgent.browser.matchChrome_;
+
+
+/**
+ * @return {boolean} Whether the user's browser is the Android browser.
+ */
+goog.labs.userAgent.browser.isAndroidBrowser =
+ goog.labs.userAgent.browser.matchAndroidBrowser_;
+
+
+/**
+ * For more information, see:
+ * http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
+ * @return {boolean} Whether the user's browser is Silk.
+ */
+goog.labs.userAgent.browser.isSilk = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Silk');
+};
+
+
+/**
+ * @return {string} The browser version or empty string if version cannot be
+ * determined. Note that for Internet Explorer, this returns the version of
+ * the browser, not the version of the rendering engine. (IE 8 in
+ * compatibility mode will return 8.0 rather than 7.0. To determine the
+ * rendering engine version, look at document.documentMode instead. See
+ * http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more
+ * details.)
+ */
+goog.labs.userAgent.browser.getVersion = function() {
+ var userAgentString = goog.labs.userAgent.util.getUserAgent();
+ // Special case IE since IE's version is inside the parenthesis and
+ // without the '/'.
+ if (goog.labs.userAgent.browser.isIE()) {
+ return goog.labs.userAgent.browser.getIEVersion_(userAgentString);
+ }
+
+ var versionTuples =
+ goog.labs.userAgent.util.extractVersionTuples(userAgentString);
+
+ // Construct a map for easy lookup.
+ var versionMap = {};
+ goog.array.forEach(versionTuples, function(tuple) {
+ // Note that the tuple is of length three, but we only care about the
+ // first two.
+ var key = tuple[0];
+ var value = tuple[1];
+ versionMap[key] = value;
+ });
+
+ var versionMapHasKey = goog.partial(goog.object.containsKey, versionMap);
+
+ // Gives the value with the first key it finds, otherwise empty string.
+ function lookUpValueWithKeys(keys) {
+ var key = goog.array.find(keys, versionMapHasKey);
+ return versionMap[key] || '';
+ }
+
+ // Check Opera before Chrome since Opera 15+ has "Chrome" in the string.
+ // See
+ // http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond
+ if (goog.labs.userAgent.browser.isOpera()) {
+ // Opera 10 has Version/10.0 but Opera/9.8, so look for "Version" first.
+ // Opera uses 'OPR' for more recent UAs.
+ return lookUpValueWithKeys(['Version', 'Opera']);
+ }
+
+ // Check Edge before Chrome since it has Chrome in the string.
+ if (goog.labs.userAgent.browser.isEdge()) {
+ return lookUpValueWithKeys(['Edge']);
+ }
+
+ if (goog.labs.userAgent.browser.isChrome()) {
+ return lookUpValueWithKeys(['Chrome', 'CriOS']);
+ }
+
+ // Usually products browser versions are in the third tuple after "Mozilla"
+ // and the engine.
+ var tuple = versionTuples[2];
+ return tuple && tuple[1] || '';
+};
+
+
+/**
+ * @param {string|number} version The version to check.
+ * @return {boolean} Whether the browser version is higher or the same as the
+ * given version.
+ */
+goog.labs.userAgent.browser.isVersionOrHigher = function(version) {
+ return goog.string.compareVersions(
+ goog.labs.userAgent.browser.getVersion(), version) >= 0;
+};
+
+
+/**
+ * Determines IE version. More information:
+ * http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString
+ * http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
+ * http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx
+ * http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx
+ *
+ * @param {string} userAgent the User-Agent.
+ * @return {string}
+ * @private
+ */
+goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) {
+ // IE11 may identify itself as MSIE 9.0 or MSIE 10.0 due to an IE 11 upgrade
+ // bug. Example UA:
+ // Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; rv:11.0)
+ // like Gecko.
+ // See http://www.whatismybrowser.com/developers/unknown-user-agent-fragments.
+ var rv = /rv: *([\d\.]*)/.exec(userAgent);
+ if (rv && rv[1]) {
+ return rv[1];
+ }
+
+ var version = '';
+ var msie = /MSIE +([\d\.]+)/.exec(userAgent);
+ if (msie && msie[1]) {
+ // IE in compatibility mode usually identifies itself as MSIE 7.0; in this
+ // case, use the Trident version to determine the version of IE. For more
+ // details, see the links above.
+ var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent);
+ if (msie[1] == '7.0') {
+ if (tridentVersion && tridentVersion[1]) {
+ switch (tridentVersion[1]) {
+ case '4.0':
+ version = '8.0';
+ break;
+ case '5.0':
+ version = '9.0';
+ break;
+ case '6.0':
+ version = '10.0';
+ break;
+ case '7.0':
+ version = '11.0';
+ break;
+ }
+ } else {
+ version = '7.0';
+ }
+ } else {
+ version = msie[1];
+ }
+ }
+ return version;
+};
+
+// Copyright 2013 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Closure user agent detection.
+ * @see http://en.wikipedia.org/wiki/User_agent
+ * For more information on browser brand, platform, or device see the other
+ * sub-namespaces in goog.labs.userAgent (browser, platform, and device).
+ *
+ */
+
+goog.provide('goog.labs.userAgent.engine');
+
+goog.require('goog.array');
+goog.require('goog.labs.userAgent.util');
+goog.require('goog.string');
+
+
+/**
+ * @return {boolean} Whether the rendering engine is Presto.
+ */
+goog.labs.userAgent.engine.isPresto = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Presto');
+};
+
+
+/**
+ * @return {boolean} Whether the rendering engine is Trident.
+ */
+goog.labs.userAgent.engine.isTrident = function() {
+ // IE only started including the Trident token in IE8.
+ return goog.labs.userAgent.util.matchUserAgent('Trident') ||
+ goog.labs.userAgent.util.matchUserAgent('MSIE');
+};
+
+
+/**
+ * @return {boolean} Whether the rendering engine is Edge.
+ */
+goog.labs.userAgent.engine.isEdge = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Edge');
+};
+
+
+/**
+ * @return {boolean} Whether the rendering engine is WebKit.
+ */
+goog.labs.userAgent.engine.isWebKit = function() {
+ return goog.labs.userAgent.util.matchUserAgentIgnoreCase('WebKit') &&
+ !goog.labs.userAgent.engine.isEdge();
+};
+
+
+/**
+ * @return {boolean} Whether the rendering engine is Gecko.
+ */
+goog.labs.userAgent.engine.isGecko = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Gecko') &&
+ !goog.labs.userAgent.engine.isWebKit() &&
+ !goog.labs.userAgent.engine.isTrident() &&
+ !goog.labs.userAgent.engine.isEdge();
+};
+
+
+/**
+ * @return {string} The rendering engine's version or empty string if version
+ * can't be determined.
+ */
+goog.labs.userAgent.engine.getVersion = function() {
+ var userAgentString = goog.labs.userAgent.util.getUserAgent();
+ if (userAgentString) {
+ var tuples = goog.labs.userAgent.util.extractVersionTuples(userAgentString);
+
+ var engineTuple = goog.labs.userAgent.engine.getEngineTuple_(tuples);
+ if (engineTuple) {
+ // In Gecko, the version string is either in the browser info or the
+ // Firefox version. See Gecko user agent string reference:
+ // http://goo.gl/mULqa
+ if (engineTuple[0] == 'Gecko') {
+ return goog.labs.userAgent.engine.getVersionForKey_(tuples, 'Firefox');
+ }
+
+ return engineTuple[1];
+ }
+
+ // MSIE has only one version identifier, and the Trident version is
+ // specified in the parenthetical. IE Edge is covered in the engine tuple
+ // detection.
+ var browserTuple = tuples[0];
+ var info;
+ if (browserTuple && (info = browserTuple[2])) {
+ var match = /Trident\/([^\s;]+)/.exec(info);
+ if (match) {
+ return match[1];
+ }
+ }
+ }
+ return '';
+};
+
+
+/**
+ * @param {!Array<!Array<string>>} tuples Extracted version tuples.
+ * @return {!Array<string>|undefined} The engine tuple or undefined if not
+ * found.
+ * @private
+ */
+goog.labs.userAgent.engine.getEngineTuple_ = function(tuples) {
+ if (!goog.labs.userAgent.engine.isEdge()) {
+ return tuples[1];
+ }
+ for (var i = 0; i < tuples.length; i++) {
+ var tuple = tuples[i];
+ if (tuple[0] == 'Edge') {
+ return tuple;
+ }
+ }
+};
+
+
+/**
+ * @param {string|number} version The version to check.
+ * @return {boolean} Whether the rendering engine version is higher or the same
+ * as the given version.
+ */
+goog.labs.userAgent.engine.isVersionOrHigher = function(version) {
+ return goog.string.compareVersions(
+ goog.labs.userAgent.engine.getVersion(), version) >= 0;
+};
+
+
+/**
+ * @param {!Array<!Array<string>>} tuples Version tuples.
+ * @param {string} key The key to look for.
+ * @return {string} The version string of the given key, if present.
+ * Otherwise, the empty string.
+ * @private
+ */
+goog.labs.userAgent.engine.getVersionForKey_ = function(tuples, key) {
+ // TODO(nnaze): Move to util if useful elsewhere.
+
+ var pair = goog.array.find(tuples, function(pair) { return key == pair[0]; });
+
+ return pair && pair[1] || '';
+};
+
+// Copyright 2013 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Closure user agent platform detection.
+ * @see <a href="http://www.useragentstring.com/">User agent strings</a>
+ * For more information on browser brand, rendering engine, or device see the
+ * other sub-namespaces in goog.labs.userAgent (browser, engine, and device
+ * respectively).
+ *
+ */
+
+goog.provide('goog.labs.userAgent.platform');
+
+goog.require('goog.labs.userAgent.util');
+goog.require('goog.string');
+
+
+/**
+ * @return {boolean} Whether the platform is Android.
+ */
+goog.labs.userAgent.platform.isAndroid = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Android');
+};
+
+
+/**
+ * @return {boolean} Whether the platform is iPod.
+ */
+goog.labs.userAgent.platform.isIpod = function() {
+ return goog.labs.userAgent.util.matchUserAgent('iPod');
+};
+
+
+/**
+ * @return {boolean} Whether the platform is iPhone.
+ */
+goog.labs.userAgent.platform.isIphone = function() {
+ return goog.labs.userAgent.util.matchUserAgent('iPhone') &&
+ !goog.labs.userAgent.util.matchUserAgent('iPod') &&
+ !goog.labs.userAgent.util.matchUserAgent('iPad');
+};
+
+
+/**
+ * @return {boolean} Whether the platform is iPad.
+ */
+goog.labs.userAgent.platform.isIpad = function() {
+ return goog.labs.userAgent.util.matchUserAgent('iPad');
+};
+
+
+/**
+ * @return {boolean} Whether the platform is iOS.
+ */
+goog.labs.userAgent.platform.isIos = function() {
+ return goog.labs.userAgent.platform.isIphone() ||
+ goog.labs.userAgent.platform.isIpad() ||
+ goog.labs.userAgent.platform.isIpod();
+};
+
+
+/**
+ * @return {boolean} Whether the platform is Mac.
+ */
+goog.labs.userAgent.platform.isMacintosh = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Macintosh');
+};
+
+
+/**
+ * Note: ChromeOS is not considered to be Linux as it does not report itself
+ * as Linux in the user agent string.
+ * @return {boolean} Whether the platform is Linux.
+ */
+goog.labs.userAgent.platform.isLinux = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Linux');
+};
+
+
+/**
+ * @return {boolean} Whether the platform is Windows.
+ */
+goog.labs.userAgent.platform.isWindows = function() {
+ return goog.labs.userAgent.util.matchUserAgent('Windows');
+};
+
+
+/**
+ * @return {boolean} Whether the platform is ChromeOS.
+ */
+goog.labs.userAgent.platform.isChromeOS = function() {
+ return goog.labs.userAgent.util.matchUserAgent('CrOS');
+};
+
+
+/**
+ * The version of the platform. We only determine the version for Windows,
+ * Mac, and Chrome OS. It doesn't make much sense on Linux. For Windows, we only
+ * look at the NT version. Non-NT-based versions (e.g. 95, 98, etc.) are given
+ * version 0.0.
+ *
+ * @return {string} The platform version or empty string if version cannot be
+ * determined.
+ */
+goog.labs.userAgent.platform.getVersion = function() {
+ var userAgentString = goog.labs.userAgent.util.getUserAgent();
+ var version = '', re;
+ if (goog.labs.userAgent.platform.isWindows()) {
+ re = /Windows (?:NT|Phone) ([0-9.]+)/;
+ var match = re.exec(userAgentString);
+ if (match) {
+ version = match[1];
+ } else {
+ version = '0.0';
+ }
+ } else if (goog.labs.userAgent.platform.isIos()) {
+ re = /(?:iPhone|iPod|iPad|CPU)\s+OS\s+(\S+)/;
+ var match = re.exec(userAgentString);
+ // Report the version as x.y.z and not x_y_z
+ version = match && match[1].replace(/_/g, '.');
+ } else if (goog.labs.userAgent.platform.isMacintosh()) {
+ re = /Mac OS X ([0-9_.]+)/;
+ var match = re.exec(userAgentString);
+ // Note: some old versions of Camino do not report an OSX version.
+ // Default to 10.
+ version = match ? match[1].replace(/_/g, '.') : '10';
+ } else if (goog.labs.userAgent.platform.isAndroid()) {
+ re = /Android\s+([^\);]+)(\)|;)/;
+ var match = re.exec(userAgentString);
+ version = match && match[1];
+ } else if (goog.labs.userAgent.platform.isChromeOS()) {
+ re = /(?:CrOS\s+(?:i686|x86_64)\s+([0-9.]+))/;
+ var match = re.exec(userAgentString);
+ version = match && match[1];
+ }
+ return version || '';
+};
+
+
+/**
+ * @param {string|number} version The version to check.
+ * @return {boolean} Whether the browser version is higher or the same as the
+ * given version.
+ */
+goog.labs.userAgent.platform.isVersionOrHigher = function(version) {
+ return goog.string.compareVersions(
+ goog.labs.userAgent.platform.getVersion(), version) >= 0;
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Rendering engine detection.
+ * @see <a href="http://www.useragentstring.com/">User agent strings</a>
+ * For information on the browser brand (such as Safari versus Chrome), see
+ * goog.userAgent.product.
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/useragent.html
+ */
+
+goog.provide('goog.userAgent');
+
+goog.require('goog.labs.userAgent.browser');
+goog.require('goog.labs.userAgent.engine');
+goog.require('goog.labs.userAgent.platform');
+goog.require('goog.labs.userAgent.util');
+goog.require('goog.string');
+
+
+/**
+ * @define {boolean} Whether we know at compile-time that the browser is IE.
+ */
+goog.define('goog.userAgent.ASSUME_IE', false);
+
+
+/**
+ * @define {boolean} Whether we know at compile-time that the browser is EDGE.
+ */
+goog.define('goog.userAgent.ASSUME_EDGE', false);
+
+
+/**
+ * @define {boolean} Whether we know at compile-time that the browser is GECKO.
+ */
+goog.define('goog.userAgent.ASSUME_GECKO', false);
+
+
+/**
+ * @define {boolean} Whether we know at compile-time that the browser is WEBKIT.
+ */
+goog.define('goog.userAgent.ASSUME_WEBKIT', false);
+
+
+/**
+ * @define {boolean} Whether we know at compile-time that the browser is a
+ * mobile device running WebKit e.g. iPhone or Android.
+ */
+goog.define('goog.userAgent.ASSUME_MOBILE_WEBKIT', false);
+
+
+/**
+ * @define {boolean} Whether we know at compile-time that the browser is OPERA.
+ */
+goog.define('goog.userAgent.ASSUME_OPERA', false);
+
+
+/**
+ * @define {boolean} Whether the
+ * {@code goog.userAgent.isVersionOrHigher}
+ * function will return true for any version.
+ */
+goog.define('goog.userAgent.ASSUME_ANY_VERSION', false);
+
+
+/**
+ * Whether we know the browser engine at compile-time.
+ * @type {boolean}
+ * @private
+ */
+goog.userAgent.BROWSER_KNOWN_ = goog.userAgent.ASSUME_IE ||
+ goog.userAgent.ASSUME_EDGE || goog.userAgent.ASSUME_GECKO ||
+ goog.userAgent.ASSUME_MOBILE_WEBKIT || goog.userAgent.ASSUME_WEBKIT ||
+ goog.userAgent.ASSUME_OPERA;
+
+
+/**
+ * Returns the userAgent string for the current browser.
+ *
+ * @return {string} The userAgent string.
+ */
+goog.userAgent.getUserAgentString = function() {
+ return goog.labs.userAgent.util.getUserAgent();
+};
+
+
+/**
+ * TODO(nnaze): Change type to "Navigator" and update compilation targets.
+ * @return {Object} The native navigator object.
+ */
+goog.userAgent.getNavigator = function() {
+ // Need a local navigator reference instead of using the global one,
+ // to avoid the rare case where they reference different objects.
+ // (in a WorkerPool, for example).
+ return goog.global['navigator'] || null;
+};
+
+
+/**
+ * Whether the user agent is Opera.
+ * @type {boolean}
+ */
+goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ?
+ goog.userAgent.ASSUME_OPERA :
+ goog.labs.userAgent.browser.isOpera();
+
+
+/**
+ * Whether the user agent is Internet Explorer.
+ * @type {boolean}
+ */
+goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ?
+ goog.userAgent.ASSUME_IE :
+ goog.labs.userAgent.browser.isIE();
+
+
+/**
+ * Whether the user agent is Microsoft Edge.
+ * @type {boolean}
+ */
+goog.userAgent.EDGE = goog.userAgent.BROWSER_KNOWN_ ?
+ goog.userAgent.ASSUME_EDGE :
+ goog.labs.userAgent.engine.isEdge();
+
+
+/**
+ * Whether the user agent is MS Internet Explorer or MS Edge.
+ * @type {boolean}
+ */
+goog.userAgent.EDGE_OR_IE = goog.userAgent.EDGE || goog.userAgent.IE;
+
+
+/**
+ * Whether the user agent is Gecko. Gecko is the rendering engine used by
+ * Mozilla, Firefox, and others.
+ * @type {boolean}
+ */
+goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ?
+ goog.userAgent.ASSUME_GECKO :
+ goog.labs.userAgent.engine.isGecko();
+
+
+/**
+ * Whether the user agent is WebKit. WebKit is the rendering engine that
+ * Safari, Android and others use.
+ * @type {boolean}
+ */
+goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ?
+ goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT :
+ goog.labs.userAgent.engine.isWebKit();
+
+
+/**
+ * Whether the user agent is running on a mobile device.
+ *
+ * This is a separate function so that the logic can be tested.
+ *
+ * TODO(nnaze): Investigate swapping in goog.labs.userAgent.device.isMobile().
+ *
+ * @return {boolean} Whether the user agent is running on a mobile device.
+ * @private
+ */
+goog.userAgent.isMobile_ = function() {
+ return goog.userAgent.WEBKIT &&
+ goog.labs.userAgent.util.matchUserAgent('Mobile');
+};
+
+
+/**
+ * Whether the user agent is running on a mobile device.
+ *
+ * TODO(nnaze): Consider deprecating MOBILE when labs.userAgent
+ * is promoted as the gecko/webkit logic is likely inaccurate.
+ *
+ * @type {boolean}
+ */
+goog.userAgent.MOBILE =
+ goog.userAgent.ASSUME_MOBILE_WEBKIT || goog.userAgent.isMobile_();
+
+
+/**
+ * Used while transitioning code to use WEBKIT instead.
+ * @type {boolean}
+ * @deprecated Use {@link goog.userAgent.product.SAFARI} instead.
+ * TODO(nicksantos): Delete this from goog.userAgent.
+ */
+goog.userAgent.SAFARI = goog.userAgent.WEBKIT;
+
+
+/**
+ * @return {string} the platform (operating system) the user agent is running
+ * on. Default to empty string because navigator.platform may not be defined
+ * (on Rhino, for example).
+ * @private
+ */
+goog.userAgent.determinePlatform_ = function() {
+ var navigator = goog.userAgent.getNavigator();
+ return navigator && navigator.platform || '';
+};
+
+
+/**
+ * The platform (operating system) the user agent is running on. Default to
+ * empty string because navigator.platform may not be defined (on Rhino, for
+ * example).
+ * @type {string}
+ */
+goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_();
+
+
+/**
+ * @define {boolean} Whether the user agent is running on a Macintosh operating
+ * system.
+ */
+goog.define('goog.userAgent.ASSUME_MAC', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on a Windows operating
+ * system.
+ */
+goog.define('goog.userAgent.ASSUME_WINDOWS', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on a Linux operating
+ * system.
+ */
+goog.define('goog.userAgent.ASSUME_LINUX', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on a X11 windowing
+ * system.
+ */
+goog.define('goog.userAgent.ASSUME_X11', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on Android.
+ */
+goog.define('goog.userAgent.ASSUME_ANDROID', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on an iPhone.
+ */
+goog.define('goog.userAgent.ASSUME_IPHONE', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on an iPad.
+ */
+goog.define('goog.userAgent.ASSUME_IPAD', false);
+
+
+/**
+ * @define {boolean} Whether the user agent is running on an iPod.
+ */
+goog.define('goog.userAgent.ASSUME_IPOD', false);
+
+
+/**
+ * @type {boolean}
+ * @private
+ */
+goog.userAgent.PLATFORM_KNOWN_ = goog.userAgent.ASSUME_MAC ||
+ goog.userAgent.ASSUME_WINDOWS || goog.userAgent.ASSUME_LINUX ||
+ goog.userAgent.ASSUME_X11 || goog.userAgent.ASSUME_ANDROID ||
+ goog.userAgent.ASSUME_IPHONE || goog.userAgent.ASSUME_IPAD ||
+ goog.userAgent.ASSUME_IPOD;
+
+
+/**
+ * Whether the user agent is running on a Macintosh operating system.
+ * @type {boolean}
+ */
+goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_MAC :
+ goog.labs.userAgent.platform.isMacintosh();
+
+
+/**
+ * Whether the user agent is running on a Windows operating system.
+ * @type {boolean}
+ */
+goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_WINDOWS :
+ goog.labs.userAgent.platform.isWindows();
+
+
+/**
+ * Whether the user agent is Linux per the legacy behavior of
+ * goog.userAgent.LINUX, which considered ChromeOS to also be
+ * Linux.
+ * @return {boolean}
+ * @private
+ */
+goog.userAgent.isLegacyLinux_ = function() {
+ return goog.labs.userAgent.platform.isLinux() ||
+ goog.labs.userAgent.platform.isChromeOS();
+};
+
+
+/**
+ * Whether the user agent is running on a Linux operating system.
+ *
+ * Note that goog.userAgent.LINUX considers ChromeOS to be Linux,
+ * while goog.labs.userAgent.platform considers ChromeOS and
+ * Linux to be different OSes.
+ *
+ * @type {boolean}
+ */
+goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_LINUX :
+ goog.userAgent.isLegacyLinux_();
+
+
+/**
+ * @return {boolean} Whether the user agent is an X11 windowing system.
+ * @private
+ */
+goog.userAgent.isX11_ = function() {
+ var navigator = goog.userAgent.getNavigator();
+ return !!navigator &&
+ goog.string.contains(navigator['appVersion'] || '', 'X11');
+};
+
+
+/**
+ * Whether the user agent is running on a X11 windowing system.
+ * @type {boolean}
+ */
+goog.userAgent.X11 = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_X11 :
+ goog.userAgent.isX11_();
+
+
+/**
+ * Whether the user agent is running on Android.
+ * @type {boolean}
+ */
+goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_ANDROID :
+ goog.labs.userAgent.platform.isAndroid();
+
+
+/**
+ * Whether the user agent is running on an iPhone.
+ * @type {boolean}
+ */
+goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_IPHONE :
+ goog.labs.userAgent.platform.isIphone();
+
+
+/**
+ * Whether the user agent is running on an iPad.
+ * @type {boolean}
+ */
+goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_IPAD :
+ goog.labs.userAgent.platform.isIpad();
+
+
+/**
+ * Whether the user agent is running on an iPod.
+ * @type {boolean}
+ */
+goog.userAgent.IPOD = goog.userAgent.PLATFORM_KNOWN_ ?
+ goog.userAgent.ASSUME_IPOD :
+ goog.labs.userAgent.platform.isIpod();
+
+
+/**
+ * @return {string} The string that describes the version number of the user
+ * agent.
+ * @private
+ */
+goog.userAgent.determineVersion_ = function() {
+ // All browsers have different ways to detect the version and they all have
+ // different naming schemes.
+ // version is a string rather than a number because it may contain 'b', 'a',
+ // and so on.
+ var version = '';
+ var arr = goog.userAgent.getVersionRegexResult_();
+ if (arr) {
+ version = arr ? arr[1] : '';
+ }
+
+ if (goog.userAgent.IE) {
+ // IE9 can be in document mode 9 but be reporting an inconsistent user agent
+ // version. If it is identifying as a version lower than 9 we take the
+ // documentMode as the version instead. IE8 has similar behavior.
+ // It is recommended to set the X-UA-Compatible header to ensure that IE9
+ // uses documentMode 9.
+ var docMode = goog.userAgent.getDocumentMode_();
+ if (docMode != null && docMode > parseFloat(version)) {
+ return String(docMode);
+ }
+ }
+
+ return version;
+};
+
+
+/**
+ * @return {?Array|undefined} The version regex matches from parsing the user
+ * agent string. These regex statements must be executed inline so they can
+ * be compiled out by the closure compiler with the rest of the useragent
+ * detection logic when ASSUME_* is specified.
+ * @private
+ */
+goog.userAgent.getVersionRegexResult_ = function() {
+ var userAgent = goog.userAgent.getUserAgentString();
+ if (goog.userAgent.GECKO) {
+ return /rv\:([^\);]+)(\)|;)/.exec(userAgent);
+ }
+ if (goog.userAgent.EDGE) {
+ return /Edge\/([\d\.]+)/.exec(userAgent);
+ }
+ if (goog.userAgent.IE) {
+ return /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(userAgent);
+ }
+ if (goog.userAgent.WEBKIT) {
+ // WebKit/125.4
+ return /WebKit\/(\S+)/.exec(userAgent);
+ }
+ if (goog.userAgent.OPERA) {
+ // If none of the above browsers were detected but the browser is Opera, the
+ // only string that is of interest is 'Version/<number>'.
+ return /(?:Version)[ \/]?(\S+)/.exec(userAgent);
+ }
+ return undefined;
+};
+
+
+/**
+ * @return {number|undefined} Returns the document mode (for testing).
+ * @private
+ */
+goog.userAgent.getDocumentMode_ = function() {
+ // NOTE(user): goog.userAgent may be used in context where there is no DOM.
+ var doc = goog.global['document'];
+ return doc ? doc['documentMode'] : undefined;
+};
+
+
+/**
+ * The version of the user agent. This is a string because it might contain
+ * 'b' (as in beta) as well as multiple dots.
+ * @type {string}
+ */
+goog.userAgent.VERSION = goog.userAgent.determineVersion_();
+
+
+/**
+ * Compares two version numbers.
+ *
+ * @param {string} v1 Version of first item.
+ * @param {string} v2 Version of second item.
+ *
+ * @return {number} 1 if first argument is higher
+ * 0 if arguments are equal
+ * -1 if second argument is higher.
+ * @deprecated Use goog.string.compareVersions.
+ */
+goog.userAgent.compare = function(v1, v2) {
+ return goog.string.compareVersions(v1, v2);
+};
+
+
+/**
+ * Cache for {@link goog.userAgent.isVersionOrHigher}.
+ * Calls to compareVersions are surprisingly expensive and, as a browser's
+ * version number is unlikely to change during a session, we cache the results.
+ * @const
+ * @private
+ */
+goog.userAgent.isVersionOrHigherCache_ = {};
+
+
+/**
+ * Whether the user agent version is higher or the same as the given version.
+ * NOTE: When checking the version numbers for Firefox and Safari, be sure to
+ * use the engine's version, not the browser's version number. For example,
+ * Firefox 3.0 corresponds to Gecko 1.9 and Safari 3.0 to Webkit 522.11.
+ * Opera and Internet Explorer versions match the product release number.<br>
+ * @see <a href="http://en.wikipedia.org/wiki/Safari_version_history">
+ * Webkit</a>
+ * @see <a href="http://en.wikipedia.org/wiki/Gecko_engine">Gecko</a>
+ *
+ * @param {string|number} version The version to check.
+ * @return {boolean} Whether the user agent version is higher or the same as
+ * the given version.
+ */
+goog.userAgent.isVersionOrHigher = function(version) {
+ return goog.userAgent.ASSUME_ANY_VERSION ||
+ goog.userAgent.isVersionOrHigherCache_[version] ||
+ (goog.userAgent.isVersionOrHigherCache_[version] =
+ goog.string.compareVersions(goog.userAgent.VERSION, version) >= 0);
+};
+
+
+/**
+ * Deprecated alias to {@code goog.userAgent.isVersionOrHigher}.
+ * @param {string|number} version The version to check.
+ * @return {boolean} Whether the user agent version is higher or the same as
+ * the given version.
+ * @deprecated Use goog.userAgent.isVersionOrHigher().
+ */
+goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher;
+
+
+/**
+ * Whether the IE effective document mode is higher or the same as the given
+ * document mode version.
+ * NOTE: Only for IE, return false for another browser.
+ *
+ * @param {number} documentMode The document mode version to check.
+ * @return {boolean} Whether the IE effective document mode is higher or the
+ * same as the given version.
+ */
+goog.userAgent.isDocumentModeOrHigher = function(documentMode) {
+ return Number(goog.userAgent.DOCUMENT_MODE) >= documentMode;
+};
+
+
+/**
+ * Deprecated alias to {@code goog.userAgent.isDocumentModeOrHigher}.
+ * @param {number} version The version to check.
+ * @return {boolean} Whether the IE effective document mode is higher or the
+ * same as the given version.
+ * @deprecated Use goog.userAgent.isDocumentModeOrHigher().
+ */
+goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher;
+
+
+/**
+ * For IE version < 7, documentMode is undefined, so attempt to use the
+ * CSS1Compat property to see if we are in standards mode. If we are in
+ * standards mode, treat the browser version as the document mode. Otherwise,
+ * IE is emulating version 5.
+ * @type {number|undefined}
+ * @const
+ */
+goog.userAgent.DOCUMENT_MODE = (function() {
+ var doc = goog.global['document'];
+ var mode = goog.userAgent.getDocumentMode_();
+ if (!doc || !goog.userAgent.IE) {
+ return undefined;
+ }
+ return mode || (doc['compatMode'] == 'CSS1Compat' ?
+ parseInt(goog.userAgent.VERSION, 10) :
+ 5);
+})();
+
+goog.provide('ol.dom');
+
+goog.require('goog.asserts');
+goog.require('goog.userAgent');
+goog.require('goog.vec.Mat4');
+goog.require('ol');
+
+
+/**
+ * Create an html canvas element and returns its 2d context.
+ * @param {number=} opt_width Canvas width.
+ * @param {number=} opt_height Canvas height.
+ * @return {CanvasRenderingContext2D} The context.
+ */
+ol.dom.createCanvasContext2D = function(opt_width, opt_height) {
+ var canvas = document.createElement('CANVAS');
+ if (opt_width) {
+ canvas.width = opt_width;
+ }
+ if (opt_height) {
+ canvas.height = opt_height;
+ }
+ return canvas.getContext('2d');
+};
+
+
+/**
+ * Detect 2d transform.
+ * Adapted from http://stackoverflow.com/q/5661671/130442
+ * http://caniuse.com/#feat=transforms2d
+ * @return {boolean}
+ */
+ol.dom.canUseCssTransform = (function() {
+ var canUseCssTransform;
+ return function() {
+ if (canUseCssTransform === undefined) {
+ goog.asserts.assert(document.body,
+ 'document.body should not be null');
+ goog.asserts.assert(ol.global.getComputedStyle,
+ 'getComputedStyle is required (unsupported browser?)');
+
+ var el = document.createElement('P'),
+ has2d,
+ transforms = {
+ 'webkitTransform': '-webkit-transform',
+ 'OTransform': '-o-transform',
+ 'msTransform': '-ms-transform',
+ 'MozTransform': '-moz-transform',
+ 'transform': 'transform'
+ };
+ document.body.appendChild(el);
+ for (var t in transforms) {
+ if (t in el.style) {
+ el.style[t] = 'translate(1px,1px)';
+ has2d = ol.global.getComputedStyle(el).getPropertyValue(
+ transforms[t]);
+ }
+ }
+ document.body.removeChild(el);
+
+ canUseCssTransform = (has2d && has2d !== 'none');
+ }
+ return canUseCssTransform;
+ };
+}());
+
+
+/**
+ * Detect 3d transform.
+ * Adapted from http://stackoverflow.com/q/5661671/130442
+ * http://caniuse.com/#feat=transforms3d
+ * @return {boolean}
+ */
+ol.dom.canUseCssTransform3D = (function() {
+ var canUseCssTransform3D;
+ return function() {
+ if (canUseCssTransform3D === undefined) {
+ goog.asserts.assert(document.body,
+ 'document.body should not be null');
+ goog.asserts.assert(ol.global.getComputedStyle,
+ 'getComputedStyle is required (unsupported browser?)');
+
+ var el = document.createElement('P'),
+ has3d,
+ transforms = {
+ 'webkitTransform': '-webkit-transform',
+ 'OTransform': '-o-transform',
+ 'msTransform': '-ms-transform',
+ 'MozTransform': '-moz-transform',
+ 'transform': 'transform'
+ };
+ document.body.appendChild(el);
+ for (var t in transforms) {
+ if (t in el.style) {
+ el.style[t] = 'translate3d(1px,1px,1px)';
+ has3d = ol.global.getComputedStyle(el).getPropertyValue(
+ transforms[t]);
+ }
+ }
+ document.body.removeChild(el);
+
+ canUseCssTransform3D = (has3d && has3d !== 'none');
+ }
+ return canUseCssTransform3D;
+ };
+}());
+
+
+/**
+ * @param {Element} element Element.
+ * @param {string} value Value.
+ */
+ol.dom.setTransform = function(element, value) {
+ var style = element.style;
+ style.WebkitTransform = value;
+ style.MozTransform = value;
+ style.OTransform = value;
+ style.msTransform = value;
+ style.transform = value;
+
+ // IE 9+ seems to assume transform-origin: 100% 100%; for some unknown reason
+ if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9.0')) {
+ element.style.transformOrigin = '0 0';
+ }
+};
+
+
+/**
+ * @param {!Element} element Element.
+ * @param {goog.vec.Mat4.Number} transform Matrix.
+ * @param {number=} opt_precision Precision.
+ */
+ol.dom.transformElement2D = function(element, transform, opt_precision) {
+ // using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer
+ // matrix3d()
+ var i;
+ if (ol.dom.canUseCssTransform3D()) {
+ var value3D;
+
+ if (opt_precision !== undefined) {
+ /** @type {Array.<string>} */
+ var strings3D = new Array(16);
+ for (i = 0; i < 16; ++i) {
+ strings3D[i] = transform[i].toFixed(opt_precision);
+ }
+ value3D = strings3D.join(',');
+ } else {
+ value3D = transform.join(',');
+ }
+ ol.dom.setTransform(element, 'matrix3d(' + value3D + ')');
+ } else if (ol.dom.canUseCssTransform()) {
+ /** @type {Array.<number>} */
+ var transform2D = [
+ goog.vec.Mat4.getElement(transform, 0, 0),
+ goog.vec.Mat4.getElement(transform, 1, 0),
+ goog.vec.Mat4.getElement(transform, 0, 1),
+ goog.vec.Mat4.getElement(transform, 1, 1),
+ goog.vec.Mat4.getElement(transform, 0, 3),
+ goog.vec.Mat4.getElement(transform, 1, 3)
+ ];
+ var value2D;
+ if (opt_precision !== undefined) {
+ /** @type {Array.<string>} */
+ var strings2D = new Array(6);
+ for (i = 0; i < 6; ++i) {
+ strings2D[i] = transform2D[i].toFixed(opt_precision);
+ }
+ value2D = strings2D.join(',');
+ } else {
+ value2D = transform2D.join(',');
+ }
+ ol.dom.setTransform(element, 'matrix(' + value2D + ')');
+ } else {
+ element.style.left =
+ Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px';
+ element.style.top =
+ Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px';
+
+ // TODO: Add scaling here. This isn't quite as simple as multiplying
+ // width/height, because that only changes the container size, not the
+ // content size.
+ }
+};
+
+
+/**
+ * Get the current computed width for the given element including margin,
+ * padding and border.
+ * Equivalent to jQuery's `$(el).outerWidth(true)`.
+ * @param {!Element} element Element.
+ * @return {number} The width.
+ */
+ol.dom.outerWidth = function(element) {
+ var width = element.offsetWidth;
+ var style = element.currentStyle || ol.global.getComputedStyle(element);
+ width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
+
+ return width;
+};
+
+
+/**
+ * Get the current computed height for the given element including margin,
+ * padding and border.
+ * Equivalent to jQuery's `$(el).outerHeight(true)`.
+ * @param {!Element} element Element.
+ * @return {number} The height.
+ */
+ol.dom.outerHeight = function(element) {
+ var height = element.offsetHeight;
+ var style = element.currentStyle || ol.global.getComputedStyle(element);
+ height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
+
+ return height;
+};
+
+/**
+ * @param {Node} newNode Node to replace old node
+ * @param {Node} oldNode The node to be replaced
+ */
+ol.dom.replaceNode = function(newNode, oldNode) {
+ var parent = oldNode.parentNode;
+ if (parent) {
+ parent.replaceChild(newNode, oldNode);
+ }
+};
+
+/**
+ * @param {Node} node The node to remove.
+ * @returns {Node} The node that was removed or null.
+ */
+ol.dom.removeNode = function(node) {
+ return node && node.parentNode ? node.parentNode.removeChild(node) : null;
+};
+
+/**
+ * @param {Node} node The node to remove the children from.
+ */
+ol.dom.removeChildren = function(node) {
+ while (node.lastChild) {
+ node.removeChild(node.lastChild);
+ }
+};
+
+goog.provide('ol.MapEvent');
+goog.provide('ol.MapEventType');
+
+goog.require('ol.events.Event');
+
+
+/**
+ * @enum {string}
+ */
+ol.MapEventType = {
+
+ /**
+ * Triggered after a map frame is rendered.
+ * @event ol.MapEvent#postrender
+ * @api
+ */
+ POSTRENDER: 'postrender',
+
+ /**
+ * Triggered after the map is moved.
+ * @event ol.MapEvent#moveend
+ * @api stable
+ */
+ MOVEEND: 'moveend'
+
+};
+
+
+/**
+ * @classdesc
+ * Events emitted as map events are instances of this type.
+ * See {@link ol.Map} for which events trigger a map event.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.MapEvent}
+ * @param {string} type Event type.
+ * @param {ol.Map} map Map.
+ * @param {?olx.FrameState=} opt_frameState Frame state.
+ */
+ol.MapEvent = function(type, map, opt_frameState) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The map where the event occurred.
+ * @type {ol.Map}
+ * @api stable
+ */
+ this.map = map;
+
+ /**
+ * The frame state at the time of the event.
+ * @type {?olx.FrameState}
+ * @api
+ */
+ this.frameState = opt_frameState !== undefined ? opt_frameState : null;
+
+};
+ol.inherits(ol.MapEvent, ol.events.Event);
+
+goog.provide('ol.control.Control');
+
+goog.require('ol.events');
+goog.require('ol');
+goog.require('ol.MapEventType');
+goog.require('ol.Object');
+goog.require('ol.dom');
+
+
+/**
+ * @classdesc
+ * A control is a visible widget with a DOM element in a fixed position on the
+ * screen. They can involve user input (buttons), or be informational only;
+ * the position is determined using CSS. By default these are placed in the
+ * container with CSS class name `ol-overlaycontainer-stopevent`, but can use
+ * any outside DOM element.
+ *
+ * This is the base class for controls. You can use it for simple custom
+ * controls by creating the element with listeners, creating an instance:
+ * ```js
+ * var myControl = new ol.control.Control({element: myElement});
+ * ```
+ * and then adding this to the map.
+ *
+ * The main advantage of having this as a control rather than a simple separate
+ * DOM element is that preventing propagation is handled for you. Controls
+ * will also be `ol.Object`s in a `ol.Collection`, so you can use their
+ * methods.
+ *
+ * You can also extend this base for your own control class. See
+ * examples/custom-controls for an example of how to do this.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @implements {oli.control.Control}
+ * @param {olx.control.ControlOptions} options Control options.
+ * @api stable
+ */
+ol.control.Control = function(options) {
+
+ ol.Object.call(this);
+
+ /**
+ * @protected
+ * @type {Element}
+ */
+ this.element = options.element ? options.element : null;
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.target_ = null;
+
+ /**
+ * @private
+ * @type {ol.Map}
+ */
+ this.map_ = null;
+
+ /**
+ * @protected
+ * @type {!Array.<ol.EventsKey>}
+ */
+ this.listenerKeys = [];
+
+ /**
+ * @type {function(ol.MapEvent)}
+ */
+ this.render = options.render ? options.render : ol.nullFunction;
+
+ if (options.target) {
+ this.setTarget(options.target);
+ }
+
+};
+ol.inherits(ol.control.Control, ol.Object);
+
+
+/**
+ * @inheritDoc
+ */
+ol.control.Control.prototype.disposeInternal = function() {
+ ol.dom.removeNode(this.element);
+ ol.Object.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * Get the map associated with this control.
+ * @return {ol.Map} Map.
+ * @api stable
+ */
+ol.control.Control.prototype.getMap = function() {
+ return this.map_;
+};
+
+
+/**
+ * Remove the control from its current map and attach it to the new map.
+ * Subclasses may set up event handlers to get notified about changes to
+ * the map here.
+ * @param {ol.Map} map Map.
+ * @api stable
+ */
+ol.control.Control.prototype.setMap = function(map) {
+ if (this.map_) {
+ ol.dom.removeNode(this.element);
+ }
+ for (var i = 0, ii = this.listenerKeys.length; i < ii; ++i) {
+ ol.events.unlistenByKey(this.listenerKeys[i]);
+ }
+ this.listenerKeys.length = 0;
+ this.map_ = map;
+ if (this.map_) {
+ var target = this.target_ ?
+ this.target_ : map.getOverlayContainerStopEvent();
+ target.appendChild(this.element);
+ if (this.render !== ol.nullFunction) {
+ this.listenerKeys.push(ol.events.listen(map,
+ ol.MapEventType.POSTRENDER, this.render, this));
+ }
+ map.render();
+ }
+};
+
+
+/**
+ * This function is used to set a target element for the control. It has no
+ * effect if it is called after the control has been added to the map (i.e.
+ * after `setMap` is called on the control). If no `target` is set in the
+ * options passed to the control constructor and if `setTarget` is not called
+ * then the control is added to the map's overlay container.
+ * @param {Element|string} target Target.
+ * @api
+ */
+ol.control.Control.prototype.setTarget = function(target) {
+ this.target_ = typeof target === 'string' ?
+ document.getElementById(target) :
+ target;
+};
+
+goog.provide('ol.css');
+
+
+/**
+ * The CSS class for hidden feature.
+ *
+ * @const
+ * @type {string}
+ */
+ol.css.CLASS_HIDDEN = 'ol-hidden';
+
+
+/**
+ * The CSS class that we'll give the DOM elements to have them unselectable.
+ *
+ * @const
+ * @type {string}
+ */
+ol.css.CLASS_UNSELECTABLE = 'ol-unselectable';
+
+
+/**
+ * The CSS class for unsupported feature.
+ *
+ * @const
+ * @type {string}
+ */
+ol.css.CLASS_UNSUPPORTED = 'ol-unsupported';
+
+
+/**
+ * The CSS class for controls.
+ *
+ * @const
+ * @type {string}
+ */
+ol.css.CLASS_CONTROL = 'ol-control';
+
+goog.provide('ol.structs.LRUCache');
+
+goog.require('goog.asserts');
+goog.require('ol.object');
+
+
+/**
+ * Implements a Least-Recently-Used cache where the keys do not conflict with
+ * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring
+ * items from the cache is the responsibility of the user.
+ * @constructor
+ * @struct
+ * @template T
+ */
+ol.structs.LRUCache = function() {
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.count_ = 0;
+
+ /**
+ * @private
+ * @type {!Object.<string, ol.LRUCacheEntry>}
+ */
+ this.entries_ = {};
+
+ /**
+ * @private
+ * @type {?ol.LRUCacheEntry}
+ */
+ this.oldest_ = null;
+
+ /**
+ * @private
+ * @type {?ol.LRUCacheEntry}
+ */
+ this.newest_ = null;
+
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.structs.LRUCache.prototype.assertValid = function() {
+ if (this.count_ === 0) {
+ goog.asserts.assert(ol.object.isEmpty(this.entries_),
+ 'entries must be an empty object (count = 0)');
+ goog.asserts.assert(!this.oldest_,
+ 'oldest must be null (count = 0)');
+ goog.asserts.assert(!this.newest_,
+ 'newest must be null (count = 0)');
+ } else {
+ goog.asserts.assert(Object.keys(this.entries_).length == this.count_,
+ 'number of entries matches count');
+ goog.asserts.assert(this.oldest_,
+ 'we have an oldest entry');
+ goog.asserts.assert(!this.oldest_.older,
+ 'no entry is older than oldest');
+ goog.asserts.assert(this.newest_,
+ 'we have a newest entry');
+ goog.asserts.assert(!this.newest_.newer,
+ 'no entry is newer than newest');
+ var i, entry;
+ var older = null;
+ i = 0;
+ for (entry = this.oldest_; entry; entry = entry.newer) {
+ goog.asserts.assert(entry.older === older,
+ 'entry.older links to correct older');
+ older = entry;
+ ++i;
+ }
+ goog.asserts.assert(i == this.count_, 'iterated correct amount of times');
+ var newer = null;
+ i = 0;
+ for (entry = this.newest_; entry; entry = entry.older) {
+ goog.asserts.assert(entry.newer === newer,
+ 'entry.newer links to correct newer');
+ newer = entry;
+ ++i;
+ }
+ goog.asserts.assert(i == this.count_, 'iterated correct amount of times');
+ }
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.structs.LRUCache.prototype.clear = function() {
+ this.count_ = 0;
+ this.entries_ = {};
+ this.oldest_ = null;
+ this.newest_ = null;
+};
+
+
+/**
+ * @param {string} key Key.
+ * @return {boolean} Contains key.
+ */
+ol.structs.LRUCache.prototype.containsKey = function(key) {
+ return this.entries_.hasOwnProperty(key);
+};
+
+
+/**
+ * @param {function(this: S, T, string, ol.structs.LRUCache): ?} f The function
+ * to call for every entry from the oldest to the newer. This function takes
+ * 3 arguments (the entry value, the entry key and the LRUCache object).
+ * The return value is ignored.
+ * @param {S=} opt_this The object to use as `this` in `f`.
+ * @template S
+ */
+ol.structs.LRUCache.prototype.forEach = function(f, opt_this) {
+ var entry = this.oldest_;
+ while (entry) {
+ f.call(opt_this, entry.value_, entry.key_, this);
+ entry = entry.newer;
+ }
+};
+
+
+/**
+ * @param {string} key Key.
+ * @return {T} Value.
+ */
+ol.structs.LRUCache.prototype.get = function(key) {
+ var entry = this.entries_[key];
+ goog.asserts.assert(entry !== undefined, 'an entry exists for key %s', key);
+ if (entry === this.newest_) {
+ return entry.value_;
+ } else if (entry === this.oldest_) {
+ this.oldest_ = /** @type {ol.LRUCacheEntry} */ (this.oldest_.newer);
+ this.oldest_.older = null;
+ } else {
+ entry.newer.older = entry.older;
+ entry.older.newer = entry.newer;
+ }
+ entry.newer = null;
+ entry.older = this.newest_;
+ this.newest_.newer = entry;
+ this.newest_ = entry;
+ return entry.value_;
+};
+
+
+/**
+ * @return {number} Count.
+ */
+ol.structs.LRUCache.prototype.getCount = function() {
+ return this.count_;
+};
+
+
+/**
+ * @return {Array.<string>} Keys.
+ */
+ol.structs.LRUCache.prototype.getKeys = function() {
+ var keys = new Array(this.count_);
+ var i = 0;
+ var entry;
+ for (entry = this.newest_; entry; entry = entry.older) {
+ keys[i++] = entry.key_;
+ }
+ goog.asserts.assert(i == this.count_, 'iterated correct number of times');
+ return keys;
+};
+
+
+/**
+ * @return {Array.<T>} Values.
+ */
+ol.structs.LRUCache.prototype.getValues = function() {
+ var values = new Array(this.count_);
+ var i = 0;
+ var entry;
+ for (entry = this.newest_; entry; entry = entry.older) {
+ values[i++] = entry.value_;
+ }
+ goog.asserts.assert(i == this.count_, 'iterated correct number of times');
+ return values;
+};
+
+
+/**
+ * @return {T} Last value.
+ */
+ol.structs.LRUCache.prototype.peekLast = function() {
+ goog.asserts.assert(this.oldest_, 'oldest must not be null');
+ return this.oldest_.value_;
+};
+
+
+/**
+ * @return {string} Last key.
+ */
+ol.structs.LRUCache.prototype.peekLastKey = function() {
+ goog.asserts.assert(this.oldest_, 'oldest must not be null');
+ return this.oldest_.key_;
+};
+
+
+/**
+ * @return {T} value Value.
+ */
+ol.structs.LRUCache.prototype.pop = function() {
+ goog.asserts.assert(this.oldest_, 'oldest must not be null');
+ goog.asserts.assert(this.newest_, 'newest must not be null');
+ var entry = this.oldest_;
+ goog.asserts.assert(entry.key_ in this.entries_,
+ 'oldest is indexed in entries');
+ delete this.entries_[entry.key_];
+ if (entry.newer) {
+ entry.newer.older = null;
+ }
+ this.oldest_ = /** @type {ol.LRUCacheEntry} */ (entry.newer);
+ if (!this.oldest_) {
+ this.newest_ = null;
+ }
+ --this.count_;
+ return entry.value_;
+};
+
+
+/**
+ * @param {string} key Key.
+ * @param {T} value Value.
+ */
+ol.structs.LRUCache.prototype.replace = function(key, value) {
+ this.get(key); // update `newest_`
+ this.entries_[key].value_ = value;
+};
+
+
+/**
+ * @param {string} key Key.
+ * @param {T} value Value.
+ */
+ol.structs.LRUCache.prototype.set = function(key, value) {
+ goog.asserts.assert(!(key in {}),
+ 'key is not a standard property of objects (e.g. "__proto__")');
+ goog.asserts.assert(!(key in this.entries_),
+ 'key is not used already');
+ var entry = /** @type {ol.LRUCacheEntry} */ ({
+ key_: key,
+ newer: null,
+ older: this.newest_,
+ value_: value
+ });
+ if (!this.newest_) {
+ this.oldest_ = entry;
+ } else {
+ this.newest_.newer = entry;
+ }
+ this.newest_ = entry;
+ this.entries_[key] = entry;
+ ++this.count_;
+};
+
+goog.provide('ol.tilecoord');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+
+
+/**
+ * @enum {number}
+ */
+ol.QuadKeyCharCode = {
+ ZERO: '0'.charCodeAt(0),
+ ONE: '1'.charCodeAt(0),
+ TWO: '2'.charCodeAt(0),
+ THREE: '3'.charCodeAt(0)
+};
+
+
+/**
+ * @param {string} str String that follows pattern “z/x/y” where x, y and z are
+ * numbers.
+ * @return {ol.TileCoord} Tile coord.
+ */
+ol.tilecoord.createFromString = function(str) {
+ var v = str.split('/');
+ goog.asserts.assert(v.length === 3,
+ 'must provide a string in "z/x/y" format, got "%s"', str);
+ return v.map(function(e) {
+ return parseInt(e, 10);
+ });
+};
+
+
+/**
+ * @param {number} z Z.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {ol.TileCoord=} opt_tileCoord Tile coordinate.
+ * @return {ol.TileCoord} Tile coordinate.
+ */
+ol.tilecoord.createOrUpdate = function(z, x, y, opt_tileCoord) {
+ if (opt_tileCoord !== undefined) {
+ opt_tileCoord[0] = z;
+ opt_tileCoord[1] = x;
+ opt_tileCoord[2] = y;
+ return opt_tileCoord;
+ } else {
+ return [z, x, y];
+ }
+};
+
+
+/**
+ * @param {number} z Z.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {string} Key.
+ */
+ol.tilecoord.getKeyZXY = function(z, x, y) {
+ return z + '/' + x + '/' + y;
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coord.
+ * @return {number} Hash.
+ */
+ol.tilecoord.hash = function(tileCoord) {
+ return (tileCoord[1] << tileCoord[0]) + tileCoord[2];
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coord.
+ * @return {string} Quad key.
+ */
+ol.tilecoord.quadKey = function(tileCoord) {
+ var z = tileCoord[0];
+ var digits = new Array(z);
+ var mask = 1 << (z - 1);
+ var i, charCode;
+ for (i = 0; i < z; ++i) {
+ charCode = ol.QuadKeyCharCode.ZERO;
+ if (tileCoord[1] & mask) {
+ charCode += 1;
+ }
+ if (tileCoord[2] & mask) {
+ charCode += 2;
+ }
+ digits[i] = String.fromCharCode(charCode);
+ mask >>= 1;
+ }
+ return digits.join('');
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.TileCoord} Tile coordinate.
+ */
+ol.tilecoord.wrapX = function(tileCoord, tileGrid, projection) {
+ var z = tileCoord[0];
+ var center = tileGrid.getTileCoordCenter(tileCoord);
+ var projectionExtent = ol.tilegrid.extentFromProjection(projection);
+ if (!ol.extent.containsCoordinate(projectionExtent, center)) {
+ var worldWidth = ol.extent.getWidth(projectionExtent);
+ var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth);
+ center[0] += worldWidth * worldsAway;
+ return tileGrid.getTileCoordForCoordAndZ(center, z);
+ } else {
+ return tileCoord;
+ }
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @return {boolean} Tile coordinate is within extent and zoom level range.
+ */
+ol.tilecoord.withinExtentAndZ = function(tileCoord, tileGrid) {
+ var z = tileCoord[0];
+ var x = tileCoord[1];
+ var y = tileCoord[2];
+
+ if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) {
+ return false;
+ }
+ var extent = tileGrid.getExtent();
+ var tileRange;
+ if (!extent) {
+ tileRange = tileGrid.getFullTileRange(z);
+ } else {
+ tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
+ }
+ if (!tileRange) {
+ return true;
+ } else {
+ return tileRange.containsXY(x, y);
+ }
+};
+
+goog.provide('ol.TileCache');
+
+goog.require('ol.TileRange');
+goog.require('ol.structs.LRUCache');
+goog.require('ol.tilecoord');
+
+
+/**
+ * @constructor
+ * @extends {ol.structs.LRUCache.<ol.Tile>}
+ * @param {number=} opt_highWaterMark High water mark.
+ * @struct
+ */
+ol.TileCache = function(opt_highWaterMark) {
+
+ ol.structs.LRUCache.call(this);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.highWaterMark_ = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;
+
+};
+ol.inherits(ol.TileCache, ol.structs.LRUCache);
+
+
+/**
+ * @return {boolean} Can expire cache.
+ */
+ol.TileCache.prototype.canExpireCache = function() {
+ return this.getCount() > this.highWaterMark_;
+};
+
+
+/**
+ * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.
+ */
+ol.TileCache.prototype.expireCache = function(usedTiles) {
+ var tile, zKey;
+ while (this.canExpireCache()) {
+ tile = this.peekLast();
+ zKey = tile.tileCoord[0].toString();
+ if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) {
+ break;
+ } else {
+ this.pop().dispose();
+ }
+ }
+};
+
+
+/**
+ * Remove a tile range from the cache, e.g. to invalidate tiles.
+ * @param {ol.TileRange} tileRange The tile range to prune.
+ */
+ol.TileCache.prototype.pruneTileRange = function(tileRange) {
+ var i = this.getCount(),
+ key;
+ while (i--) {
+ key = this.peekLastKey();
+ if (tileRange.contains(ol.tilecoord.createFromString(key))) {
+ this.pop().dispose();
+ } else {
+ this.get(key);
+ }
+ }
+};
+
+goog.provide('ol.Tile');
+goog.provide('ol.TileState');
+
+goog.require('ol.events');
+goog.require('ol.events.EventTarget');
+goog.require('ol.events.EventType');
+
+
+/**
+ * @enum {number}
+ */
+ol.TileState = {
+ IDLE: 0,
+ LOADING: 1,
+ LOADED: 2,
+ ERROR: 3,
+ EMPTY: 4,
+ ABORT: 5
+};
+
+
+/**
+ * @classdesc
+ * Base class for tiles.
+ *
+ * @constructor
+ * @extends {ol.events.EventTarget}
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.TileState} state State.
+ */
+ol.Tile = function(tileCoord, state) {
+
+ ol.events.EventTarget.call(this);
+
+ /**
+ * @type {ol.TileCoord}
+ */
+ this.tileCoord = tileCoord;
+
+ /**
+ * @protected
+ * @type {ol.TileState}
+ */
+ this.state = state;
+
+ /**
+ * An "interim" tile for this tile. The interim tile may be used while this
+ * one is loading, for "smooth" transitions when changing params/dimensions
+ * on the source.
+ * @type {ol.Tile}
+ */
+ this.interimTile = null;
+
+ /**
+ * A key assigned to the tile. This is used by the tile source to determine
+ * if this tile can effectively be used, or if a new tile should be created
+ * and this one be used as an interim tile for this new tile.
+ * @type {string}
+ */
+ this.key = '';
+
+};
+ol.inherits(ol.Tile, ol.events.EventTarget);
+
+
+/**
+ * @protected
+ */
+ol.Tile.prototype.changed = function() {
+ this.dispatchEvent(ol.events.EventType.CHANGE);
+};
+
+
+/**
+ * Get the HTML image element for this tile (may be a Canvas, Image, or Video).
+ * @function
+ * @param {Object=} opt_context Object.
+ * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
+ */
+ol.Tile.prototype.getImage = goog.abstractMethod;
+
+
+/**
+ * @return {string} Key.
+ */
+ol.Tile.prototype.getKey = function() {
+ return goog.getUid(this).toString();
+};
+
+
+/**
+ * Get the tile coordinate for this tile.
+ * @return {ol.TileCoord} The tile coordinate.
+ * @api
+ */
+ol.Tile.prototype.getTileCoord = function() {
+ return this.tileCoord;
+};
+
+
+/**
+ * @return {ol.TileState} State.
+ */
+ol.Tile.prototype.getState = function() {
+ return this.state;
+};
+
+
+/**
+ * Load the image or retry if loading previously failed.
+ * Loading is taken care of by the tile queue, and calling this method is
+ * only needed for preloading or for reloading in case of an error.
+ * @api
+ */
+ol.Tile.prototype.load = goog.abstractMethod;
+
+goog.provide('ol.size');
+
+
+goog.require('goog.asserts');
+
+
+/**
+ * Returns a buffered size.
+ * @param {ol.Size} size Size.
+ * @param {number} buffer Buffer.
+ * @param {ol.Size=} opt_size Optional reusable size array.
+ * @return {ol.Size} The buffered size.
+ */
+ol.size.buffer = function(size, buffer, opt_size) {
+ if (opt_size === undefined) {
+ opt_size = [0, 0];
+ }
+ opt_size[0] = size[0] + 2 * buffer;
+ opt_size[1] = size[1] + 2 * buffer;
+ return opt_size;
+};
+
+
+/**
+ * Compares sizes for equality.
+ * @param {ol.Size} a Size.
+ * @param {ol.Size} b Size.
+ * @return {boolean} Equals.
+ */
+ol.size.equals = function(a, b) {
+ return a[0] == b[0] && a[1] == b[1];
+};
+
+
+/**
+ * Determines if a size has a positive area.
+ * @param {ol.Size} size The size to test.
+ * @return {boolean} The size has a positive area.
+ */
+ol.size.hasArea = function(size) {
+ return size[0] > 0 && size[1] > 0;
+};
+
+
+/**
+ * Returns a size scaled by a ratio. The result will be an array of integers.
+ * @param {ol.Size} size Size.
+ * @param {number} ratio Ratio.
+ * @param {ol.Size=} opt_size Optional reusable size array.
+ * @return {ol.Size} The scaled size.
+ */
+ol.size.scale = function(size, ratio, opt_size) {
+ if (opt_size === undefined) {
+ opt_size = [0, 0];
+ }
+ opt_size[0] = (size[0] * ratio + 0.5) | 0;
+ opt_size[1] = (size[1] * ratio + 0.5) | 0;
+ return opt_size;
+};
+
+
+/**
+ * Returns an `ol.Size` array for the passed in number (meaning: square) or
+ * `ol.Size` array.
+ * (meaning: non-square),
+ * @param {number|ol.Size} size Width and height.
+ * @param {ol.Size=} opt_size Optional reusable size array.
+ * @return {ol.Size} Size.
+ * @api stable
+ */
+ol.size.toSize = function(size, opt_size) {
+ if (Array.isArray(size)) {
+ return size;
+ } else {
+ goog.asserts.assert(goog.isNumber(size));
+ if (opt_size === undefined) {
+ opt_size = [size, size];
+ } else {
+ opt_size[0] = size;
+ opt_size[1] = size;
+ }
+ return opt_size;
+ }
+};
+
+goog.provide('ol.source.Source');
+goog.provide('ol.source.State');
+
+goog.require('ol');
+goog.require('ol.Attribution');
+goog.require('ol.Object');
+goog.require('ol.proj');
+
+
+/**
+ * State of the source, one of 'undefined', 'loading', 'ready' or 'error'.
+ * @enum {string}
+ */
+ol.source.State = {
+ UNDEFINED: 'undefined',
+ LOADING: 'loading',
+ READY: 'ready',
+ ERROR: 'error'
+};
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for {@link ol.layer.Layer} sources.
+ *
+ * A generic `change` event is triggered when the state of the source changes.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {ol.SourceSourceOptions} options Source options.
+ * @api stable
+ */
+ol.source.Source = function(options) {
+
+ ol.Object.call(this);
+
+ /**
+ * @private
+ * @type {ol.proj.Projection}
+ */
+ this.projection_ = ol.proj.get(options.projection);
+
+ /**
+ * @private
+ * @type {Array.<ol.Attribution>}
+ */
+ this.attributions_ = ol.source.Source.toAttributionsArray_(options.attributions);
+
+ /**
+ * @private
+ * @type {string|olx.LogoOptions|undefined}
+ */
+ this.logo_ = options.logo;
+
+ /**
+ * @private
+ * @type {ol.source.State}
+ */
+ this.state_ = options.state !== undefined ?
+ options.state : ol.source.State.READY;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false;
+
+};
+ol.inherits(ol.source.Source, ol.Object);
+
+/**
+ * Turns various ways of defining an attribution to an array of `ol.Attributions`.
+ *
+ * @param {ol.AttributionLike|undefined}
+ * attributionLike The attributions as string, array of strings,
+ * `ol.Attribution`, array of `ol.Attribution` or undefined.
+ * @return {Array.<ol.Attribution>} The array of `ol.Attribution` or null if
+ * `undefined` was given.
+ */
+ol.source.Source.toAttributionsArray_ = function(attributionLike) {
+ if (typeof attributionLike === 'string') {
+ return [new ol.Attribution({html: attributionLike})];
+ } else if (attributionLike instanceof ol.Attribution) {
+ return [attributionLike];
+ } else if (Array.isArray(attributionLike)) {
+ var len = attributionLike.length;
+ var attributions = new Array(len);
+ for (var i = 0; i < len; i++) {
+ var item = attributionLike[i];
+ if (typeof item === 'string') {
+ attributions[i] = new ol.Attribution({html: item});
+ } else {
+ attributions[i] = item;
+ }
+ }
+ return attributions;
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {Object.<string, boolean>} skippedFeatureUids Skipped feature uids.
+ * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature
+ * callback.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.source.Source.prototype.forEachFeatureAtCoordinate = ol.nullFunction;
+
+
+/**
+ * Get the attributions of the source.
+ * @return {Array.<ol.Attribution>} Attributions.
+ * @api stable
+ */
+ol.source.Source.prototype.getAttributions = function() {
+ return this.attributions_;
+};
+
+
+/**
+ * Get the logo of the source.
+ * @return {string|olx.LogoOptions|undefined} Logo.
+ * @api stable
+ */
+ol.source.Source.prototype.getLogo = function() {
+ return this.logo_;
+};
+
+
+/**
+ * Get the projection of the source.
+ * @return {ol.proj.Projection} Projection.
+ * @api
+ */
+ol.source.Source.prototype.getProjection = function() {
+ return this.projection_;
+};
+
+
+/**
+ * @return {Array.<number>|undefined} Resolutions.
+ */
+ol.source.Source.prototype.getResolutions = goog.abstractMethod;
+
+
+/**
+ * Get the state of the source, see {@link ol.source.State} for possible states.
+ * @return {ol.source.State} State.
+ * @api
+ */
+ol.source.Source.prototype.getState = function() {
+ return this.state_;
+};
+
+
+/**
+ * @return {boolean|undefined} Wrap X.
+ */
+ol.source.Source.prototype.getWrapX = function() {
+ return this.wrapX_;
+};
+
+
+/**
+ * Refreshes the source and finally dispatches a 'change' event.
+ * @api
+ */
+ol.source.Source.prototype.refresh = function() {
+ this.changed();
+};
+
+
+/**
+ * Set the attributions of the source.
+ * @param {ol.AttributionLike|undefined} attributions Attributions.
+ * Can be passed as `string`, `Array<string>`, `{@link ol.Attribution}`,
+ * `Array<{@link ol.Attribution}>` or `undefined`.
+ * @api
+ */
+ol.source.Source.prototype.setAttributions = function(attributions) {
+ this.attributions_ = ol.source.Source.toAttributionsArray_(attributions);
+ this.changed();
+};
+
+
+/**
+ * Set the logo of the source.
+ * @param {string|olx.LogoOptions|undefined} logo Logo.
+ */
+ol.source.Source.prototype.setLogo = function(logo) {
+ this.logo_ = logo;
+};
+
+
+/**
+ * Set the state of the source.
+ * @param {ol.source.State} state State.
+ * @protected
+ */
+ol.source.Source.prototype.setState = function(state) {
+ this.state_ = state;
+ this.changed();
+};
+
+goog.provide('ol.tilegrid.TileGrid');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.TileRange');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.extent.Corner');
+goog.require('ol.math');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.proj.METERS_PER_UNIT');
+goog.require('ol.proj.Projection');
+goog.require('ol.proj.Units');
+goog.require('ol.size');
+goog.require('ol.tilecoord');
+
+
+/**
+ * @classdesc
+ * Base class for setting the grid pattern for sources accessing tiled-image
+ * servers.
+ *
+ * @constructor
+ * @param {olx.tilegrid.TileGridOptions} options Tile grid options.
+ * @struct
+ * @api stable
+ */
+ol.tilegrid.TileGrid = function(options) {
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.minZoom = options.minZoom !== undefined ? options.minZoom : 0;
+
+ /**
+ * @private
+ * @type {!Array.<number>}
+ */
+ this.resolutions_ = options.resolutions;
+ goog.asserts.assert(ol.array.isSorted(this.resolutions_, function(a, b) {
+ return b - a;
+ }, true), 'resolutions must be sorted in descending order');
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.maxZoom = this.resolutions_.length - 1;
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.origin_ = options.origin !== undefined ? options.origin : null;
+
+ /**
+ * @private
+ * @type {Array.<ol.Coordinate>}
+ */
+ this.origins_ = null;
+ if (options.origins !== undefined) {
+ this.origins_ = options.origins;
+ goog.asserts.assert(this.origins_.length == this.resolutions_.length,
+ 'number of origins and resolutions must be equal');
+ }
+
+ var extent = options.extent;
+
+ if (extent !== undefined &&
+ !this.origin_ && !this.origins_) {
+ this.origin_ = ol.extent.getTopLeft(extent);
+ }
+
+ goog.asserts.assert(
+ (!this.origin_ && this.origins_) ||
+ (this.origin_ && !this.origins_),
+ 'either origin or origins must be configured, never both');
+
+ /**
+ * @private
+ * @type {Array.<number|ol.Size>}
+ */
+ this.tileSizes_ = null;
+ if (options.tileSizes !== undefined) {
+ this.tileSizes_ = options.tileSizes;
+ goog.asserts.assert(this.tileSizes_.length == this.resolutions_.length,
+ 'number of tileSizes and resolutions must be equal');
+ }
+
+ /**
+ * @private
+ * @type {number|ol.Size}
+ */
+ this.tileSize_ = options.tileSize !== undefined ?
+ options.tileSize :
+ !this.tileSizes_ ? ol.DEFAULT_TILE_SIZE : null;
+ goog.asserts.assert(
+ (!this.tileSize_ && this.tileSizes_) ||
+ (this.tileSize_ && !this.tileSizes_),
+ 'either tileSize or tileSizes must be configured, never both');
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.extent_ = extent !== undefined ? extent : null;
+
+
+ /**
+ * @private
+ * @type {Array.<ol.TileRange>}
+ */
+ this.fullTileRanges_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.tmpSize_ = [0, 0];
+
+ if (options.sizes !== undefined) {
+ goog.asserts.assert(options.sizes.length == this.resolutions_.length,
+ 'number of sizes and resolutions must be equal');
+ this.fullTileRanges_ = options.sizes.map(function(size, z) {
+ goog.asserts.assert(size[0] !== 0, 'width must not be 0');
+ goog.asserts.assert(size[1] !== 0, 'height must not be 0');
+ var tileRange = new ol.TileRange(
+ Math.min(0, size[0]), Math.max(size[0] - 1, -1),
+ Math.min(0, size[1]), Math.max(size[1] - 1, -1));
+ if (this.minZoom <= z && z <= this.maxZoom && extent !== undefined) {
+ goog.asserts.assert(tileRange.containsTileRange(
+ this.getTileRangeForExtentAndZ(extent, z)),
+ 'extent tile range must not exceed tilegrid width and height');
+ }
+ return tileRange;
+ }, this);
+ } else if (extent) {
+ this.calculateTileRanges_(extent);
+ }
+
+};
+
+
+/**
+ * @private
+ * @type {ol.TileCoord}
+ */
+ol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0];
+
+
+/**
+ * Call a function with each tile coordinate for a given extent and zoom level.
+ *
+ * @param {ol.Extent} extent Extent.
+ * @param {number} zoom Zoom level.
+ * @param {function(ol.TileCoord)} callback Function called with each tile coordinate.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.forEachTileCoord = function(extent, zoom, callback) {
+ var tileRange = this.getTileRangeForExtentAndZ(extent, zoom);
+ for (var i = tileRange.minX, ii = tileRange.maxX; i <= ii; ++i) {
+ for (var j = tileRange.minY, jj = tileRange.maxY; j <= jj; ++j) {
+ callback([zoom, i, j]);
+ }
+ }
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {function(this: T, number, ol.TileRange): boolean} callback Callback.
+ * @param {T=} opt_this The object to use as `this` in `callback`.
+ * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.
+ * @param {ol.Extent=} opt_extent Temporary ol.Extent object.
+ * @return {boolean} Callback succeeded.
+ * @template T
+ */
+ol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange = function(tileCoord, callback, opt_this, opt_tileRange, opt_extent) {
+ var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent);
+ var z = tileCoord[0] - 1;
+ while (z >= this.minZoom) {
+ if (callback.call(opt_this, z,
+ this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange))) {
+ return true;
+ }
+ --z;
+ }
+ return false;
+};
+
+
+/**
+ * Get the extent for this tile grid, if it was configured.
+ * @return {ol.Extent} Extent.
+ */
+ol.tilegrid.TileGrid.prototype.getExtent = function() {
+ return this.extent_;
+};
+
+
+/**
+ * Get the maximum zoom level for the grid.
+ * @return {number} Max zoom.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.getMaxZoom = function() {
+ return this.maxZoom;
+};
+
+
+/**
+ * Get the minimum zoom level for the grid.
+ * @return {number} Min zoom.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.getMinZoom = function() {
+ return this.minZoom;
+};
+
+
+/**
+ * Get the origin for the grid at the given zoom level.
+ * @param {number} z Z.
+ * @return {ol.Coordinate} Origin.
+ * @api stable
+ */
+ol.tilegrid.TileGrid.prototype.getOrigin = function(z) {
+ if (this.origin_) {
+ return this.origin_;
+ } else {
+ goog.asserts.assert(this.origins_,
+ 'origins cannot be null if origin is null');
+ goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom,
+ 'given z is not in allowed range (%s <= %s <= %s)',
+ this.minZoom, z, this.maxZoom);
+ return this.origins_[z];
+ }
+};
+
+
+/**
+ * Get the resolution for the given zoom level.
+ * @param {number} z Z.
+ * @return {number} Resolution.
+ * @api stable
+ */
+ol.tilegrid.TileGrid.prototype.getResolution = function(z) {
+ goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom,
+ 'given z is not in allowed range (%s <= %s <= %s)',
+ this.minZoom, z, this.maxZoom);
+ return this.resolutions_[z];
+};
+
+
+/**
+ * Get the list of resolutions for the tile grid.
+ * @return {Array.<number>} Resolutions.
+ * @api stable
+ */
+ol.tilegrid.TileGrid.prototype.getResolutions = function() {
+ return this.resolutions_;
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.
+ * @param {ol.Extent=} opt_extent Temporary ol.Extent object.
+ * @return {ol.TileRange} Tile range.
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordChildTileRange = function(tileCoord, opt_tileRange, opt_extent) {
+ if (tileCoord[0] < this.maxZoom) {
+ var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent);
+ return this.getTileRangeForExtentAndZ(
+ tileCoordExtent, tileCoord[0] + 1, opt_tileRange);
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * @param {number} z Z.
+ * @param {ol.TileRange} tileRange Tile range.
+ * @param {ol.Extent=} opt_extent Temporary ol.Extent object.
+ * @return {ol.Extent} Extent.
+ */
+ol.tilegrid.TileGrid.prototype.getTileRangeExtent = function(z, tileRange, opt_extent) {
+ var origin = this.getOrigin(z);
+ var resolution = this.getResolution(z);
+ var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);
+ var minX = origin[0] + tileRange.minX * tileSize[0] * resolution;
+ var maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution;
+ var minY = origin[1] + tileRange.minY * tileSize[1] * resolution;
+ var maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution;
+ return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {ol.TileRange=} opt_tileRange Temporary tile range object.
+ * @return {ol.TileRange} Tile range.
+ */
+ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = function(extent, resolution, opt_tileRange) {
+ var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_;
+ this.getTileCoordForXYAndResolution_(
+ extent[0], extent[1], resolution, false, tileCoord);
+ var minX = tileCoord[1];
+ var minY = tileCoord[2];
+ this.getTileCoordForXYAndResolution_(
+ extent[2], extent[3], resolution, true, tileCoord);
+ return ol.TileRange.createOrUpdate(
+ minX, tileCoord[1], minY, tileCoord[2], opt_tileRange);
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} z Z.
+ * @param {ol.TileRange=} opt_tileRange Temporary tile range object.
+ * @return {ol.TileRange} Tile range.
+ */
+ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = function(extent, z, opt_tileRange) {
+ var resolution = this.getResolution(z);
+ return this.getTileRangeForExtentAndResolution(
+ extent, resolution, opt_tileRange);
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @return {ol.Coordinate} Tile center.
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) {
+ var origin = this.getOrigin(tileCoord[0]);
+ var resolution = this.getResolution(tileCoord[0]);
+ var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);
+ return [
+ origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution,
+ origin[1] + (tileCoord[2] + 0.5) * tileSize[1] * resolution
+ ];
+};
+
+
+/**
+ * Get the extent of a tile coordinate.
+ *
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.Extent=} opt_extent Temporary extent object.
+ * @return {ol.Extent} Extent.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordExtent = function(tileCoord, opt_extent) {
+ var origin = this.getOrigin(tileCoord[0]);
+ var resolution = this.getResolution(tileCoord[0]);
+ var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);
+ var minX = origin[0] + tileCoord[1] * tileSize[0] * resolution;
+ var minY = origin[1] + tileCoord[2] * tileSize[1] * resolution;
+ var maxX = minX + tileSize[0] * resolution;
+ var maxY = minY + tileSize[1] * resolution;
+ return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
+};
+
+
+/**
+ * Get the tile coordinate for the given map coordinate and resolution. This
+ * method considers that coordinates that intersect tile boundaries should be
+ * assigned the higher tile coordinate.
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} resolution Resolution.
+ * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object.
+ * @return {ol.TileCoord} Tile coordinate.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = function(coordinate, resolution, opt_tileCoord) {
+ return this.getTileCoordForXYAndResolution_(
+ coordinate[0], coordinate[1], resolution, false, opt_tileCoord);
+};
+
+
+/**
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @param {number} resolution Resolution.
+ * @param {boolean} reverseIntersectionPolicy Instead of letting edge
+ * intersections go to the higher tile coordinate, let edge intersections
+ * go to the lower tile coordinate.
+ * @param {ol.TileCoord=} opt_tileCoord Temporary ol.TileCoord object.
+ * @return {ol.TileCoord} Tile coordinate.
+ * @private
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function(
+ x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) {
+ var z = this.getZForResolution(resolution);
+ var scale = resolution / this.getResolution(z);
+ var origin = this.getOrigin(z);
+ var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);
+
+ var adjustX = reverseIntersectionPolicy ? 0.5 : 0;
+ var adjustY = reverseIntersectionPolicy ? 0 : 0.5;
+ var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX);
+ var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY);
+ var tileCoordX = scale * xFromOrigin / tileSize[0];
+ var tileCoordY = scale * yFromOrigin / tileSize[1];
+
+ if (reverseIntersectionPolicy) {
+ tileCoordX = Math.ceil(tileCoordX) - 1;
+ tileCoordY = Math.ceil(tileCoordY) - 1;
+ } else {
+ tileCoordX = Math.floor(tileCoordX);
+ tileCoordY = Math.floor(tileCoordY);
+ }
+
+ return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord);
+};
+
+
+/**
+ * Get a tile coordinate given a map coordinate and zoom level.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} z Zoom level.
+ * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object.
+ * @return {ol.TileCoord} Tile coordinate.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ = function(coordinate, z, opt_tileCoord) {
+ var resolution = this.getResolution(z);
+ return this.getTileCoordForXYAndResolution_(
+ coordinate[0], coordinate[1], resolution, false, opt_tileCoord);
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @return {number} Tile resolution.
+ */
+ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) {
+ goog.asserts.assert(
+ this.minZoom <= tileCoord[0] && tileCoord[0] <= this.maxZoom,
+ 'z of given tilecoord is not in allowed range (%s <= %s <= %s',
+ this.minZoom, tileCoord[0], this.maxZoom);
+ return this.resolutions_[tileCoord[0]];
+};
+
+
+/**
+ * Get the tile size for a zoom level. The type of the return value matches the
+ * `tileSize` or `tileSizes` that the tile grid was configured with. To always
+ * get an `ol.Size`, run the result through `ol.size.toSize()`.
+ * @param {number} z Z.
+ * @return {number|ol.Size} Tile size.
+ * @api stable
+ */
+ol.tilegrid.TileGrid.prototype.getTileSize = function(z) {
+ if (this.tileSize_) {
+ return this.tileSize_;
+ } else {
+ goog.asserts.assert(this.tileSizes_,
+ 'tileSizes cannot be null if tileSize is null');
+ goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom,
+ 'z is not in allowed range (%s <= %s <= %s',
+ this.minZoom, z, this.maxZoom);
+ return this.tileSizes_[z];
+ }
+};
+
+
+/**
+ * @param {number} z Zoom level.
+ * @return {ol.TileRange} Extent tile range for the specified zoom level.
+ */
+ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) {
+ if (!this.fullTileRanges_) {
+ return null;
+ } else {
+ goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom,
+ 'z is not in allowed range (%s <= %s <= %s',
+ this.minZoom, z, this.maxZoom);
+ return this.fullTileRanges_[z];
+ }
+};
+
+
+/**
+ * @param {number} resolution Resolution.
+ * @param {number=} opt_direction If 0, the nearest resolution will be used.
+ * If 1, the nearest lower resolution will be used. If -1, the nearest
+ * higher resolution will be used. Default is 0.
+ * @return {number} Z.
+ * @api
+ */
+ol.tilegrid.TileGrid.prototype.getZForResolution = function(
+ resolution, opt_direction) {
+ var z = ol.array.linearFindNearest(this.resolutions_, resolution,
+ opt_direction || 0);
+ return ol.math.clamp(z, this.minZoom, this.maxZoom);
+};
+
+
+/**
+ * @param {!ol.Extent} extent Extent for this tile grid.
+ * @private
+ */
+ol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) {
+ var length = this.resolutions_.length;
+ var fullTileRanges = new Array(length);
+ for (var z = this.minZoom; z < length; ++z) {
+ fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z);
+ }
+ this.fullTileRanges_ = fullTileRanges;
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.tilegrid.TileGrid} Default tile grid for the passed projection.
+ */
+ol.tilegrid.getForProjection = function(projection) {
+ var tileGrid = projection.getDefaultTileGrid();
+ if (!tileGrid) {
+ tileGrid = ol.tilegrid.createForProjection(projection);
+ projection.setDefaultTileGrid(tileGrid);
+ }
+ return tileGrid;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number=} opt_maxZoom Maximum zoom level (default is
+ * ol.DEFAULT_MAX_ZOOM).
+ * @param {number|ol.Size=} opt_tileSize Tile size (default uses
+ * ol.DEFAULT_TILE_SIZE).
+ * @param {ol.extent.Corner=} opt_corner Extent corner (default is
+ * ol.extent.Corner.TOP_LEFT).
+ * @return {ol.tilegrid.TileGrid} TileGrid instance.
+ */
+ol.tilegrid.createForExtent = function(extent, opt_maxZoom, opt_tileSize, opt_corner) {
+ var corner = opt_corner !== undefined ?
+ opt_corner : ol.extent.Corner.TOP_LEFT;
+
+ var resolutions = ol.tilegrid.resolutionsFromExtent(
+ extent, opt_maxZoom, opt_tileSize);
+
+ return new ol.tilegrid.TileGrid({
+ extent: extent,
+ origin: ol.extent.getCorner(extent, corner),
+ resolutions: resolutions,
+ tileSize: opt_tileSize
+ });
+};
+
+
+/**
+ * Creates a tile grid with a standard XYZ tiling scheme.
+ * @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options.
+ * @return {ol.tilegrid.TileGrid} Tile grid instance.
+ * @api
+ */
+ol.tilegrid.createXYZ = function(opt_options) {
+ var options = /** @type {olx.tilegrid.TileGridOptions} */ ({});
+ ol.object.assign(options, opt_options !== undefined ?
+ opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({}));
+ if (options.extent === undefined) {
+ options.extent = ol.proj.get('EPSG:3857').getExtent();
+ }
+ options.resolutions = ol.tilegrid.resolutionsFromExtent(
+ options.extent, options.maxZoom, options.tileSize);
+ delete options.maxZoom;
+
+ return new ol.tilegrid.TileGrid(options);
+};
+
+
+/**
+ * Create a resolutions array from an extent. A zoom factor of 2 is assumed.
+ * @param {ol.Extent} extent Extent.
+ * @param {number=} opt_maxZoom Maximum zoom level (default is
+ * ol.DEFAULT_MAX_ZOOM).
+ * @param {number|ol.Size=} opt_tileSize Tile size (default uses
+ * ol.DEFAULT_TILE_SIZE).
+ * @return {!Array.<number>} Resolutions array.
+ */
+ol.tilegrid.resolutionsFromExtent = function(extent, opt_maxZoom, opt_tileSize) {
+ var maxZoom = opt_maxZoom !== undefined ?
+ opt_maxZoom : ol.DEFAULT_MAX_ZOOM;
+
+ var height = ol.extent.getHeight(extent);
+ var width = ol.extent.getWidth(extent);
+
+ var tileSize = ol.size.toSize(opt_tileSize !== undefined ?
+ opt_tileSize : ol.DEFAULT_TILE_SIZE);
+ var maxResolution = Math.max(
+ width / tileSize[0], height / tileSize[1]);
+
+ var length = maxZoom + 1;
+ var resolutions = new Array(length);
+ for (var z = 0; z < length; ++z) {
+ resolutions[z] = maxResolution / Math.pow(2, z);
+ }
+ return resolutions;
+};
+
+
+/**
+ * @param {ol.ProjectionLike} projection Projection.
+ * @param {number=} opt_maxZoom Maximum zoom level (default is
+ * ol.DEFAULT_MAX_ZOOM).
+ * @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE).
+ * @param {ol.extent.Corner=} opt_corner Extent corner (default is
+ * ol.extent.Corner.BOTTOM_LEFT).
+ * @return {ol.tilegrid.TileGrid} TileGrid instance.
+ */
+ol.tilegrid.createForProjection = function(projection, opt_maxZoom, opt_tileSize, opt_corner) {
+ var extent = ol.tilegrid.extentFromProjection(projection);
+ return ol.tilegrid.createForExtent(
+ extent, opt_maxZoom, opt_tileSize, opt_corner);
+};
+
+
+/**
+ * Generate a tile grid extent from a projection. If the projection has an
+ * extent, it is used. If not, a global extent is assumed.
+ * @param {ol.ProjectionLike} projection Projection.
+ * @return {ol.Extent} Extent.
+ */
+ol.tilegrid.extentFromProjection = function(projection) {
+ projection = ol.proj.get(projection);
+ var extent = projection.getExtent();
+ if (!extent) {
+ var half = 180 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /
+ projection.getMetersPerUnit();
+ extent = ol.extent.createOrUpdate(-half, -half, half, half);
+ }
+ return extent;
+};
+
+goog.provide('ol.source.Tile');
+goog.provide('ol.source.TileEvent');
+
+goog.require('goog.asserts');
+goog.require('ol.events.Event');
+goog.require('ol');
+goog.require('ol.TileCache');
+goog.require('ol.TileRange');
+goog.require('ol.TileState');
+goog.require('ol.proj');
+goog.require('ol.size');
+goog.require('ol.source.Source');
+goog.require('ol.tilecoord');
+goog.require('ol.tilegrid.TileGrid');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for sources providing images divided into a tile grid.
+ *
+ * @constructor
+ * @extends {ol.source.Source}
+ * @param {ol.SourceTileOptions} options Tile source options.
+ * @api
+ */
+ol.source.Tile = function(options) {
+
+ ol.source.Source.call(this, {
+ attributions: options.attributions,
+ extent: options.extent,
+ logo: options.logo,
+ projection: options.projection,
+ state: options.state,
+ wrapX: options.wrapX
+ });
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.opaque_ = options.opaque !== undefined ? options.opaque : false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.tilePixelRatio_ = options.tilePixelRatio !== undefined ?
+ options.tilePixelRatio : 1;
+
+ /**
+ * @protected
+ * @type {ol.tilegrid.TileGrid}
+ */
+ this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null;
+
+ /**
+ * @protected
+ * @type {ol.TileCache}
+ */
+ this.tileCache = new ol.TileCache(options.cacheSize);
+
+ /**
+ * @protected
+ * @type {ol.Size}
+ */
+ this.tmpSize = [0, 0];
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.key_ = '';
+
+};
+ol.inherits(ol.source.Tile, ol.source.Source);
+
+
+/**
+ * @return {boolean} Can expire cache.
+ */
+ol.source.Tile.prototype.canExpireCache = function() {
+ return this.tileCache.canExpireCache();
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.
+ */
+ol.source.Tile.prototype.expireCache = function(projection, usedTiles) {
+ var tileCache = this.getTileCacheForProjection(projection);
+ if (tileCache) {
+ tileCache.expireCache(usedTiles);
+ }
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {number} z Zoom level.
+ * @param {ol.TileRange} tileRange Tile range.
+ * @param {function(ol.Tile):(boolean|undefined)} callback Called with each
+ * loaded tile. If the callback returns `false`, the tile will not be
+ * considered loaded.
+ * @return {boolean} The tile range is fully covered with loaded tiles.
+ */
+ol.source.Tile.prototype.forEachLoadedTile = function(projection, z, tileRange, callback) {
+ var tileCache = this.getTileCacheForProjection(projection);
+ if (!tileCache) {
+ return false;
+ }
+
+ var covered = true;
+ var tile, tileCoordKey, loaded;
+ for (var x = tileRange.minX; x <= tileRange.maxX; ++x) {
+ for (var y = tileRange.minY; y <= tileRange.maxY; ++y) {
+ tileCoordKey = this.getKeyZXY(z, x, y);
+ loaded = false;
+ if (tileCache.containsKey(tileCoordKey)) {
+ tile = /** @type {!ol.Tile} */ (tileCache.get(tileCoordKey));
+ loaded = tile.getState() === ol.TileState.LOADED;
+ if (loaded) {
+ loaded = (callback(tile) !== false);
+ }
+ }
+ if (!loaded) {
+ covered = false;
+ }
+ }
+ }
+ return covered;
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {number} Gutter.
+ */
+ol.source.Tile.prototype.getGutter = function(projection) {
+ return 0;
+};
+
+
+/**
+ * Return the key to be used for all tiles in the source.
+ * @return {string} The key for all tiles.
+ * @protected
+ */
+ol.source.Tile.prototype.getKey = function() {
+ return this.key_;
+};
+
+
+/**
+ * Set the value to be used as the key for all tiles in the source.
+ * @param {string} key The key for tiles.
+ * @protected
+ */
+ol.source.Tile.prototype.setKey = function(key) {
+ if (this.key_ !== key) {
+ this.key_ = key;
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {number} z Z.
+ * @param {number} x X.
+ * @param {number} y Y.
+ * @return {string} Key.
+ * @protected
+ */
+ol.source.Tile.prototype.getKeyZXY = ol.tilecoord.getKeyZXY;
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {boolean} Opaque.
+ */
+ol.source.Tile.prototype.getOpaque = function(projection) {
+ return this.opaque_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.Tile.prototype.getResolutions = function() {
+ return this.tileGrid.getResolutions();
+};
+
+
+/**
+ * @param {number} z Tile coordinate z.
+ * @param {number} x Tile coordinate x.
+ * @param {number} y Tile coordinate y.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {!ol.Tile} Tile.
+ */
+ol.source.Tile.prototype.getTile = goog.abstractMethod;
+
+
+/**
+ * Return the tile grid of the tile source.
+ * @return {ol.tilegrid.TileGrid} Tile grid.
+ * @api stable
+ */
+ol.source.Tile.prototype.getTileGrid = function() {
+ return this.tileGrid;
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.tilegrid.TileGrid} Tile grid.
+ */
+ol.source.Tile.prototype.getTileGridForProjection = function(projection) {
+ if (!this.tileGrid) {
+ return ol.tilegrid.getForProjection(projection);
+ } else {
+ return this.tileGrid;
+ }
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.TileCache} Tile cache.
+ * @protected
+ */
+ol.source.Tile.prototype.getTileCacheForProjection = function(projection) {
+ var thisProj = this.getProjection();
+ if (thisProj && !ol.proj.equivalent(thisProj, projection)) {
+ return null;
+ } else {
+ return this.tileCache;
+ }
+};
+
+
+/**
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {number} Tile pixel ratio.
+ */
+ol.source.Tile.prototype.getTilePixelRatio = function(pixelRatio) {
+ return this.tilePixelRatio_;
+};
+
+
+/**
+ * @param {number} z Z.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.Size} Tile size.
+ */
+ol.source.Tile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
+ var tileGrid = this.getTileGridForProjection(projection);
+ var tilePixelRatio = this.getTilePixelRatio(pixelRatio);
+ var tileSize = ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize);
+ if (tilePixelRatio == 1) {
+ return tileSize;
+ } else {
+ return ol.size.scale(tileSize, tilePixelRatio, this.tmpSize);
+ }
+};
+
+
+/**
+ * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate
+ * is outside the resolution and extent range of the tile grid, `null` will be
+ * returned.
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.proj.Projection=} opt_projection Projection.
+ * @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or
+ * null if no tile URL should be created for the passed `tileCoord`.
+ */
+ol.source.Tile.prototype.getTileCoordForTileUrlFunction = function(tileCoord, opt_projection) {
+ var projection = opt_projection !== undefined ?
+ opt_projection : this.getProjection();
+ var tileGrid = this.getTileGridForProjection(projection);
+ goog.asserts.assert(tileGrid, 'tile grid needed');
+ if (this.getWrapX() && projection.isGlobal()) {
+ tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection);
+ }
+ return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.Tile.prototype.refresh = function() {
+ this.tileCache.clear();
+ this.changed();
+};
+
+
+/**
+ * Marks a tile coord as being used, without triggering a load.
+ * @param {number} z Tile coordinate z.
+ * @param {number} x Tile coordinate x.
+ * @param {number} y Tile coordinate y.
+ * @param {ol.proj.Projection} projection Projection.
+ */
+ol.source.Tile.prototype.useTile = ol.nullFunction;
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.source.Tile} instances are instances of this
+ * type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.source.TileEvent}
+ * @param {string} type Type.
+ * @param {ol.Tile} tile The tile.
+ */
+ol.source.TileEvent = function(type, tile) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The tile related to the event.
+ * @type {ol.Tile}
+ * @api
+ */
+ this.tile = tile;
+
+};
+ol.inherits(ol.source.TileEvent, ol.events.Event);
+
+
+/**
+ * @enum {string}
+ */
+ol.source.TileEventType = {
+
+ /**
+ * Triggered when a tile starts loading.
+ * @event ol.source.TileEvent#tileloadstart
+ * @api stable
+ */
+ TILELOADSTART: 'tileloadstart',
+
+ /**
+ * Triggered when a tile finishes loading.
+ * @event ol.source.TileEvent#tileloadend
+ * @api stable
+ */
+ TILELOADEND: 'tileloadend',
+
+ /**
+ * Triggered if tile loading results in an error.
+ * @event ol.source.TileEvent#tileloaderror
+ * @api stable
+ */
+ TILELOADERROR: 'tileloaderror'
+
+};
+
+// FIXME handle date line wrap
+
+goog.provide('ol.control.Attribution');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.dom');
+goog.require('ol.Attribution');
+goog.require('ol.control.Control');
+goog.require('ol.css');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.object');
+goog.require('ol.source.Tile');
+
+
+/**
+ * @classdesc
+ * Control to show all the attributions associated with the layer sources
+ * in the map. This control is one of the default controls included in maps.
+ * By default it will show in the bottom right portion of the map, but this can
+ * be changed by using a css selector for `.ol-attribution`.
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.AttributionOptions=} opt_options Attribution options.
+ * @api stable
+ */
+ol.control.Attribution = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.ulElement_ = document.createElement('UL');
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.logoLi_ = document.createElement('LI');
+
+ this.ulElement_.appendChild(this.logoLi_);
+ this.logoLi_.style.display = 'none';
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.collapsible_ = options.collapsible !== undefined ?
+ options.collapsible : true;
+
+ if (!this.collapsible_) {
+ this.collapsed_ = false;
+ }
+
+ var className = options.className !== undefined ? options.className : 'ol-attribution';
+
+ var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';
+
+ var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\u00BB';
+
+ if (typeof collapseLabel === 'string') {
+ /**
+ * @private
+ * @type {Node}
+ */
+ this.collapseLabel_ = document.createElement('span');
+ this.collapseLabel_.textContent = collapseLabel;
+ } else {
+ this.collapseLabel_ = collapseLabel;
+ }
+
+ var label = options.label !== undefined ? options.label : 'i';
+
+ if (typeof label === 'string') {
+ /**
+ * @private
+ * @type {Node}
+ */
+ this.label_ = document.createElement('span');
+ this.label_.textContent = label;
+ } else {
+ this.label_ = label;
+ }
+
+
+ var activeLabel = (this.collapsible_ && !this.collapsed_) ?
+ this.collapseLabel_ : this.label_;
+ var button = document.createElement('button');
+ button.setAttribute('type', 'button');
+ button.title = tipLabel;
+ button.appendChild(activeLabel);
+
+ ol.events.listen(button, ol.events.EventType.CLICK, this.handleClick_, this);
+
+ var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
+ ol.css.CLASS_CONTROL +
+ (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +
+ (this.collapsible_ ? '' : ' ol-uncollapsible');
+ var element = document.createElement('div');
+ element.className = cssClasses;
+ element.appendChild(this.ulElement_);
+ element.appendChild(button);
+
+ var render = options.render ? options.render : ol.control.Attribution.render;
+
+ ol.control.Control.call(this, {
+ element: element,
+ render: render,
+ target: options.target
+ });
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderedVisible_ = true;
+
+ /**
+ * @private
+ * @type {Object.<string, Element>}
+ */
+ this.attributionElements_ = {};
+
+ /**
+ * @private
+ * @type {Object.<string, boolean>}
+ */
+ this.attributionElementRenderedVisible_ = {};
+
+ /**
+ * @private
+ * @type {Object.<string, Element>}
+ */
+ this.logoElements_ = {};
+
+};
+ol.inherits(ol.control.Attribution, ol.control.Control);
+
+
+/**
+ * @param {?olx.FrameState} frameState Frame state.
+ * @return {Array.<Object.<string, ol.Attribution>>} Attributions.
+ */
+ol.control.Attribution.prototype.getSourceAttributions = function(frameState) {
+ var i, ii, j, jj, tileRanges, source, sourceAttribution,
+ sourceAttributionKey, sourceAttributions, sourceKey;
+ var intersectsTileRange;
+ var layerStatesArray = frameState.layerStatesArray;
+ /** @type {Object.<string, ol.Attribution>} */
+ var attributions = ol.object.assign({}, frameState.attributions);
+ /** @type {Object.<string, ol.Attribution>} */
+ var hiddenAttributions = {};
+ var projection = frameState.viewState.projection;
+ goog.asserts.assert(projection, 'projection of viewState required');
+ for (i = 0, ii = layerStatesArray.length; i < ii; i++) {
+ source = layerStatesArray[i].layer.getSource();
+ if (!source) {
+ continue;
+ }
+ sourceKey = goog.getUid(source).toString();
+ sourceAttributions = source.getAttributions();
+ if (!sourceAttributions) {
+ continue;
+ }
+ for (j = 0, jj = sourceAttributions.length; j < jj; j++) {
+ sourceAttribution = sourceAttributions[j];
+ sourceAttributionKey = goog.getUid(sourceAttribution).toString();
+ if (sourceAttributionKey in attributions) {
+ continue;
+ }
+ tileRanges = frameState.usedTiles[sourceKey];
+ if (tileRanges) {
+ goog.asserts.assertInstanceof(source, ol.source.Tile,
+ 'source should be an ol.source.Tile');
+ var tileGrid = source.getTileGridForProjection(projection);
+ goog.asserts.assert(tileGrid, 'tileGrid required for projection');
+ intersectsTileRange = sourceAttribution.intersectsAnyTileRange(
+ tileRanges, tileGrid, projection);
+ } else {
+ intersectsTileRange = false;
+ }
+ if (intersectsTileRange) {
+ if (sourceAttributionKey in hiddenAttributions) {
+ delete hiddenAttributions[sourceAttributionKey];
+ }
+ attributions[sourceAttributionKey] = sourceAttribution;
+ } else {
+ hiddenAttributions[sourceAttributionKey] = sourceAttribution;
+ }
+ }
+ }
+ return [attributions, hiddenAttributions];
+};
+
+
+/**
+ * Update the attribution element.
+ * @param {ol.MapEvent} mapEvent Map event.
+ * @this {ol.control.Attribution}
+ * @api
+ */
+ol.control.Attribution.render = function(mapEvent) {
+ this.updateElement_(mapEvent.frameState);
+};
+
+
+/**
+ * @private
+ * @param {?olx.FrameState} frameState Frame state.
+ */
+ol.control.Attribution.prototype.updateElement_ = function(frameState) {
+
+ if (!frameState) {
+ if (this.renderedVisible_) {
+ this.element.style.display = 'none';
+ this.renderedVisible_ = false;
+ }
+ return;
+ }
+
+ var attributions = this.getSourceAttributions(frameState);
+ /** @type {Object.<string, ol.Attribution>} */
+ var visibleAttributions = attributions[0];
+ /** @type {Object.<string, ol.Attribution>} */
+ var hiddenAttributions = attributions[1];
+
+ var attributionElement, attributionKey;
+ for (attributionKey in this.attributionElements_) {
+ if (attributionKey in visibleAttributions) {
+ if (!this.attributionElementRenderedVisible_[attributionKey]) {
+ this.attributionElements_[attributionKey].style.display = '';
+ this.attributionElementRenderedVisible_[attributionKey] = true;
+ }
+ delete visibleAttributions[attributionKey];
+ } else if (attributionKey in hiddenAttributions) {
+ if (this.attributionElementRenderedVisible_[attributionKey]) {
+ this.attributionElements_[attributionKey].style.display = 'none';
+ delete this.attributionElementRenderedVisible_[attributionKey];
+ }
+ delete hiddenAttributions[attributionKey];
+ } else {
+ ol.dom.removeNode(this.attributionElements_[attributionKey]);
+ delete this.attributionElements_[attributionKey];
+ delete this.attributionElementRenderedVisible_[attributionKey];
+ }
+ }
+ for (attributionKey in visibleAttributions) {
+ attributionElement = document.createElement('LI');
+ attributionElement.innerHTML =
+ visibleAttributions[attributionKey].getHTML();
+ this.ulElement_.appendChild(attributionElement);
+ this.attributionElements_[attributionKey] = attributionElement;
+ this.attributionElementRenderedVisible_[attributionKey] = true;
+ }
+ for (attributionKey in hiddenAttributions) {
+ attributionElement = document.createElement('LI');
+ attributionElement.innerHTML =
+ hiddenAttributions[attributionKey].getHTML();
+ attributionElement.style.display = 'none';
+ this.ulElement_.appendChild(attributionElement);
+ this.attributionElements_[attributionKey] = attributionElement;
+ }
+
+ var renderVisible =
+ !ol.object.isEmpty(this.attributionElementRenderedVisible_) ||
+ !ol.object.isEmpty(frameState.logos);
+ if (this.renderedVisible_ != renderVisible) {
+ this.element.style.display = renderVisible ? '' : 'none';
+ this.renderedVisible_ = renderVisible;
+ }
+ if (renderVisible &&
+ ol.object.isEmpty(this.attributionElementRenderedVisible_)) {
+ this.element.classList.add('ol-logo-only');
+ } else {
+ this.element.classList.remove('ol-logo-only');
+ }
+
+ this.insertLogos_(frameState);
+
+};
+
+
+/**
+ * @param {?olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.control.Attribution.prototype.insertLogos_ = function(frameState) {
+
+ var logo;
+ var logos = frameState.logos;
+ var logoElements = this.logoElements_;
+
+ for (logo in logoElements) {
+ if (!(logo in logos)) {
+ ol.dom.removeNode(logoElements[logo]);
+ delete logoElements[logo];
+ }
+ }
+
+ var image, logoElement, logoKey;
+ for (logoKey in logos) {
+ var logoValue = logos[logoKey];
+ if (logoValue instanceof HTMLElement) {
+ this.logoLi_.appendChild(logoValue);
+ logoElements[logoKey] = logoValue;
+ }
+ if (!(logoKey in logoElements)) {
+ image = new Image();
+ image.src = logoKey;
+ if (logoValue === '') {
+ logoElement = image;
+ } else {
+ logoElement = document.createElement('a');
+ logoElement.href = logoValue;
+ logoElement.appendChild(image);
+ }
+ this.logoLi_.appendChild(logoElement);
+ logoElements[logoKey] = logoElement;
+ }
+ }
+
+ this.logoLi_.style.display = !ol.object.isEmpty(logos) ? '' : 'none';
+
+};
+
+
+/**
+ * @param {Event} event The event to handle
+ * @private
+ */
+ol.control.Attribution.prototype.handleClick_ = function(event) {
+ event.preventDefault();
+ this.handleToggle_();
+};
+
+
+/**
+ * @private
+ */
+ol.control.Attribution.prototype.handleToggle_ = function() {
+ this.element.classList.toggle('ol-collapsed');
+ if (this.collapsed_) {
+ ol.dom.replaceNode(this.collapseLabel_, this.label_);
+ } else {
+ ol.dom.replaceNode(this.label_, this.collapseLabel_);
+ }
+ this.collapsed_ = !this.collapsed_;
+};
+
+
+/**
+ * Return `true` if the attribution is collapsible, `false` otherwise.
+ * @return {boolean} True if the widget is collapsible.
+ * @api stable
+ */
+ol.control.Attribution.prototype.getCollapsible = function() {
+ return this.collapsible_;
+};
+
+
+/**
+ * Set whether the attribution should be collapsible.
+ * @param {boolean} collapsible True if the widget is collapsible.
+ * @api stable
+ */
+ol.control.Attribution.prototype.setCollapsible = function(collapsible) {
+ if (this.collapsible_ === collapsible) {
+ return;
+ }
+ this.collapsible_ = collapsible;
+ this.element.classList.toggle('ol-uncollapsible');
+ if (!collapsible && this.collapsed_) {
+ this.handleToggle_();
+ }
+};
+
+
+/**
+ * Collapse or expand the attribution according to the passed parameter. Will
+ * not do anything if the attribution isn't collapsible or if the current
+ * collapsed state is already the one requested.
+ * @param {boolean} collapsed True if the widget is collapsed.
+ * @api stable
+ */
+ol.control.Attribution.prototype.setCollapsed = function(collapsed) {
+ if (!this.collapsible_ || this.collapsed_ === collapsed) {
+ return;
+ }
+ this.handleToggle_();
+};
+
+
+/**
+ * Return `true` when the attribution is currently collapsed or `false`
+ * otherwise.
+ * @return {boolean} True if the widget is collapsed.
+ * @api stable
+ */
+ol.control.Attribution.prototype.getCollapsed = function() {
+ return this.collapsed_;
+};
+
+goog.provide('ol.control.Rotate');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.animation');
+goog.require('ol.control.Control');
+goog.require('ol.css');
+goog.require('ol.easing');
+
+
+/**
+ * @classdesc
+ * A button control to reset rotation to 0.
+ * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css
+ * selector is added to the button when the rotation is 0.
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.RotateOptions=} opt_options Rotate options.
+ * @api stable
+ */
+ol.control.Rotate = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var className = options.className !== undefined ? options.className : 'ol-rotate';
+
+ var label = options.label !== undefined ? options.label : '\u21E7';
+
+ /**
+ * @type {Element}
+ * @private
+ */
+ this.label_ = null;
+
+ if (typeof label === 'string') {
+ this.label_ = document.createElement('span');
+ this.label_.className = 'ol-compass';
+ this.label_.textContent = label;
+ } else {
+ this.label_ = label;
+ this.label_.classList.add('ol-compass');
+ }
+
+ var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';
+
+ var button = document.createElement('button');
+ button.className = className + '-reset';
+ button.setAttribute('type', 'button');
+ button.title = tipLabel;
+ button.appendChild(this.label_);
+
+ ol.events.listen(button, ol.events.EventType.CLICK,
+ ol.control.Rotate.prototype.handleClick_, this);
+
+ var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
+ ol.css.CLASS_CONTROL;
+ var element = document.createElement('div');
+ element.className = cssClasses;
+ element.appendChild(button);
+
+ var render = options.render ? options.render : ol.control.Rotate.render;
+
+ this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;
+
+ ol.control.Control.call(this, {
+ element: element,
+ render: render,
+ target: options.target
+ });
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 250;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.rotation_ = undefined;
+
+ if (this.autoHide_) {
+ this.element.classList.add(ol.css.CLASS_HIDDEN);
+ }
+
+};
+ol.inherits(ol.control.Rotate, ol.control.Control);
+
+
+/**
+ * @param {Event} event The event to handle
+ * @private
+ */
+ol.control.Rotate.prototype.handleClick_ = function(event) {
+ event.preventDefault();
+ if (this.callResetNorth_ !== undefined) {
+ this.callResetNorth_();
+ } else {
+ this.resetNorth_();
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.control.Rotate.prototype.resetNorth_ = function() {
+ var map = this.getMap();
+ var view = map.getView();
+ if (!view) {
+ // the map does not have a view, so we can't act
+ // upon it
+ return;
+ }
+ var currentRotation = view.getRotation();
+ if (currentRotation !== undefined) {
+ if (this.duration_ > 0) {
+ currentRotation = currentRotation % (2 * Math.PI);
+ if (currentRotation < -Math.PI) {
+ currentRotation += 2 * Math.PI;
+ }
+ if (currentRotation > Math.PI) {
+ currentRotation -= 2 * Math.PI;
+ }
+ map.beforeRender(ol.animation.rotate({
+ rotation: currentRotation,
+ duration: this.duration_,
+ easing: ol.easing.easeOut
+ }));
+ }
+ view.setRotation(0);
+ }
+};
+
+
+/**
+ * Update the rotate control element.
+ * @param {ol.MapEvent} mapEvent Map event.
+ * @this {ol.control.Rotate}
+ * @api
+ */
+ol.control.Rotate.render = function(mapEvent) {
+ var frameState = mapEvent.frameState;
+ if (!frameState) {
+ return;
+ }
+ var rotation = frameState.viewState.rotation;
+ if (rotation != this.rotation_) {
+ var transform = 'rotate(' + rotation + 'rad)';
+ if (this.autoHide_) {
+ var contains = this.element.classList.contains(ol.css.CLASS_HIDDEN);
+ if (!contains && rotation === 0) {
+ this.element.classList.add(ol.css.CLASS_HIDDEN);
+ } else if (contains && rotation !== 0) {
+ this.element.classList.remove(ol.css.CLASS_HIDDEN);
+ }
+ }
+ this.label_.style.msTransform = transform;
+ this.label_.style.webkitTransform = transform;
+ this.label_.style.transform = transform;
+ }
+ this.rotation_ = rotation;
+};
+
+goog.provide('ol.control.Zoom');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.animation');
+goog.require('ol.control.Control');
+goog.require('ol.css');
+goog.require('ol.easing');
+
+
+/**
+ * @classdesc
+ * A control with 2 buttons, one for zoom in and one for zoom out.
+ * This control is one of the default controls of a map. To style this control
+ * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.ZoomOptions=} opt_options Zoom options.
+ * @api stable
+ */
+ol.control.Zoom = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var className = options.className !== undefined ? options.className : 'ol-zoom';
+
+ var delta = options.delta !== undefined ? options.delta : 1;
+
+ var zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';
+ var zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212';
+
+ var zoomInTipLabel = options.zoomInTipLabel !== undefined ?
+ options.zoomInTipLabel : 'Zoom in';
+ var zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?
+ options.zoomOutTipLabel : 'Zoom out';
+
+ var inElement = document.createElement('button');
+ inElement.className = className + '-in';
+ inElement.setAttribute('type', 'button');
+ inElement.title = zoomInTipLabel;
+ inElement.appendChild(
+ typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel
+ );
+
+ ol.events.listen(inElement, ol.events.EventType.CLICK,
+ ol.control.Zoom.prototype.handleClick_.bind(this, delta));
+
+ var outElement = document.createElement('button');
+ outElement.className = className + '-out';
+ outElement.setAttribute('type', 'button');
+ outElement.title = zoomOutTipLabel;
+ outElement.appendChild(
+ typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel
+ );
+
+ ol.events.listen(outElement, ol.events.EventType.CLICK,
+ ol.control.Zoom.prototype.handleClick_.bind(this, -delta));
+
+ var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
+ ol.css.CLASS_CONTROL;
+ var element = document.createElement('div');
+ element.className = cssClasses;
+ element.appendChild(inElement);
+ element.appendChild(outElement);
+
+ ol.control.Control.call(this, {
+ element: element,
+ target: options.target
+ });
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 250;
+
+};
+ol.inherits(ol.control.Zoom, ol.control.Control);
+
+
+/**
+ * @param {number} delta Zoom delta.
+ * @param {Event} event The event to handle
+ * @private
+ */
+ol.control.Zoom.prototype.handleClick_ = function(delta, event) {
+ event.preventDefault();
+ this.zoomByDelta_(delta);
+};
+
+
+/**
+ * @param {number} delta Zoom delta.
+ * @private
+ */
+ol.control.Zoom.prototype.zoomByDelta_ = function(delta) {
+ var map = this.getMap();
+ var view = map.getView();
+ if (!view) {
+ // the map does not have a view, so we can't act
+ // upon it
+ return;
+ }
+ var currentResolution = view.getResolution();
+ if (currentResolution) {
+ if (this.duration_ > 0) {
+ map.beforeRender(ol.animation.zoom({
+ resolution: currentResolution,
+ duration: this.duration_,
+ easing: ol.easing.easeOut
+ }));
+ }
+ var newResolution = view.constrainResolution(currentResolution, delta);
+ view.setResolution(newResolution);
+ }
+};
+
+goog.provide('ol.control');
+
+goog.require('ol');
+goog.require('ol.Collection');
+goog.require('ol.control.Attribution');
+goog.require('ol.control.Rotate');
+goog.require('ol.control.Zoom');
+
+
+/**
+ * Set of controls included in maps by default. Unless configured otherwise,
+ * this returns a collection containing an instance of each of the following
+ * controls:
+ * * {@link ol.control.Zoom}
+ * * {@link ol.control.Rotate}
+ * * {@link ol.control.Attribution}
+ *
+ * @param {olx.control.DefaultsOptions=} opt_options Defaults options.
+ * @return {ol.Collection.<ol.control.Control>} Controls.
+ * @api stable
+ */
+ol.control.defaults = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var controls = new ol.Collection();
+
+ var zoomControl = options.zoom !== undefined ? options.zoom : true;
+ if (zoomControl) {
+ controls.push(new ol.control.Zoom(options.zoomOptions));
+ }
+
+ var rotateControl = options.rotate !== undefined ? options.rotate : true;
+ if (rotateControl) {
+ controls.push(new ol.control.Rotate(options.rotateOptions));
+ }
+
+ var attributionControl = options.attribution !== undefined ?
+ options.attribution : true;
+ if (attributionControl) {
+ controls.push(new ol.control.Attribution(options.attributionOptions));
+ }
+
+ return controls;
+
+};
+
+goog.provide('ol.control.FullScreen');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.control.Control');
+goog.require('ol.dom');
+goog.require('ol.css');
+
+
+/**
+ * @classdesc
+ * Provides a button that when clicked fills up the full screen with the map.
+ * The full screen source element is by default the element containing the map viewport unless
+ * overriden by providing the `source` option. In which case, the dom
+ * element introduced using this parameter will be displayed in full screen.
+ *
+ * When in full screen mode, a close button is shown to exit full screen mode.
+ * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
+ * toggle the map in full screen mode.
+ *
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.FullScreenOptions=} opt_options Options.
+ * @api stable
+ */
+ol.control.FullScreen = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.cssClassName_ = options.className !== undefined ? options.className :
+ 'ol-full-screen';
+
+ var label = options.label !== undefined ? options.label : '\u2922';
+
+ /**
+ * @private
+ * @type {Node}
+ */
+ this.labelNode_ = typeof label === 'string' ?
+ document.createTextNode(label) : label;
+
+ var labelActive = options.labelActive !== undefined ? options.labelActive : '\u00d7';
+
+ /**
+ * @private
+ * @type {Node}
+ */
+ this.labelActiveNode_ = typeof labelActive === 'string' ?
+ document.createTextNode(labelActive) : labelActive;
+
+ var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
+ var button = document.createElement('button');
+ button.className = this.cssClassName_ + '-' + ol.control.FullScreen.isFullScreen();
+ button.setAttribute('type', 'button');
+ button.title = tipLabel;
+ button.appendChild(this.labelNode_);
+
+ ol.events.listen(button, ol.events.EventType.CLICK,
+ this.handleClick_, this);
+
+ var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE +
+ ' ' + ol.css.CLASS_CONTROL + ' ' +
+ (!ol.control.FullScreen.isFullScreenSupported() ? ol.css.CLASS_UNSUPPORTED : '');
+ var element = document.createElement('div');
+ element.className = cssClasses;
+ element.appendChild(button);
+
+ ol.control.Control.call(this, {
+ element: element,
+ target: options.target
+ });
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.keys_ = options.keys !== undefined ? options.keys : false;
+
+ /**
+ * @private
+ * @type {Element|string|undefined}
+ */
+ this.source_ = options.source;
+
+};
+ol.inherits(ol.control.FullScreen, ol.control.Control);
+
+
+/**
+ * @param {Event} event The event to handle
+ * @private
+ */
+ol.control.FullScreen.prototype.handleClick_ = function(event) {
+ event.preventDefault();
+ this.handleFullScreen_();
+};
+
+
+/**
+ * @private
+ */
+ol.control.FullScreen.prototype.handleFullScreen_ = function() {
+ if (!ol.control.FullScreen.isFullScreenSupported()) {
+ return;
+ }
+ var map = this.getMap();
+ if (!map) {
+ return;
+ }
+ if (ol.control.FullScreen.isFullScreen()) {
+ ol.control.FullScreen.exitFullScreen();
+ } else {
+ var element;
+ if (this.source_) {
+ element = typeof this.source_ === 'string' ?
+ document.getElementById(this.source_) :
+ this.source_;
+ } else {
+ element = map.getTargetElement();
+ }
+ goog.asserts.assert(element, 'element should be defined');
+ if (this.keys_) {
+ ol.control.FullScreen.requestFullScreenWithKeys(element);
+
+ } else {
+ ol.control.FullScreen.requestFullScreen(element);
+ }
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.control.FullScreen.prototype.handleFullScreenChange_ = function() {
+ var button = this.element.firstElementChild;
+ var map = this.getMap();
+ if (ol.control.FullScreen.isFullScreen()) {
+ button.className = this.cssClassName_ + '-true';
+ ol.dom.replaceNode(this.labelActiveNode_, this.labelNode_);
+ } else {
+ button.className = this.cssClassName_ + '-false';
+ ol.dom.replaceNode(this.labelNode_, this.labelActiveNode_);
+ }
+ if (map) {
+ map.updateSize();
+ }
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.control.FullScreen.prototype.setMap = function(map) {
+ ol.control.Control.prototype.setMap.call(this, map);
+ if (map) {
+ this.listenerKeys.push(ol.events.listen(ol.global.document,
+ ol.control.FullScreen.getChangeType_(),
+ this.handleFullScreenChange_, this)
+ );
+ }
+};
+
+/**
+ * @return {boolean} Fullscreen is supported by the current platform.
+ */
+ol.control.FullScreen.isFullScreenSupported = function() {
+ var body = document.body;
+ return !!(
+ body.webkitRequestFullscreen ||
+ (body.mozRequestFullScreen && document.mozFullScreenEnabled) ||
+ (body.msRequestFullscreen && document.msFullscreenEnabled) ||
+ (body.requestFullscreen && document.fullscreenEnabled)
+ );
+};
+
+/**
+ * @return {boolean} Element is currently in fullscreen.
+ */
+ol.control.FullScreen.isFullScreen = function() {
+ return !!(
+ document.webkitIsFullScreen || document.mozFullScreen ||
+ document.msFullscreenElement || document.fullscreenElement
+ );
+};
+
+/**
+ * Request to fullscreen an element.
+ * @param {Node} element Element to request fullscreen
+ */
+ol.control.FullScreen.requestFullScreen = function(element) {
+ if (element.requestFullscreen) {
+ element.requestFullscreen();
+ } else if (element.msRequestFullscreen) {
+ element.msRequestFullscreen();
+ } else if (element.mozRequestFullScreen) {
+ element.mozRequestFullScreen();
+ } else if (element.webkitRequestFullscreen) {
+ element.webkitRequestFullscreen();
+ }
+};
+
+/**
+ * Request to fullscreen an element with keyboard input.
+ * @param {Node} element Element to request fullscreen
+ */
+ol.control.FullScreen.requestFullScreenWithKeys = function(element) {
+ if (element.mozRequestFullScreenWithKeys) {
+ element.mozRequestFullScreenWithKeys();
+ } else if (element.webkitRequestFullscreen) {
+ element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+ } else {
+ ol.control.FullScreen.requestFullScreen(element);
+ }
+};
+
+/**
+ * Exit fullscreen.
+ */
+ol.control.FullScreen.exitFullScreen = function() {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen();
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ }
+};
+
+/**
+ * @return {string} Change type.
+ * @private
+ */
+ol.control.FullScreen.getChangeType_ = (function() {
+ var changeType;
+ return function() {
+ if (!changeType) {
+ var body = document.body;
+ if (body.webkitRequestFullscreen) {
+ changeType = 'webkitfullscreenchange';
+ } else if (body.mozRequestFullScreen) {
+ changeType = 'mozfullscreenchange';
+ } else if (body.msRequestFullscreen) {
+ changeType = 'MSFullscreenChange';
+ } else if (body.requestFullscreen) {
+ changeType = 'fullscreenchange';
+ }
+ }
+ return changeType;
+ };
+})();
+
+// FIXME should listen on appropriate pane, once it is defined
+
+goog.provide('ol.control.MousePosition');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.Object');
+goog.require('ol.control.Control');
+goog.require('ol.proj');
+goog.require('ol.proj.Projection');
+
+
+/**
+ * @enum {string}
+ */
+ol.control.MousePositionProperty = {
+ PROJECTION: 'projection',
+ COORDINATE_FORMAT: 'coordinateFormat'
+};
+
+
+/**
+ * @classdesc
+ * A control to show the 2D coordinates of the mouse cursor. By default, these
+ * are in the view projection, but can be in any supported projection.
+ * By default the control is shown in the top right corner of the map, but this
+ * can be changed by using the css selector `.ol-mouse-position`.
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.MousePositionOptions=} opt_options Mouse position
+ * options.
+ * @api stable
+ */
+ol.control.MousePosition = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var element = document.createElement('DIV');
+ element.className = options.className !== undefined ? options.className : 'ol-mouse-position';
+
+ var render = options.render ?
+ options.render : ol.control.MousePosition.render;
+
+ ol.control.Control.call(this, {
+ element: element,
+ render: render,
+ target: options.target
+ });
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION),
+ this.handleProjectionChanged_, this);
+
+ if (options.coordinateFormat) {
+ this.setCoordinateFormat(options.coordinateFormat);
+ }
+ if (options.projection) {
+ this.setProjection(ol.proj.get(options.projection));
+ }
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.undefinedHTML_ = options.undefinedHTML !== undefined ? options.undefinedHTML : '';
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.renderedHTML_ = element.innerHTML;
+
+ /**
+ * @private
+ * @type {ol.proj.Projection}
+ */
+ this.mapProjection_ = null;
+
+ /**
+ * @private
+ * @type {?ol.TransformFunction}
+ */
+ this.transform_ = null;
+
+ /**
+ * @private
+ * @type {ol.Pixel}
+ */
+ this.lastMouseMovePixel_ = null;
+
+};
+ol.inherits(ol.control.MousePosition, ol.control.Control);
+
+
+/**
+ * Update the mouseposition element.
+ * @param {ol.MapEvent} mapEvent Map event.
+ * @this {ol.control.MousePosition}
+ * @api
+ */
+ol.control.MousePosition.render = function(mapEvent) {
+ var frameState = mapEvent.frameState;
+ if (!frameState) {
+ this.mapProjection_ = null;
+ } else {
+ if (this.mapProjection_ != frameState.viewState.projection) {
+ this.mapProjection_ = frameState.viewState.projection;
+ this.transform_ = null;
+ }
+ }
+ this.updateHTML_(this.lastMouseMovePixel_);
+};
+
+
+/**
+ * @private
+ */
+ol.control.MousePosition.prototype.handleProjectionChanged_ = function() {
+ this.transform_ = null;
+};
+
+
+/**
+ * Return the coordinate format type used to render the current position or
+ * undefined.
+ * @return {ol.CoordinateFormatType|undefined} The format to render the current
+ * position in.
+ * @observable
+ * @api stable
+ */
+ol.control.MousePosition.prototype.getCoordinateFormat = function() {
+ return /** @type {ol.CoordinateFormatType|undefined} */ (
+ this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT));
+};
+
+
+/**
+ * Return the projection that is used to report the mouse position.
+ * @return {ol.proj.Projection|undefined} The projection to report mouse
+ * position in.
+ * @observable
+ * @api stable
+ */
+ol.control.MousePosition.prototype.getProjection = function() {
+ return /** @type {ol.proj.Projection|undefined} */ (
+ this.get(ol.control.MousePositionProperty.PROJECTION));
+};
+
+
+/**
+ * @param {Event} event Browser event.
+ * @protected
+ */
+ol.control.MousePosition.prototype.handleMouseMove = function(event) {
+ var map = this.getMap();
+ this.lastMouseMovePixel_ = map.getEventPixel(event);
+ this.updateHTML_(this.lastMouseMovePixel_);
+};
+
+
+/**
+ * @param {Event} event Browser event.
+ * @protected
+ */
+ol.control.MousePosition.prototype.handleMouseOut = function(event) {
+ this.updateHTML_(null);
+ this.lastMouseMovePixel_ = null;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.control.MousePosition.prototype.setMap = function(map) {
+ ol.control.Control.prototype.setMap.call(this, map);
+ if (map) {
+ var viewport = map.getViewport();
+ this.listenerKeys.push(
+ ol.events.listen(viewport, ol.events.EventType.MOUSEMOVE,
+ this.handleMouseMove, this),
+ ol.events.listen(viewport, ol.events.EventType.MOUSEOUT,
+ this.handleMouseOut, this)
+ );
+ }
+};
+
+
+/**
+ * Set the coordinate format type used to render the current position.
+ * @param {ol.CoordinateFormatType} format The format to render the current
+ * position in.
+ * @observable
+ * @api stable
+ */
+ol.control.MousePosition.prototype.setCoordinateFormat = function(format) {
+ this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format);
+};
+
+
+/**
+ * Set the projection that is used to report the mouse position.
+ * @param {ol.proj.Projection} projection The projection to report mouse
+ * position in.
+ * @observable
+ * @api stable
+ */
+ol.control.MousePosition.prototype.setProjection = function(projection) {
+ this.set(ol.control.MousePositionProperty.PROJECTION, projection);
+};
+
+
+/**
+ * @param {?ol.Pixel} pixel Pixel.
+ * @private
+ */
+ol.control.MousePosition.prototype.updateHTML_ = function(pixel) {
+ var html = this.undefinedHTML_;
+ if (pixel && this.mapProjection_) {
+ if (!this.transform_) {
+ var projection = this.getProjection();
+ if (projection) {
+ this.transform_ = ol.proj.getTransformFromProjections(
+ this.mapProjection_, projection);
+ } else {
+ this.transform_ = ol.proj.identityTransform;
+ }
+ }
+ var map = this.getMap();
+ var coordinate = map.getCoordinateFromPixel(pixel);
+ if (coordinate) {
+ this.transform_(coordinate, coordinate);
+ var coordinateFormat = this.getCoordinateFormat();
+ if (coordinateFormat) {
+ html = coordinateFormat(coordinate);
+ } else {
+ html = coordinate.toString();
+ }
+ }
+ }
+ if (!this.renderedHTML_ || html != this.renderedHTML_) {
+ this.element.innerHTML = html;
+ this.renderedHTML_ = html;
+ }
+};
+
+// Copyright 2010 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview A global registry for entry points into a program,
+ * so that they can be instrumented. Each module should register their
+ * entry points with this registry. Designed to be compiled out
+ * if no instrumentation is requested.
+ *
+ * Entry points may be registered before or after a call to
+ * goog.debug.entryPointRegistry.monitorAll. If an entry point is registered
+ * later, the existing monitor will instrument the new entry point.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.debug.EntryPointMonitor');
+goog.provide('goog.debug.entryPointRegistry');
+
+goog.require('goog.asserts');
+
+
+
+/**
+ * @interface
+ */
+goog.debug.EntryPointMonitor = function() {};
+
+
+/**
+ * Instruments a function.
+ *
+ * @param {!Function} fn A function to instrument.
+ * @return {!Function} The instrumented function.
+ */
+goog.debug.EntryPointMonitor.prototype.wrap;
+
+
+/**
+ * Try to remove an instrumentation wrapper created by this monitor.
+ * If the function passed to unwrap is not a wrapper created by this
+ * monitor, then we will do nothing.
+ *
+ * Notice that some wrappers may not be unwrappable. For example, if other
+ * monitors have applied their own wrappers, then it will be impossible to
+ * unwrap them because their wrappers will have captured our wrapper.
+ *
+ * So it is important that entry points are unwrapped in the reverse
+ * order that they were wrapped.
+ *
+ * @param {!Function} fn A function to unwrap.
+ * @return {!Function} The unwrapped function, or {@code fn} if it was not
+ * a wrapped function created by this monitor.
+ */
+goog.debug.EntryPointMonitor.prototype.unwrap;
+
+
+/**
+ * An array of entry point callbacks.
+ * @type {!Array<function(!Function)>}
+ * @private
+ */
+goog.debug.entryPointRegistry.refList_ = [];
+
+
+/**
+ * Monitors that should wrap all the entry points.
+ * @type {!Array<!goog.debug.EntryPointMonitor>}
+ * @private
+ */
+goog.debug.entryPointRegistry.monitors_ = [];
+
+
+/**
+ * Whether goog.debug.entryPointRegistry.monitorAll has ever been called.
+ * Checking this allows the compiler to optimize out the registrations.
+ * @type {boolean}
+ * @private
+ */
+goog.debug.entryPointRegistry.monitorsMayExist_ = false;
+
+
+/**
+ * Register an entry point with this module.
+ *
+ * The entry point will be instrumented when a monitor is passed to
+ * goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the
+ * entry point is instrumented immediately.
+ *
+ * @param {function(!Function)} callback A callback function which is called
+ * with a transforming function to instrument the entry point. The callback
+ * is responsible for wrapping the relevant entry point with the
+ * transforming function.
+ */
+goog.debug.entryPointRegistry.register = function(callback) {
+ // Don't use push(), so that this can be compiled out.
+ goog.debug.entryPointRegistry
+ .refList_[goog.debug.entryPointRegistry.refList_.length] = callback;
+ // If no one calls monitorAll, this can be compiled out.
+ if (goog.debug.entryPointRegistry.monitorsMayExist_) {
+ var monitors = goog.debug.entryPointRegistry.monitors_;
+ for (var i = 0; i < monitors.length; i++) {
+ callback(goog.bind(monitors[i].wrap, monitors[i]));
+ }
+ }
+};
+
+
+/**
+ * Configures a monitor to wrap all entry points.
+ *
+ * Entry points that have already been registered are immediately wrapped by
+ * the monitor. When an entry point is registered in the future, it will also
+ * be wrapped by the monitor when it is registered.
+ *
+ * @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor.
+ */
+goog.debug.entryPointRegistry.monitorAll = function(monitor) {
+ goog.debug.entryPointRegistry.monitorsMayExist_ = true;
+ var transformer = goog.bind(monitor.wrap, monitor);
+ for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
+ goog.debug.entryPointRegistry.refList_[i](transformer);
+ }
+ goog.debug.entryPointRegistry.monitors_.push(monitor);
+};
+
+
+/**
+ * Try to unmonitor all the entry points that have already been registered. If
+ * an entry point is registered in the future, it will not be wrapped by the
+ * monitor when it is registered. Note that this may fail if the entry points
+ * have additional wrapping.
+ *
+ * @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap
+ * the entry points.
+ * @throws {Error} If the monitor is not the most recently configured monitor.
+ */
+goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) {
+ var monitors = goog.debug.entryPointRegistry.monitors_;
+ goog.asserts.assert(
+ monitor == monitors[monitors.length - 1],
+ 'Only the most recent monitor can be unwrapped.');
+ var transformer = goog.bind(monitor.unwrap, monitor);
+ for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
+ goog.debug.entryPointRegistry.refList_[i](transformer);
+ }
+ monitors.length--;
+};
+
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Defines the goog.dom.TagName enum. This enumerates
+ * all HTML tag names specified in either the the W3C HTML 4.01 index of
+ * elements or the HTML5 draft specification.
+ *
+ * References:
+ * http://www.w3.org/TR/html401/index/elements.html
+ * http://dev.w3.org/html5/spec/section-index.html
+ *
+ */
+goog.provide('goog.dom.TagName');
+
+
+/**
+ * Enum of all html tag names specified by the W3C HTML4.01 and HTML5
+ * specifications.
+ * @enum {string}
+ */
+goog.dom.TagName = {
+ A: 'A',
+ ABBR: 'ABBR',
+ ACRONYM: 'ACRONYM',
+ ADDRESS: 'ADDRESS',
+ APPLET: 'APPLET',
+ AREA: 'AREA',
+ ARTICLE: 'ARTICLE',
+ ASIDE: 'ASIDE',
+ AUDIO: 'AUDIO',
+ B: 'B',
+ BASE: 'BASE',
+ BASEFONT: 'BASEFONT',
+ BDI: 'BDI',
+ BDO: 'BDO',
+ BIG: 'BIG',
+ BLOCKQUOTE: 'BLOCKQUOTE',
+ BODY: 'BODY',
+ BR: 'BR',
+ BUTTON: 'BUTTON',
+ CANVAS: 'CANVAS',
+ CAPTION: 'CAPTION',
+ CENTER: 'CENTER',
+ CITE: 'CITE',
+ CODE: 'CODE',
+ COL: 'COL',
+ COLGROUP: 'COLGROUP',
+ COMMAND: 'COMMAND',
+ DATA: 'DATA',
+ DATALIST: 'DATALIST',
+ DD: 'DD',
+ DEL: 'DEL',
+ DETAILS: 'DETAILS',
+ DFN: 'DFN',
+ DIALOG: 'DIALOG',
+ DIR: 'DIR',
+ DIV: 'DIV',
+ DL: 'DL',
+ DT: 'DT',
+ EM: 'EM',
+ EMBED: 'EMBED',
+ FIELDSET: 'FIELDSET',
+ FIGCAPTION: 'FIGCAPTION',
+ FIGURE: 'FIGURE',
+ FONT: 'FONT',
+ FOOTER: 'FOOTER',
+ FORM: 'FORM',
+ FRAME: 'FRAME',
+ FRAMESET: 'FRAMESET',
+ H1: 'H1',
+ H2: 'H2',
+ H3: 'H3',
+ H4: 'H4',
+ H5: 'H5',
+ H6: 'H6',
+ HEAD: 'HEAD',
+ HEADER: 'HEADER',
+ HGROUP: 'HGROUP',
+ HR: 'HR',
+ HTML: 'HTML',
+ I: 'I',
+ IFRAME: 'IFRAME',
+ IMG: 'IMG',
+ INPUT: 'INPUT',
+ INS: 'INS',
+ ISINDEX: 'ISINDEX',
+ KBD: 'KBD',
+ KEYGEN: 'KEYGEN',
+ LABEL: 'LABEL',
+ LEGEND: 'LEGEND',
+ LI: 'LI',
+ LINK: 'LINK',
+ MAP: 'MAP',
+ MARK: 'MARK',
+ MATH: 'MATH',
+ MENU: 'MENU',
+ META: 'META',
+ METER: 'METER',
+ NAV: 'NAV',
+ NOFRAMES: 'NOFRAMES',
+ NOSCRIPT: 'NOSCRIPT',
+ OBJECT: 'OBJECT',
+ OL: 'OL',
+ OPTGROUP: 'OPTGROUP',
+ OPTION: 'OPTION',
+ OUTPUT: 'OUTPUT',
+ P: 'P',
+ PARAM: 'PARAM',
+ PRE: 'PRE',
+ PROGRESS: 'PROGRESS',
+ Q: 'Q',
+ RP: 'RP',
+ RT: 'RT',
+ RUBY: 'RUBY',
+ S: 'S',
+ SAMP: 'SAMP',
+ SCRIPT: 'SCRIPT',
+ SECTION: 'SECTION',
+ SELECT: 'SELECT',
+ SMALL: 'SMALL',
+ SOURCE: 'SOURCE',
+ SPAN: 'SPAN',
+ STRIKE: 'STRIKE',
+ STRONG: 'STRONG',
+ STYLE: 'STYLE',
+ SUB: 'SUB',
+ SUMMARY: 'SUMMARY',
+ SUP: 'SUP',
+ SVG: 'SVG',
+ TABLE: 'TABLE',
+ TBODY: 'TBODY',
+ TD: 'TD',
+ TEMPLATE: 'TEMPLATE',
+ TEXTAREA: 'TEXTAREA',
+ TFOOT: 'TFOOT',
+ TH: 'TH',
+ THEAD: 'THEAD',
+ TIME: 'TIME',
+ TITLE: 'TITLE',
+ TR: 'TR',
+ TRACK: 'TRACK',
+ TT: 'TT',
+ U: 'U',
+ UL: 'UL',
+ VAR: 'VAR',
+ VIDEO: 'VIDEO',
+ WBR: 'WBR'
+};
+
+// Copyright 2008 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Utilities for creating functions. Loosely inspired by the
+ * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+
+goog.provide('goog.functions');
+
+
+/**
+ * Creates a function that always returns the same value.
+ * @param {T} retValue The value to return.
+ * @return {function():T} The new function.
+ * @template T
+ */
+goog.functions.constant = function(retValue) {
+ return function() { return retValue; };
+};
+
+
+/**
+ * Always returns false.
+ * @type {function(...): boolean}
+ */
+goog.functions.FALSE = goog.functions.constant(false);
+
+
+/**
+ * Always returns true.
+ * @type {function(...): boolean}
+ */
+goog.functions.TRUE = goog.functions.constant(true);
+
+
+/**
+ * Always returns NULL.
+ * @type {function(...): null}
+ */
+goog.functions.NULL = goog.functions.constant(null);
+
+
+/**
+ * A simple function that returns the first argument of whatever is passed
+ * into it.
+ * @param {T=} opt_returnValue The single value that will be returned.
+ * @param {...*} var_args Optional trailing arguments. These are ignored.
+ * @return {T} The first argument passed in, or undefined if nothing was passed.
+ * @template T
+ */
+goog.functions.identity = function(opt_returnValue, var_args) {
+ return opt_returnValue;
+};
+
+
+/**
+ * Creates a function that always throws an error with the given message.
+ * @param {string} message The error message.
+ * @return {!Function} The error-throwing function.
+ */
+goog.functions.error = function(message) {
+ return function() { throw Error(message); };
+};
+
+
+/**
+ * Creates a function that throws the given object.
+ * @param {*} err An object to be thrown.
+ * @return {!Function} The error-throwing function.
+ */
+goog.functions.fail = function(err) {
+ return function() { throw err; };
+};
+
+
+/**
+ * Given a function, create a function that keeps opt_numArgs arguments and
+ * silently discards all additional arguments.
+ * @param {Function} f The original function.
+ * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
+ * @return {!Function} A version of f that only keeps the first opt_numArgs
+ * arguments.
+ */
+goog.functions.lock = function(f, opt_numArgs) {
+ opt_numArgs = opt_numArgs || 0;
+ return function() {
+ return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
+ };
+};
+
+
+/**
+ * Creates a function that returns its nth argument.
+ * @param {number} n The position of the return argument.
+ * @return {!Function} A new function.
+ */
+goog.functions.nth = function(n) {
+ return function() { return arguments[n]; };
+};
+
+
+/**
+ * Like goog.partial(), except that arguments are added after arguments to the
+ * returned function.
+ *
+ * Usage:
+ * function f(arg1, arg2, arg3, arg4) { ... }
+ * var g = goog.functions.partialRight(f, arg3, arg4);
+ * g(arg1, arg2);
+ *
+ * @param {!Function} fn A function to partially apply.
+ * @param {...*} var_args Additional arguments that are partially applied to fn
+ * at the end.
+ * @return {!Function} A partially-applied form of the function goog.partial()
+ * was invoked as a method of.
+ */
+goog.functions.partialRight = function(fn, var_args) {
+ var rightArgs = Array.prototype.slice.call(arguments, 1);
+ return function() {
+ var newArgs = Array.prototype.slice.call(arguments);
+ newArgs.push.apply(newArgs, rightArgs);
+ return fn.apply(this, newArgs);
+ };
+};
+
+
+/**
+ * Given a function, create a new function that swallows its return value
+ * and replaces it with a new one.
+ * @param {Function} f A function.
+ * @param {T} retValue A new return value.
+ * @return {function(...?):T} A new function.
+ * @template T
+ */
+goog.functions.withReturnValue = function(f, retValue) {
+ return goog.functions.sequence(f, goog.functions.constant(retValue));
+};
+
+
+/**
+ * Creates a function that returns whether its argument equals the given value.
+ *
+ * Example:
+ * var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
+ *
+ * @param {*} value The value to compare to.
+ * @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
+ * comparison rather than a strict (===) one. Defaults to false.
+ * @return {function(*):boolean} The new function.
+ */
+goog.functions.equalTo = function(value, opt_useLooseComparison) {
+ return function(other) {
+ return opt_useLooseComparison ? (value == other) : (value === other);
+ };
+};
+
+
+/**
+ * Creates the composition of the functions passed in.
+ * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
+ * @param {function(...?):T} fn The final function.
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):T} The composition of all inputs.
+ * @template T
+ */
+goog.functions.compose = function(fn, var_args) {
+ var functions = arguments;
+ var length = functions.length;
+ return function() {
+ var result;
+ if (length) {
+ result = functions[length - 1].apply(this, arguments);
+ }
+
+ for (var i = length - 2; i >= 0; i--) {
+ result = functions[i].call(this, result);
+ }
+ return result;
+ };
+};
+
+
+/**
+ * Creates a function that calls the functions passed in in sequence, and
+ * returns the value of the last function. For example,
+ * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {!Function} A function that calls all inputs in sequence.
+ */
+goog.functions.sequence = function(var_args) {
+ var functions = arguments;
+ var length = functions.length;
+ return function() {
+ var result;
+ for (var i = 0; i < length; i++) {
+ result = functions[i].apply(this, arguments);
+ }
+ return result;
+ };
+};
+
+
+/**
+ * Creates a function that returns true if each of its components evaluates
+ * to true. The components are evaluated in order, and the evaluation will be
+ * short-circuited as soon as a function returns false.
+ * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):boolean} A function that ANDs its component
+ * functions.
+ */
+goog.functions.and = function(var_args) {
+ var functions = arguments;
+ var length = functions.length;
+ return function() {
+ for (var i = 0; i < length; i++) {
+ if (!functions[i].apply(this, arguments)) {
+ return false;
+ }
+ }
+ return true;
+ };
+};
+
+
+/**
+ * Creates a function that returns true if any of its components evaluates
+ * to true. The components are evaluated in order, and the evaluation will be
+ * short-circuited as soon as a function returns true.
+ * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):boolean} A function that ORs its component
+ * functions.
+ */
+goog.functions.or = function(var_args) {
+ var functions = arguments;
+ var length = functions.length;
+ return function() {
+ for (var i = 0; i < length; i++) {
+ if (functions[i].apply(this, arguments)) {
+ return true;
+ }
+ }
+ return false;
+ };
+};
+
+
+/**
+ * Creates a function that returns the Boolean opposite of a provided function.
+ * For example, (goog.functions.not(f))(x) is equivalent to !f(x).
+ * @param {!Function} f The original function.
+ * @return {function(...?):boolean} A function that delegates to f and returns
+ * opposite.
+ */
+goog.functions.not = function(f) {
+ return function() { return !f.apply(this, arguments); };
+};
+
+
+/**
+ * Generic factory function to construct an object given the constructor
+ * and the arguments. Intended to be bound to create object factories.
+ *
+ * Example:
+ *
+ * var factory = goog.partial(goog.functions.create, Class);
+ *
+ * @param {function(new:T, ...)} constructor The constructor for the Object.
+ * @param {...*} var_args The arguments to be passed to the constructor.
+ * @return {T} A new instance of the class given in {@code constructor}.
+ * @template T
+ */
+goog.functions.create = function(constructor, var_args) {
+ /**
+ * @constructor
+ * @final
+ */
+ var temp = function() {};
+ temp.prototype = constructor.prototype;
+
+ // obj will have constructor's prototype in its chain and
+ // 'obj instanceof constructor' will be true.
+ var obj = new temp();
+
+ // obj is initialized by constructor.
+ // arguments is only array-like so lacks shift(), but can be used with
+ // the Array prototype function.
+ constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
+ return obj;
+};
+
+
+/**
+ * @define {boolean} Whether the return value cache should be used.
+ * This should only be used to disable caches when testing.
+ */
+goog.define('goog.functions.CACHE_RETURN_VALUE', true);
+
+
+/**
+ * Gives a wrapper function that caches the return value of a parameterless
+ * function when first called.
+ *
+ * When called for the first time, the given function is called and its
+ * return value is cached (thus this is only appropriate for idempotent
+ * functions). Subsequent calls will return the cached return value. This
+ * allows the evaluation of expensive functions to be delayed until first used.
+ *
+ * To cache the return values of functions with parameters, see goog.memoize.
+ *
+ * @param {!function():T} fn A function to lazily evaluate.
+ * @return {!function():T} A wrapped version the function.
+ * @template T
+ */
+goog.functions.cacheReturnValue = function(fn) {
+ var called = false;
+ var value;
+
+ return function() {
+ if (!goog.functions.CACHE_RETURN_VALUE) {
+ return fn();
+ }
+
+ if (!called) {
+ value = fn();
+ called = true;
+ }
+
+ return value;
+ };
+};
+
+
+/**
+ * Wraps a function to allow it to be called, at most, once. All
+ * additional calls are no-ops.
+ *
+ * This is particularly useful for initialization functions
+ * that should be called, at most, once.
+ *
+ * @param {function():*} f Function to call.
+ * @return {function():undefined} Wrapped function.
+ */
+goog.functions.once = function(f) {
+ // Keep a reference to the function that we null out when we're done with
+ // it -- that way, the function can be GC'd when we're done with it.
+ var inner = f;
+ return function() {
+ if (inner) {
+ var tmp = inner;
+ inner = null;
+ tmp();
+ }
+ };
+};
+
+
+/**
+ * Wraps a function to allow it to be called, at most, once for each sequence of
+ * calls fired repeatedly so long as they are fired less than a specified
+ * interval apart (in milliseconds). Whether it receives one signal or multiple,
+ * it will always wait until a full interval has elapsed since the last signal
+ * before performing the action, passing the arguments from the last call of the
+ * debouncing decorator into the decorated function.
+ *
+ * This is particularly useful for bulking up repeated user actions (e.g. only
+ * refreshing a view once a user finishes typing rather than updating with every
+ * keystroke). For more stateful debouncing with support for pausing, resuming,
+ * and canceling debounced actions, use {@code goog.async.Debouncer}.
+ *
+ * @param {function(this:SCOPE, ...?)} f Function to call.
+ * @param {number} interval Interval over which to debounce. The function will
+ * only be called after the full interval has elapsed since the last call.
+ * @param {SCOPE=} opt_scope Object in whose scope to call the function.
+ * @return {function(...?): undefined} Wrapped function.
+ * @template SCOPE
+ */
+goog.functions.debounce = function(f, interval, opt_scope) {
+ if (opt_scope) {
+ f = goog.bind(f, opt_scope);
+ }
+ var timeout = null;
+ return /** @type {function(...?)} */ (function(var_args) {
+ goog.global.clearTimeout(timeout);
+ var args = arguments;
+ timeout =
+ goog.global.setTimeout(function() { f.apply(null, args); }, interval);
+ });
+};
+
+
+/**
+ * Wraps a function to allow it to be called, at most, once per interval
+ * (specified in milliseconds). If it is called multiple times while it is
+ * waiting, it will only perform the action once at the end of the interval,
+ * passing the arguments from the last call of the throttling decorator into the
+ * decorated function.
+ *
+ * This is particularly useful for limiting repeated user requests (e.g.
+ * preventing a user from spamming a server with frequent view refreshes). For
+ * more stateful throttling with support for pausing, resuming, and canceling
+ * throttled actions, use {@code goog.async.Throttle}.
+ *
+ * @param {function(this:SCOPE, ...?)} f Function to call.
+ * @param {number} interval Interval over which to throttle. The function can
+ * only be called once per interval.
+ * @param {SCOPE=} opt_scope Object in whose scope to call the function.
+ * @return {function(...?): undefined} Wrapped function.
+ * @template SCOPE
+ */
+goog.functions.throttle = function(f, interval, opt_scope) {
+ if (opt_scope) {
+ f = goog.bind(f, opt_scope);
+ }
+ var timeout = null;
+ var shouldFire = false;
+ var args = [];
+
+ var handleTimeout = function() {
+ timeout = null;
+ if (shouldFire) {
+ shouldFire = false;
+ fire();
+ }
+ };
+
+ var fire = function() {
+ timeout = goog.global.setTimeout(handleTimeout, interval);
+ f.apply(null, args);
+ };
+
+ return /** @type {function(...?)} */ (function(var_args) {
+ args = arguments;
+ if (!timeout) {
+ fire();
+ } else {
+ shouldFire = true;
+ }
+ });
+};
+
+// Copyright 2013 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Provides a function to schedule running a function as soon
+ * as possible after the current JS execution stops and yields to the event
+ * loop.
+ *
+ */
+
+goog.provide('goog.async.nextTick');
+goog.provide('goog.async.throwException');
+
+goog.require('goog.debug.entryPointRegistry');
+goog.require('goog.dom.TagName');
+goog.require('goog.functions');
+goog.require('goog.labs.userAgent.browser');
+goog.require('goog.labs.userAgent.engine');
+
+
+/**
+ * Throw an item without interrupting the current execution context. For
+ * example, if processing a group of items in a loop, sometimes it is useful
+ * to report an error while still allowing the rest of the batch to be
+ * processed.
+ * @param {*} exception
+ */
+goog.async.throwException = function(exception) {
+ // Each throw needs to be in its own context.
+ goog.global.setTimeout(function() { throw exception; }, 0);
+};
+
+
+/**
+ * Fires the provided callbacks as soon as possible after the current JS
+ * execution context. setTimeout(…, 0) takes at least 4ms when called from
+ * within another setTimeout(…, 0) for legacy reasons.
+ *
+ * This will not schedule the callback as a microtask (i.e. a task that can
+ * preempt user input or networking callbacks). It is meant to emulate what
+ * setTimeout(_, 0) would do if it were not throttled. If you desire microtask
+ * behavior, use {@see goog.Promise} instead.
+ *
+ * @param {function(this:SCOPE)} callback Callback function to fire as soon as
+ * possible.
+ * @param {SCOPE=} opt_context Object in whose scope to call the listener.
+ * @param {boolean=} opt_useSetImmediate Avoid the IE workaround that
+ * ensures correctness at the cost of speed. See comments for details.
+ * @template SCOPE
+ */
+goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) {
+ var cb = callback;
+ if (opt_context) {
+ cb = goog.bind(callback, opt_context);
+ }
+ cb = goog.async.nextTick.wrapCallback_(cb);
+ // Note we do allow callers to also request setImmediate if they are willing
+ // to accept the possible tradeoffs of incorrectness in exchange for speed.
+ // The IE fallback of readystate change is much slower. See useSetImmediate_
+ // for details.
+ if (goog.isFunction(goog.global.setImmediate) &&
+ (opt_useSetImmediate || goog.async.nextTick.useSetImmediate_())) {
+ goog.global.setImmediate(cb);
+ return;
+ }
+
+ // Look for and cache the custom fallback version of setImmediate.
+ if (!goog.async.nextTick.setImmediate_) {
+ goog.async.nextTick.setImmediate_ =
+ goog.async.nextTick.getSetImmediateEmulator_();
+ }
+ goog.async.nextTick.setImmediate_(cb);
+};
+
+
+/**
+ * Returns whether should use setImmediate implementation currently on window.
+ *
+ * window.setImmediate was introduced and currently only supported by IE10+,
+ * but due to a bug in the implementation it is not guaranteed that
+ * setImmediate is faster than setTimeout nor that setImmediate N is before
+ * setImmediate N+1. That is why we do not use the native version if
+ * available. We do, however, call setImmediate if it is a non-native function
+ * because that indicates that it has been replaced by goog.testing.MockClock
+ * which we do want to support.
+ * See
+ * http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10
+ *
+ * @return {boolean} Whether to use the implementation of setImmediate defined
+ * on Window.
+ * @private
+ */
+goog.async.nextTick.useSetImmediate_ = function() {
+ // Not a browser environment.
+ if (!goog.global.Window || !goog.global.Window.prototype) {
+ return true;
+ }
+
+ // MS Edge has window.setImmediate natively, but it's not on Window.prototype.
+ // Also, there's no clean way to detect if the goog.global.setImmediate has
+ // been replaced by mockClock as its replacement also shows up as "[native
+ // code]" when using toString. Therefore, just always use
+ // goog.global.setImmediate for Edge. It's unclear if it suffers the same
+ // issues as IE10/11, but based on
+ // https://dev.modern.ie/testdrive/demos/setimmediatesorting/
+ // it seems they've been working to ensure it's WAI.
+ if (goog.labs.userAgent.browser.isEdge() ||
+ goog.global.Window.prototype.setImmediate != goog.global.setImmediate) {
+ // Something redefined setImmediate in which case we decide to use it (This
+ // is so that we use the mockClock setImmediate).
+ return true;
+ }
+
+ return false;
+};
+
+
+/**
+ * Cache for the setImmediate implementation.
+ * @type {function(function())}
+ * @private
+ */
+goog.async.nextTick.setImmediate_;
+
+
+/**
+ * Determines the best possible implementation to run a function as soon as
+ * the JS event loop is idle.
+ * @return {function(function())} The "setImmediate" implementation.
+ * @private
+ */
+goog.async.nextTick.getSetImmediateEmulator_ = function() {
+ // Create a private message channel and use it to postMessage empty messages
+ // to ourselves.
+ var Channel = goog.global['MessageChannel'];
+ // If MessageChannel is not available and we are in a browser, implement
+ // an iframe based polyfill in browsers that have postMessage and
+ // document.addEventListener. The latter excludes IE8 because it has a
+ // synchronous postMessage implementation.
+ if (typeof Channel === 'undefined' && typeof window !== 'undefined' &&
+ window.postMessage && window.addEventListener &&
+ // Presto (The old pre-blink Opera engine) has problems with iframes
+ // and contentWindow.
+ !goog.labs.userAgent.engine.isPresto()) {
+ /** @constructor */
+ Channel = function() {
+ // Make an empty, invisible iframe.
+ var iframe = /** @type {!HTMLIFrameElement} */ (
+ document.createElement(goog.dom.TagName.IFRAME));
+ iframe.style.display = 'none';
+ iframe.src = '';
+ document.documentElement.appendChild(iframe);
+ var win = iframe.contentWindow;
+ var doc = win.document;
+ doc.open();
+ doc.write('');
+ doc.close();
+ // Do not post anything sensitive over this channel, as the workaround for
+ // pages with file: origin could allow that information to be modified or
+ // intercepted.
+ var message = 'callImmediate' + Math.random();
+ // The same origin policy rejects attempts to postMessage from file: urls
+ // unless the origin is '*'.
+ // TODO(b/16335441): Use '*' origin for data: and other similar protocols.
+ var origin = win.location.protocol == 'file:' ?
+ '*' :
+ win.location.protocol + '//' + win.location.host;
+ var onmessage = goog.bind(function(e) {
+ // Validate origin and message to make sure that this message was
+ // intended for us. If the origin is set to '*' (see above) only the
+ // message needs to match since, for example, '*' != 'file://'. Allowing
+ // the wildcard is ok, as we are not concerned with security here.
+ if ((origin != '*' && e.origin != origin) || e.data != message) {
+ return;
+ }
+ this['port1'].onmessage();
+ }, this);
+ win.addEventListener('message', onmessage, false);
+ this['port1'] = {};
+ this['port2'] = {
+ postMessage: function() { win.postMessage(message, origin); }
+ };
+ };
+ }
+ if (typeof Channel !== 'undefined' && (!goog.labs.userAgent.browser.isIE())) {
+ // Exclude all of IE due to
+ // http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
+ // which allows starving postMessage with a busy setTimeout loop.
+ // This currently affects IE10 and IE11 which would otherwise be able
+ // to use the postMessage based fallbacks.
+ var channel = new Channel();
+ // Use a fifo linked list to call callbacks in the right order.
+ var head = {};
+ var tail = head;
+ channel['port1'].onmessage = function() {
+ if (goog.isDef(head.next)) {
+ head = head.next;
+ var cb = head.cb;
+ head.cb = null;
+ cb();
+ }
+ };
+ return function(cb) {
+ tail.next = {cb: cb};
+ tail = tail.next;
+ channel['port2'].postMessage(0);
+ };
+ }
+ // Implementation for IE6 to IE10: Script elements fire an asynchronous
+ // onreadystatechange event when inserted into the DOM.
+ if (typeof document !== 'undefined' &&
+ 'onreadystatechange' in document.createElement(goog.dom.TagName.SCRIPT)) {
+ return function(cb) {
+ var script = document.createElement(goog.dom.TagName.SCRIPT);
+ script.onreadystatechange = function() {
+ // Clean up and call the callback.
+ script.onreadystatechange = null;
+ script.parentNode.removeChild(script);
+ script = null;
+ cb();
+ cb = null;
+ };
+ document.documentElement.appendChild(script);
+ };
+ }
+ // Fall back to setTimeout with 0. In browsers this creates a delay of 5ms
+ // or more.
+ // NOTE(user): This fallback is used for IE11.
+ return function(cb) { goog.global.setTimeout(cb, 0); };
+};
+
+
+/**
+ * Helper function that is overrided to protect callbacks with entry point
+ * monitor if the application monitors entry points.
+ * @param {function()} callback Callback function to fire as soon as possible.
+ * @return {function()} The wrapped callback.
+ * @private
+ */
+goog.async.nextTick.wrapCallback_ = goog.functions.identity;
+
+
+// Register the callback function as an entry point, so that it can be
+// monitored for exception handling, etc. This has to be done in this file
+// since it requires special code to handle all browsers.
+goog.debug.entryPointRegistry.register(
+ /**
+ * @param {function(!Function): !Function} transformer The transforming
+ * function.
+ */
+ function(transformer) { goog.async.nextTick.wrapCallback_ = transformer; });
+
+// Based on https://github.com/Polymer/PointerEvents
+
+// Copyright (c) 2013 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.pointer.PointerEvent');
+
+
+goog.require('ol.events');
+goog.require('ol.events.Event');
+
+
+/**
+ * A class for pointer events.
+ *
+ * This class is used as an abstraction for mouse events,
+ * touch events and even native pointer events.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @param {string} type The type of the event to create.
+ * @param {Event} originalEvent The event.
+ * @param {Object.<string, ?>=} opt_eventDict An optional dictionary of
+ * initial event properties.
+ */
+ol.pointer.PointerEvent = function(type, originalEvent, opt_eventDict) {
+ ol.events.Event.call(this, type);
+
+ /**
+ * @const
+ * @type {Event}
+ */
+ this.originalEvent = originalEvent;
+
+ var eventDict = opt_eventDict ? opt_eventDict : {};
+
+ /**
+ * @type {number}
+ */
+ this.buttons = this.getButtons_(eventDict);
+
+ /**
+ * @type {number}
+ */
+ this.pressure = this.getPressure_(eventDict, this.buttons);
+
+ // MouseEvent related properties
+
+ /**
+ * @type {boolean}
+ */
+ this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;
+
+ /**
+ * @type {boolean}
+ */
+ this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;
+
+ /**
+ * @type {Object}
+ */
+ this.view = 'view' in eventDict ? eventDict['view'] : null;
+
+ /**
+ * @type {number}
+ */
+ this.detail = 'detail' in eventDict ? eventDict['detail'] : null;
+
+ /**
+ * @type {number}
+ */
+ this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;
+
+ /**
+ * @type {boolean}
+ */
+ this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;
+
+ /**
+ * @type {boolean}
+ */
+ this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;
+
+ /**
+ * @type {boolean}
+ */
+ this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;
+
+ /**
+ * @type {boolean}
+ */
+ this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;
+
+ /**
+ * @type {number}
+ */
+ this.button = 'button' in eventDict ? eventDict['button'] : 0;
+
+ /**
+ * @type {Node}
+ */
+ this.relatedTarget = 'relatedTarget' in eventDict ?
+ eventDict['relatedTarget'] : null;
+
+ // PointerEvent related properties
+
+ /**
+ * @const
+ * @type {number}
+ */
+ this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.width = 'width' in eventDict ? eventDict['width'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.height = 'height' in eventDict ? eventDict['height'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;
+
+ /**
+ * @type {number}
+ */
+ this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;
+
+ /**
+ * @type {string}
+ */
+ this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';
+
+ /**
+ * @type {number}
+ */
+ this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;
+
+ /**
+ * @type {boolean}
+ */
+ this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;
+
+ // keep the semantics of preventDefault
+ if (originalEvent.preventDefault) {
+ this.preventDefault = function() {
+ originalEvent.preventDefault();
+ };
+ }
+};
+ol.inherits(ol.pointer.PointerEvent, ol.events.Event);
+
+
+/**
+ * @private
+ * @param {Object.<string, ?>} eventDict The event dictionary.
+ * @return {number} Button indicator.
+ */
+ol.pointer.PointerEvent.prototype.getButtons_ = function(eventDict) {
+ // According to the w3c spec,
+ // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
+ // MouseEvent.button == 0 can mean either no mouse button depressed, or the
+ // left mouse button depressed.
+ //
+ // As of now, the only way to distinguish between the two states of
+ // MouseEvent.button is by using the deprecated MouseEvent.which property, as
+ // this maps mouse buttons to positive integers > 0, and uses 0 to mean that
+ // no mouse button is held.
+ //
+ // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
+ // but initMouseEvent does not expose an argument with which to set
+ // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
+ // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
+ // of app developers.
+ //
+ // The only way to propagate the correct state of MouseEvent.which and
+ // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
+ // is to call initMouseEvent with a buttonArg value of -1.
+ //
+ // This is fixed with DOM Level 4's use of buttons
+ var buttons;
+ if (eventDict.buttons || ol.pointer.PointerEvent.HAS_BUTTONS) {
+ buttons = eventDict.buttons;
+ } else {
+ switch (eventDict.which) {
+ case 1: buttons = 1; break;
+ case 2: buttons = 4; break;
+ case 3: buttons = 2; break;
+ default: buttons = 0;
+ }
+ }
+ return buttons;
+};
+
+
+/**
+ * @private
+ * @param {Object.<string, ?>} eventDict The event dictionary.
+ * @param {number} buttons Button indicator.
+ * @return {number} The pressure.
+ */
+ol.pointer.PointerEvent.prototype.getPressure_ = function(eventDict, buttons) {
+ // Spec requires that pointers without pressure specified use 0.5 for down
+ // state and 0 for up state.
+ var pressure = 0;
+ if (eventDict.pressure) {
+ pressure = eventDict.pressure;
+ } else {
+ pressure = buttons ? 0.5 : 0;
+ }
+ return pressure;
+};
+
+
+/**
+ * Is the `buttons` property supported?
+ * @type {boolean}
+ */
+ol.pointer.PointerEvent.HAS_BUTTONS = false;
+
+
+/**
+ * Checks if the `buttons` property is supported.
+ */
+(function() {
+ try {
+ var ev = new MouseEvent('click', {buttons: 1});
+ ol.pointer.PointerEvent.HAS_BUTTONS = ev.buttons === 1;
+ } catch (e) {
+ // pass
+ }
+})();
+
+goog.provide('ol.webgl');
+goog.provide('ol.webgl.WebGLContextEventType');
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<string>}
+ */
+ol.webgl.CONTEXT_IDS_ = [
+ 'experimental-webgl',
+ 'webgl',
+ 'webkit-3d',
+ 'moz-webgl'
+];
+
+
+/**
+ * @enum {string}
+ */
+ol.webgl.WebGLContextEventType = {
+ LOST: 'webglcontextlost',
+ RESTORED: 'webglcontextrestored'
+};
+
+
+/**
+ * @param {HTMLCanvasElement} canvas Canvas.
+ * @param {Object=} opt_attributes Attributes.
+ * @return {WebGLRenderingContext} WebGL rendering context.
+ */
+ol.webgl.getContext = function(canvas, opt_attributes) {
+ var context, i, ii = ol.webgl.CONTEXT_IDS_.length;
+ for (i = 0; i < ii; ++i) {
+ try {
+ context = canvas.getContext(ol.webgl.CONTEXT_IDS_[i], opt_attributes);
+ if (context) {
+ return /** @type {!WebGLRenderingContext} */ (context);
+ }
+ } catch (e) {
+ // pass
+ }
+ }
+ return null;
+};
+
+goog.provide('ol.has');
+
+goog.require('ol');
+goog.require('ol.dom');
+goog.require('ol.webgl');
+
+
+var ua = typeof navigator !== 'undefined' ?
+ navigator.userAgent.toLowerCase() : '';
+
+/**
+ * User agent string says we are dealing with Firefox as browser.
+ * @type {boolean}
+ */
+ol.has.FIREFOX = ua.indexOf('firefox') !== -1;
+
+/**
+ * User agent string says we are dealing with Safari as browser.
+ * @type {boolean}
+ */
+ol.has.SAFARI = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') === -1;
+
+/**
+ * User agent string says we are dealing with a Mac as platform.
+ * @type {boolean}
+ */
+ol.has.MAC = ua.indexOf('macintosh') !== -1;
+
+
+/**
+ * The ratio between physical pixels and device-independent pixels
+ * (dips) on the device (`window.devicePixelRatio`).
+ * @const
+ * @type {number}
+ * @api stable
+ */
+ol.has.DEVICE_PIXEL_RATIO = ol.global.devicePixelRatio || 1;
+
+
+/**
+ * True if the browser's Canvas implementation implements {get,set}LineDash.
+ * @type {boolean}
+ */
+ol.has.CANVAS_LINE_DASH = false;
+
+
+/**
+ * True if both the library and browser support Canvas. Always `false`
+ * if `ol.ENABLE_CANVAS` is set to `false` at compile time.
+ * @const
+ * @type {boolean}
+ * @api stable
+ */
+ol.has.CANVAS = ol.ENABLE_CANVAS && (
+ /**
+ * @return {boolean} Canvas supported.
+ */
+ function() {
+ if (!('HTMLCanvasElement' in ol.global)) {
+ return false;
+ }
+ try {
+ var context = ol.dom.createCanvasContext2D();
+ if (!context) {
+ return false;
+ } else {
+ if (context.setLineDash !== undefined) {
+ ol.has.CANVAS_LINE_DASH = true;
+ }
+ return true;
+ }
+ } catch (e) {
+ return false;
+ }
+ })();
+
+
+/**
+ * Indicates if DeviceOrientation is supported in the user's browser.
+ * @const
+ * @type {boolean}
+ * @api stable
+ */
+ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in ol.global;
+
+
+/**
+ * True if `ol.ENABLE_DOM` is set to `true` at compile time.
+ * @const
+ * @type {boolean}
+ */
+ol.has.DOM = ol.ENABLE_DOM;
+
+
+/**
+ * Is HTML5 geolocation supported in the current browser?
+ * @const
+ * @type {boolean}
+ * @api stable
+ */
+ol.has.GEOLOCATION = 'geolocation' in ol.global.navigator;
+
+
+/**
+ * True if browser supports touch events.
+ * @const
+ * @type {boolean}
+ * @api stable
+ */
+ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in ol.global;
+
+
+/**
+ * True if browser supports pointer events.
+ * @const
+ * @type {boolean}
+ */
+ol.has.POINTER = 'PointerEvent' in ol.global;
+
+
+/**
+ * True if browser supports ms pointer events (IE 10).
+ * @const
+ * @type {boolean}
+ */
+ol.has.MSPOINTER = !!(ol.global.navigator.msPointerEnabled);
+
+
+/**
+ * True if both OpenLayers and browser support WebGL. Always `false`
+ * if `ol.ENABLE_WEBGL` is set to `false` at compile time.
+ * @const
+ * @type {boolean}
+ * @api stable
+ */
+ol.has.WEBGL;
+
+
+(function() {
+ if (ol.ENABLE_WEBGL) {
+ var hasWebGL = false;
+ var textureSize;
+ var /** @type {Array.<string>} */ extensions = [];
+
+ if ('WebGLRenderingContext' in ol.global) {
+ try {
+ var canvas = /** @type {HTMLCanvasElement} */
+ (document.createElement('CANVAS'));
+ var gl = ol.webgl.getContext(canvas, {
+ failIfMajorPerformanceCaveat: true
+ });
+ if (gl) {
+ hasWebGL = true;
+ textureSize = /** @type {number} */
+ (gl.getParameter(gl.MAX_TEXTURE_SIZE));
+ extensions = gl.getSupportedExtensions();
+ }
+ } catch (e) {
+ // pass
+ }
+ }
+ ol.has.WEBGL = hasWebGL;
+ ol.WEBGL_EXTENSIONS = extensions;
+ ol.WEBGL_MAX_TEXTURE_SIZE = textureSize;
+ }
+})();
+
+goog.provide('ol.pointer.EventSource');
+
+
+/**
+ * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
+ * @param {!Object.<string, function(Event)>} mapping Event
+ * mapping.
+ * @constructor
+ */
+ol.pointer.EventSource = function(dispatcher, mapping) {
+ /**
+ * @type {ol.pointer.PointerEventHandler}
+ */
+ this.dispatcher = dispatcher;
+
+ /**
+ * @private
+ * @const
+ * @type {!Object.<string, function(Event)>}
+ */
+ this.mapping_ = mapping;
+};
+
+
+/**
+ * List of events supported by this source.
+ * @return {Array.<string>} Event names
+ */
+ol.pointer.EventSource.prototype.getEvents = function() {
+ return Object.keys(this.mapping_);
+};
+
+
+/**
+ * Returns a mapping between the supported event types and
+ * the handlers that should handle an event.
+ * @return {Object.<string, function(Event)>}
+ * Event/Handler mapping
+ */
+ol.pointer.EventSource.prototype.getMapping = function() {
+ return this.mapping_;
+};
+
+
+/**
+ * Returns the handler that should handle a given event type.
+ * @param {string} eventType The event type.
+ * @return {function(Event)} Handler
+ */
+ol.pointer.EventSource.prototype.getHandlerForEvent = function(eventType) {
+ return this.mapping_[eventType];
+};
+
+// Based on https://github.com/Polymer/PointerEvents
+
+// Copyright (c) 2013 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.pointer.MouseSource');
+
+goog.require('ol.pointer.EventSource');
+
+
+/**
+ * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
+ * @constructor
+ * @extends {ol.pointer.EventSource}
+ */
+ol.pointer.MouseSource = function(dispatcher) {
+ var mapping = {
+ 'mousedown': this.mousedown,
+ 'mousemove': this.mousemove,
+ 'mouseup': this.mouseup,
+ 'mouseover': this.mouseover,
+ 'mouseout': this.mouseout
+ };
+ ol.pointer.EventSource.call(this, dispatcher, mapping);
+
+ /**
+ * @const
+ * @type {!Object.<string, Event|Object>}
+ */
+ this.pointerMap = dispatcher.pointerMap;
+
+ /**
+ * @const
+ * @type {Array.<ol.Pixel>}
+ */
+ this.lastTouches = [];
+};
+ol.inherits(ol.pointer.MouseSource, ol.pointer.EventSource);
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.pointer.MouseSource.POINTER_ID = 1;
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.pointer.MouseSource.POINTER_TYPE = 'mouse';
+
+
+/**
+ * Radius around touchend that swallows mouse events.
+ *
+ * @const
+ * @type {number}
+ */
+ol.pointer.MouseSource.DEDUP_DIST = 25;
+
+
+/**
+ * Detect if a mouse event was simulated from a touch by
+ * checking if previously there was a touch event at the
+ * same position.
+ *
+ * FIXME - Known problem with the native Android browser on
+ * Samsung GT-I9100 (Android 4.1.2):
+ * In case the page is scrolled, this function does not work
+ * correctly when a canvas is used (WebGL or canvas renderer).
+ * Mouse listeners on canvas elements (for this browser), create
+ * two mouse events: One 'good' and one 'bad' one (on other browsers or
+ * when a div is used, there is only one event). For the 'bad' one,
+ * clientX/clientY and also pageX/pageY are wrong when the page
+ * is scrolled. Because of that, this function can not detect if
+ * the events were simulated from a touch event. As result, a
+ * pointer event at a wrong position is dispatched, which confuses
+ * the map interactions.
+ * It is unclear, how one can get the correct position for the event
+ * or detect that the positions are invalid.
+ *
+ * @private
+ * @param {Event} inEvent The in event.
+ * @return {boolean} True, if the event was generated by a touch.
+ */
+ol.pointer.MouseSource.prototype.isEventSimulatedFromTouch_ = function(inEvent) {
+ var lts = this.lastTouches;
+ var x = inEvent.clientX, y = inEvent.clientY;
+ for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
+ // simulated mouse events will be swallowed near a primary touchend
+ var dx = Math.abs(x - t[0]), dy = Math.abs(y - t[1]);
+ if (dx <= ol.pointer.MouseSource.DEDUP_DIST &&
+ dy <= ol.pointer.MouseSource.DEDUP_DIST) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Creates a copy of the original event that will be used
+ * for the fake pointer event.
+ *
+ * @param {Event} inEvent The in event.
+ * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
+ * @return {Object} The copied event.
+ */
+ol.pointer.MouseSource.prepareEvent = function(inEvent, dispatcher) {
+ var e = dispatcher.cloneEvent(inEvent, inEvent);
+
+ // forward mouse preventDefault
+ var pd = e.preventDefault;
+ e.preventDefault = function() {
+ inEvent.preventDefault();
+ pd();
+ };
+
+ e.pointerId = ol.pointer.MouseSource.POINTER_ID;
+ e.isPrimary = true;
+ e.pointerType = ol.pointer.MouseSource.POINTER_TYPE;
+
+ return e;
+};
+
+
+/**
+ * Handler for `mousedown`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MouseSource.prototype.mousedown = function(inEvent) {
+ if (!this.isEventSimulatedFromTouch_(inEvent)) {
+ // TODO(dfreedman) workaround for some elements not sending mouseup
+ // http://crbug/149091
+ if (ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap) {
+ this.cancel(inEvent);
+ }
+ var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
+ this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()] = inEvent;
+ this.dispatcher.down(e, inEvent);
+ }
+};
+
+
+/**
+ * Handler for `mousemove`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MouseSource.prototype.mousemove = function(inEvent) {
+ if (!this.isEventSimulatedFromTouch_(inEvent)) {
+ var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
+ this.dispatcher.move(e, inEvent);
+ }
+};
+
+
+/**
+ * Handler for `mouseup`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MouseSource.prototype.mouseup = function(inEvent) {
+ if (!this.isEventSimulatedFromTouch_(inEvent)) {
+ var p = this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()];
+
+ if (p && p.button === inEvent.button) {
+ var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
+ this.dispatcher.up(e, inEvent);
+ this.cleanupMouse();
+ }
+ }
+};
+
+
+/**
+ * Handler for `mouseover`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MouseSource.prototype.mouseover = function(inEvent) {
+ if (!this.isEventSimulatedFromTouch_(inEvent)) {
+ var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
+ this.dispatcher.enterOver(e, inEvent);
+ }
+};
+
+
+/**
+ * Handler for `mouseout`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MouseSource.prototype.mouseout = function(inEvent) {
+ if (!this.isEventSimulatedFromTouch_(inEvent)) {
+ var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
+ this.dispatcher.leaveOut(e, inEvent);
+ }
+};
+
+
+/**
+ * Dispatches a `pointercancel` event.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MouseSource.prototype.cancel = function(inEvent) {
+ var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
+ this.dispatcher.cancel(e, inEvent);
+ this.cleanupMouse();
+};
+
+
+/**
+ * Remove the mouse from the list of active pointers.
+ */
+ol.pointer.MouseSource.prototype.cleanupMouse = function() {
+ delete this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()];
+};
+
+// Based on https://github.com/Polymer/PointerEvents
+
+// Copyright (c) 2013 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.pointer.MsSource');
+
+goog.require('ol.pointer.EventSource');
+
+
+/**
+ * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
+ * @constructor
+ * @extends {ol.pointer.EventSource}
+ */
+ol.pointer.MsSource = function(dispatcher) {
+ var mapping = {
+ 'MSPointerDown': this.msPointerDown,
+ 'MSPointerMove': this.msPointerMove,
+ 'MSPointerUp': this.msPointerUp,
+ 'MSPointerOut': this.msPointerOut,
+ 'MSPointerOver': this.msPointerOver,
+ 'MSPointerCancel': this.msPointerCancel,
+ 'MSGotPointerCapture': this.msGotPointerCapture,
+ 'MSLostPointerCapture': this.msLostPointerCapture
+ };
+ ol.pointer.EventSource.call(this, dispatcher, mapping);
+
+ /**
+ * @const
+ * @type {!Object.<string, Event|Object>}
+ */
+ this.pointerMap = dispatcher.pointerMap;
+
+ /**
+ * @const
+ * @type {Array.<string>}
+ */
+ this.POINTER_TYPES = [
+ '',
+ 'unavailable',
+ 'touch',
+ 'pen',
+ 'mouse'
+ ];
+};
+ol.inherits(ol.pointer.MsSource, ol.pointer.EventSource);
+
+
+/**
+ * Creates a copy of the original event that will be used
+ * for the fake pointer event.
+ *
+ * @private
+ * @param {Event} inEvent The in event.
+ * @return {Object} The copied event.
+ */
+ol.pointer.MsSource.prototype.prepareEvent_ = function(inEvent) {
+ var e = inEvent;
+ if (goog.isNumber(inEvent.pointerType)) {
+ e = this.dispatcher.cloneEvent(inEvent, inEvent);
+ e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
+ }
+
+ return e;
+};
+
+
+/**
+ * Remove this pointer from the list of active pointers.
+ * @param {number} pointerId Pointer identifier.
+ */
+ol.pointer.MsSource.prototype.cleanup = function(pointerId) {
+ delete this.pointerMap[pointerId.toString()];
+};
+
+
+/**
+ * Handler for `msPointerDown`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msPointerDown = function(inEvent) {
+ this.pointerMap[inEvent.pointerId.toString()] = inEvent;
+ var e = this.prepareEvent_(inEvent);
+ this.dispatcher.down(e, inEvent);
+};
+
+
+/**
+ * Handler for `msPointerMove`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msPointerMove = function(inEvent) {
+ var e = this.prepareEvent_(inEvent);
+ this.dispatcher.move(e, inEvent);
+};
+
+
+/**
+ * Handler for `msPointerUp`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msPointerUp = function(inEvent) {
+ var e = this.prepareEvent_(inEvent);
+ this.dispatcher.up(e, inEvent);
+ this.cleanup(inEvent.pointerId);
+};
+
+
+/**
+ * Handler for `msPointerOut`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msPointerOut = function(inEvent) {
+ var e = this.prepareEvent_(inEvent);
+ this.dispatcher.leaveOut(e, inEvent);
+};
+
+
+/**
+ * Handler for `msPointerOver`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msPointerOver = function(inEvent) {
+ var e = this.prepareEvent_(inEvent);
+ this.dispatcher.enterOver(e, inEvent);
+};
+
+
+/**
+ * Handler for `msPointerCancel`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msPointerCancel = function(inEvent) {
+ var e = this.prepareEvent_(inEvent);
+ this.dispatcher.cancel(e, inEvent);
+ this.cleanup(inEvent.pointerId);
+};
+
+
+/**
+ * Handler for `msLostPointerCapture`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msLostPointerCapture = function(inEvent) {
+ var e = this.dispatcher.makeEvent('lostpointercapture',
+ inEvent, inEvent);
+ this.dispatcher.dispatchEvent(e);
+};
+
+
+/**
+ * Handler for `msGotPointerCapture`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.MsSource.prototype.msGotPointerCapture = function(inEvent) {
+ var e = this.dispatcher.makeEvent('gotpointercapture',
+ inEvent, inEvent);
+ this.dispatcher.dispatchEvent(e);
+};
+
+// Based on https://github.com/Polymer/PointerEvents
+
+// Copyright (c) 2013 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.pointer.NativeSource');
+
+goog.require('ol.pointer.EventSource');
+
+
+/**
+ * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
+ * @constructor
+ * @extends {ol.pointer.EventSource}
+ */
+ol.pointer.NativeSource = function(dispatcher) {
+ var mapping = {
+ 'pointerdown': this.pointerDown,
+ 'pointermove': this.pointerMove,
+ 'pointerup': this.pointerUp,
+ 'pointerout': this.pointerOut,
+ 'pointerover': this.pointerOver,
+ 'pointercancel': this.pointerCancel,
+ 'gotpointercapture': this.gotPointerCapture,
+ 'lostpointercapture': this.lostPointerCapture
+ };
+ ol.pointer.EventSource.call(this, dispatcher, mapping);
+};
+ol.inherits(ol.pointer.NativeSource, ol.pointer.EventSource);
+
+
+/**
+ * Handler for `pointerdown`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.pointerDown = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `pointermove`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.pointerMove = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `pointerup`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.pointerUp = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `pointerout`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.pointerOut = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `pointerover`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.pointerOver = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `pointercancel`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.pointerCancel = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `lostpointercapture`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.lostPointerCapture = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+
+/**
+ * Handler for `gotpointercapture`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.NativeSource.prototype.gotPointerCapture = function(inEvent) {
+ this.dispatcher.fireNativeEvent(inEvent);
+};
+
+// Based on https://github.com/Polymer/PointerEvents
+
+// Copyright (c) 2013 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.pointer.TouchSource');
+
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.pointer.EventSource');
+goog.require('ol.pointer.MouseSource');
+
+
+/**
+ * @constructor
+ * @param {ol.pointer.PointerEventHandler} dispatcher The event handler.
+ * @param {ol.pointer.MouseSource} mouseSource Mouse source.
+ * @extends {ol.pointer.EventSource}
+ */
+ol.pointer.TouchSource = function(dispatcher, mouseSource) {
+ var mapping = {
+ 'touchstart': this.touchstart,
+ 'touchmove': this.touchmove,
+ 'touchend': this.touchend,
+ 'touchcancel': this.touchcancel
+ };
+ ol.pointer.EventSource.call(this, dispatcher, mapping);
+
+ /**
+ * @const
+ * @type {!Object.<string, Event|Object>}
+ */
+ this.pointerMap = dispatcher.pointerMap;
+
+ /**
+ * @const
+ * @type {ol.pointer.MouseSource}
+ */
+ this.mouseSource = mouseSource;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.firstTouchId_ = undefined;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.clickCount_ = 0;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.resetId_ = undefined;
+};
+ol.inherits(ol.pointer.TouchSource, ol.pointer.EventSource);
+
+
+/**
+ * Mouse event timeout: This should be long enough to
+ * ignore compat mouse events made by touch.
+ * @const
+ * @type {number}
+ */
+ol.pointer.TouchSource.DEDUP_TIMEOUT = 2500;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT = 200;
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.pointer.TouchSource.POINTER_TYPE = 'touch';
+
+
+/**
+ * @private
+ * @param {Touch} inTouch The in touch.
+ * @return {boolean} True, if this is the primary touch.
+ */
+ol.pointer.TouchSource.prototype.isPrimaryTouch_ = function(inTouch) {
+ return this.firstTouchId_ === inTouch.identifier;
+};
+
+
+/**
+ * Set primary touch if there are no pointers, or the only pointer is the mouse.
+ * @param {Touch} inTouch The in touch.
+ * @private
+ */
+ol.pointer.TouchSource.prototype.setPrimaryTouch_ = function(inTouch) {
+ var count = Object.keys(this.pointerMap).length;
+ if (count === 0 || (count === 1 &&
+ ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap)) {
+ this.firstTouchId_ = inTouch.identifier;
+ this.cancelResetClickCount_();
+ }
+};
+
+
+/**
+ * @private
+ * @param {Object} inPointer The in pointer object.
+ */
+ol.pointer.TouchSource.prototype.removePrimaryPointer_ = function(inPointer) {
+ if (inPointer.isPrimary) {
+ this.firstTouchId_ = undefined;
+ this.resetClickCount_();
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.pointer.TouchSource.prototype.resetClickCount_ = function() {
+ this.resetId_ = ol.global.setTimeout(
+ this.resetClickCountHandler_.bind(this),
+ ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT);
+};
+
+
+/**
+ * @private
+ */
+ol.pointer.TouchSource.prototype.resetClickCountHandler_ = function() {
+ this.clickCount_ = 0;
+ this.resetId_ = undefined;
+};
+
+
+/**
+ * @private
+ */
+ol.pointer.TouchSource.prototype.cancelResetClickCount_ = function() {
+ if (this.resetId_ !== undefined) {
+ ol.global.clearTimeout(this.resetId_);
+ }
+};
+
+
+/**
+ * @private
+ * @param {Event} browserEvent Browser event
+ * @param {Touch} inTouch Touch event
+ * @return {Object} A pointer object.
+ */
+ol.pointer.TouchSource.prototype.touchToPointer_ = function(browserEvent, inTouch) {
+ var e = this.dispatcher.cloneEvent(browserEvent, inTouch);
+ // Spec specifies that pointerId 1 is reserved for Mouse.
+ // Touch identifiers can start at 0.
+ // Add 2 to the touch identifier for compatibility.
+ e.pointerId = inTouch.identifier + 2;
+ // TODO: check if this is necessary?
+ //e.target = findTarget(e);
+ e.bubbles = true;
+ e.cancelable = true;
+ e.detail = this.clickCount_;
+ e.button = 0;
+ e.buttons = 1;
+ e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
+ e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
+ e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
+ e.isPrimary = this.isPrimaryTouch_(inTouch);
+ e.pointerType = ol.pointer.TouchSource.POINTER_TYPE;
+
+ // make sure that the properties that are different for
+ // each `Touch` object are not copied from the BrowserEvent object
+ e.clientX = inTouch.clientX;
+ e.clientY = inTouch.clientY;
+ e.screenX = inTouch.screenX;
+ e.screenY = inTouch.screenY;
+
+ return e;
+};
+
+
+/**
+ * @private
+ * @param {Event} inEvent Touch event
+ * @param {function(Event, Object)} inFunction In function.
+ */
+ol.pointer.TouchSource.prototype.processTouches_ = function(inEvent, inFunction) {
+ var touches = Array.prototype.slice.call(
+ inEvent.changedTouches);
+ var count = touches.length;
+ function preventDefault() {
+ inEvent.preventDefault();
+ }
+ var i, pointer;
+ for (i = 0; i < count; ++i) {
+ pointer = this.touchToPointer_(inEvent, touches[i]);
+ // forward touch preventDefaults
+ pointer.preventDefault = preventDefault;
+ inFunction.call(this, inEvent, pointer);
+ }
+};
+
+
+/**
+ * @private
+ * @param {TouchList} touchList The touch list.
+ * @param {number} searchId Search identifier.
+ * @return {boolean} True, if the `Touch` with the given id is in the list.
+ */
+ol.pointer.TouchSource.prototype.findTouch_ = function(touchList, searchId) {
+ var l = touchList.length;
+ var touch;
+ for (var i = 0; i < l; i++) {
+ touch = touchList[i];
+ if (touch.identifier === searchId) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * In some instances, a touchstart can happen without a touchend. This
+ * leaves the pointermap in a broken state.
+ * Therefore, on every touchstart, we remove the touches that did not fire a
+ * touchend event.
+ * To keep state globally consistent, we fire a pointercancel for
+ * this "abandoned" touch
+ *
+ * @private
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.TouchSource.prototype.vacuumTouches_ = function(inEvent) {
+ var touchList = inEvent.touches;
+ // pointerMap.getCount() should be < touchList.length here,
+ // as the touchstart has not been processed yet.
+ var keys = Object.keys(this.pointerMap);
+ var count = keys.length;
+ if (count >= touchList.length) {
+ var d = [];
+ var i, key, value;
+ for (i = 0; i < count; ++i) {
+ key = keys[i];
+ value = this.pointerMap[key];
+ // Never remove pointerId == 1, which is mouse.
+ // Touch identifiers are 2 smaller than their pointerId, which is the
+ // index in pointermap.
+ if (key != ol.pointer.MouseSource.POINTER_ID &&
+ !this.findTouch_(touchList, key - 2)) {
+ d.push(value.out);
+ }
+ }
+ for (i = 0; i < d.length; ++i) {
+ this.cancelOut_(inEvent, d[i]);
+ }
+ }
+};
+
+
+/**
+ * Handler for `touchstart`, triggers `pointerover`,
+ * `pointerenter` and `pointerdown` events.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.TouchSource.prototype.touchstart = function(inEvent) {
+ this.vacuumTouches_(inEvent);
+ this.setPrimaryTouch_(inEvent.changedTouches[0]);
+ this.dedupSynthMouse_(inEvent);
+ this.clickCount_++;
+ this.processTouches_(inEvent, this.overDown_);
+};
+
+
+/**
+ * @private
+ * @param {Event} browserEvent The event.
+ * @param {Object} inPointer The in pointer object.
+ */
+ol.pointer.TouchSource.prototype.overDown_ = function(browserEvent, inPointer) {
+ this.pointerMap[inPointer.pointerId] = {
+ target: inPointer.target,
+ out: inPointer,
+ outTarget: inPointer.target
+ };
+ this.dispatcher.over(inPointer, browserEvent);
+ this.dispatcher.enter(inPointer, browserEvent);
+ this.dispatcher.down(inPointer, browserEvent);
+};
+
+
+/**
+ * Handler for `touchmove`.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.TouchSource.prototype.touchmove = function(inEvent) {
+ inEvent.preventDefault();
+ this.processTouches_(inEvent, this.moveOverOut_);
+};
+
+
+/**
+ * @private
+ * @param {Event} browserEvent The event.
+ * @param {Object} inPointer The in pointer.
+ */
+ol.pointer.TouchSource.prototype.moveOverOut_ = function(browserEvent, inPointer) {
+ var event = inPointer;
+ var pointer = this.pointerMap[event.pointerId];
+ // a finger drifted off the screen, ignore it
+ if (!pointer) {
+ return;
+ }
+ var outEvent = pointer.out;
+ var outTarget = pointer.outTarget;
+ this.dispatcher.move(event, browserEvent);
+ if (outEvent && outTarget !== event.target) {
+ outEvent.relatedTarget = event.target;
+ event.relatedTarget = outTarget;
+ // recover from retargeting by shadow
+ outEvent.target = outTarget;
+ if (event.target) {
+ this.dispatcher.leaveOut(outEvent, browserEvent);
+ this.dispatcher.enterOver(event, browserEvent);
+ } else {
+ // clean up case when finger leaves the screen
+ event.target = outTarget;
+ event.relatedTarget = null;
+ this.cancelOut_(browserEvent, event);
+ }
+ }
+ pointer.out = event;
+ pointer.outTarget = event.target;
+};
+
+
+/**
+ * Handler for `touchend`, triggers `pointerup`,
+ * `pointerout` and `pointerleave` events.
+ *
+ * @param {Event} inEvent The event.
+ */
+ol.pointer.TouchSource.prototype.touchend = function(inEvent) {
+ this.dedupSynthMouse_(inEvent);
+ this.processTouches_(inEvent, this.upOut_);
+};
+
+
+/**
+ * @private
+ * @param {Event} browserEvent An event.
+ * @param {Object} inPointer The inPointer object.
+ */
+ol.pointer.TouchSource.prototype.upOut_ = function(browserEvent, inPointer) {
+ this.dispatcher.up(inPointer, browserEvent);
+ this.dispatcher.out(inPointer, browserEvent);
+ this.dispatcher.leave(inPointer, browserEvent);
+ this.cleanUpPointer_(inPointer);
+};
+
+
+/**
+ * Handler for `touchcancel`, triggers `pointercancel`,
+ * `pointerout` and `pointerleave` events.
+ *
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.TouchSource.prototype.touchcancel = function(inEvent) {
+ this.processTouches_(inEvent, this.cancelOut_);
+};
+
+
+/**
+ * @private
+ * @param {Event} browserEvent The event.
+ * @param {Object} inPointer The in pointer.
+ */
+ol.pointer.TouchSource.prototype.cancelOut_ = function(browserEvent, inPointer) {
+ this.dispatcher.cancel(inPointer, browserEvent);
+ this.dispatcher.out(inPointer, browserEvent);
+ this.dispatcher.leave(inPointer, browserEvent);
+ this.cleanUpPointer_(inPointer);
+};
+
+
+/**
+ * @private
+ * @param {Object} inPointer The inPointer object.
+ */
+ol.pointer.TouchSource.prototype.cleanUpPointer_ = function(inPointer) {
+ delete this.pointerMap[inPointer.pointerId];
+ this.removePrimaryPointer_(inPointer);
+};
+
+
+/**
+ * Prevent synth mouse events from creating pointer events.
+ *
+ * @private
+ * @param {Event} inEvent The in event.
+ */
+ol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) {
+ var lts = this.mouseSource.lastTouches;
+ var t = inEvent.changedTouches[0];
+ // only the primary finger will synth mouse events
+ if (this.isPrimaryTouch_(t)) {
+ // remember x/y of last touch
+ var lt = [t.clientX, t.clientY];
+ lts.push(lt);
+
+ ol.global.setTimeout(function() {
+ // remove touch after timeout
+ ol.array.remove(lts, lt);
+ }, ol.pointer.TouchSource.DEDUP_TIMEOUT);
+ }
+};
+
+// Based on https://github.com/Polymer/PointerEvents
+
+// Copyright (c) 2013 The Polymer Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+goog.provide('ol.pointer.PointerEventHandler');
+
+goog.require('ol.events');
+goog.require('ol.events.EventTarget');
+
+goog.require('ol.has');
+goog.require('ol.pointer.MouseSource');
+goog.require('ol.pointer.MsSource');
+goog.require('ol.pointer.NativeSource');
+goog.require('ol.pointer.PointerEvent');
+goog.require('ol.pointer.TouchSource');
+
+
+/**
+ * @constructor
+ * @extends {ol.events.EventTarget}
+ * @param {Element|HTMLDocument} element Viewport element.
+ */
+ol.pointer.PointerEventHandler = function(element) {
+ ol.events.EventTarget.call(this);
+
+ /**
+ * @const
+ * @private
+ * @type {Element|HTMLDocument}
+ */
+ this.element_ = element;
+
+ /**
+ * @const
+ * @type {!Object.<string, Event|Object>}
+ */
+ this.pointerMap = {};
+
+ /**
+ * @type {Object.<string, function(Event)>}
+ * @private
+ */
+ this.eventMap_ = {};
+
+ /**
+ * @type {Array.<ol.pointer.EventSource>}
+ * @private
+ */
+ this.eventSourceList_ = [];
+
+ this.registerSources();
+};
+ol.inherits(ol.pointer.PointerEventHandler, ol.events.EventTarget);
+
+
+/**
+ * Set up the event sources (mouse, touch and native pointers)
+ * that generate pointer events.
+ */
+ol.pointer.PointerEventHandler.prototype.registerSources = function() {
+ if (ol.has.POINTER) {
+ this.registerSource('native', new ol.pointer.NativeSource(this));
+ } else if (ol.has.MSPOINTER) {
+ this.registerSource('ms', new ol.pointer.MsSource(this));
+ } else {
+ var mouseSource = new ol.pointer.MouseSource(this);
+ this.registerSource('mouse', mouseSource);
+
+ if (ol.has.TOUCH) {
+ this.registerSource('touch',
+ new ol.pointer.TouchSource(this, mouseSource));
+ }
+ }
+
+ // register events on the viewport element
+ this.register_();
+};
+
+
+/**
+ * Add a new event source that will generate pointer events.
+ *
+ * @param {string} name A name for the event source
+ * @param {ol.pointer.EventSource} source The source event.
+ */
+ol.pointer.PointerEventHandler.prototype.registerSource = function(name, source) {
+ var s = source;
+ var newEvents = s.getEvents();
+
+ if (newEvents) {
+ newEvents.forEach(function(e) {
+ var handler = s.getHandlerForEvent(e);
+
+ if (handler) {
+ this.eventMap_[e] = handler.bind(s);
+ }
+ }, this);
+ this.eventSourceList_.push(s);
+ }
+};
+
+
+/**
+ * Set up the events for all registered event sources.
+ * @private
+ */
+ol.pointer.PointerEventHandler.prototype.register_ = function() {
+ var l = this.eventSourceList_.length;
+ var eventSource;
+ for (var i = 0; i < l; i++) {
+ eventSource = this.eventSourceList_[i];
+ this.addEvents_(eventSource.getEvents());
+ }
+};
+
+
+/**
+ * Remove all registered events.
+ * @private
+ */
+ol.pointer.PointerEventHandler.prototype.unregister_ = function() {
+ var l = this.eventSourceList_.length;
+ var eventSource;
+ for (var i = 0; i < l; i++) {
+ eventSource = this.eventSourceList_[i];
+ this.removeEvents_(eventSource.getEvents());
+ }
+};
+
+
+/**
+ * Calls the right handler for a new event.
+ * @private
+ * @param {Event} inEvent Browser event.
+ */
+ol.pointer.PointerEventHandler.prototype.eventHandler_ = function(inEvent) {
+ var type = inEvent.type;
+ var handler = this.eventMap_[type];
+ if (handler) {
+ handler(inEvent);
+ }
+};
+
+
+/**
+ * Setup listeners for the given events.
+ * @private
+ * @param {Array.<string>} events List of events.
+ */
+ol.pointer.PointerEventHandler.prototype.addEvents_ = function(events) {
+ events.forEach(function(eventName) {
+ ol.events.listen(this.element_, eventName, this.eventHandler_, this);
+ }, this);
+};
+
+
+/**
+ * Unregister listeners for the given events.
+ * @private
+ * @param {Array.<string>} events List of events.
+ */
+ol.pointer.PointerEventHandler.prototype.removeEvents_ = function(events) {
+ events.forEach(function(e) {
+ ol.events.unlisten(this.element_, e, this.eventHandler_, this);
+ }, this);
+};
+
+
+/**
+ * Returns a snapshot of inEvent, with writable properties.
+ *
+ * @param {Event} event Browser event.
+ * @param {Event|Touch} inEvent An event that contains
+ * properties to copy.
+ * @return {Object} An object containing shallow copies of
+ * `inEvent`'s properties.
+ */
+ol.pointer.PointerEventHandler.prototype.cloneEvent = function(event, inEvent) {
+ var eventCopy = {}, p;
+ for (var i = 0, ii = ol.pointer.CLONE_PROPS.length; i < ii; i++) {
+ p = ol.pointer.CLONE_PROPS[i][0];
+ eventCopy[p] = event[p] || inEvent[p] || ol.pointer.CLONE_PROPS[i][1];
+ }
+
+ return eventCopy;
+};
+
+
+// EVENTS
+
+
+/**
+ * Triggers a 'pointerdown' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.down = function(data, event) {
+ this.fireEvent(ol.pointer.EventType.POINTERDOWN, data, event);
+};
+
+
+/**
+ * Triggers a 'pointermove' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.move = function(data, event) {
+ this.fireEvent(ol.pointer.EventType.POINTERMOVE, data, event);
+};
+
+
+/**
+ * Triggers a 'pointerup' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.up = function(data, event) {
+ this.fireEvent(ol.pointer.EventType.POINTERUP, data, event);
+};
+
+
+/**
+ * Triggers a 'pointerenter' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.enter = function(data, event) {
+ data.bubbles = false;
+ this.fireEvent(ol.pointer.EventType.POINTERENTER, data, event);
+};
+
+
+/**
+ * Triggers a 'pointerleave' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.leave = function(data, event) {
+ data.bubbles = false;
+ this.fireEvent(ol.pointer.EventType.POINTERLEAVE, data, event);
+};
+
+
+/**
+ * Triggers a 'pointerover' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.over = function(data, event) {
+ data.bubbles = true;
+ this.fireEvent(ol.pointer.EventType.POINTEROVER, data, event);
+};
+
+
+/**
+ * Triggers a 'pointerout' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.out = function(data, event) {
+ data.bubbles = true;
+ this.fireEvent(ol.pointer.EventType.POINTEROUT, data, event);
+};
+
+
+/**
+ * Triggers a 'pointercancel' event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.cancel = function(data, event) {
+ this.fireEvent(ol.pointer.EventType.POINTERCANCEL, data, event);
+};
+
+
+/**
+ * Triggers a combination of 'pointerout' and 'pointerleave' events.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.leaveOut = function(data, event) {
+ this.out(data, event);
+ if (!this.contains_(data.target, data.relatedTarget)) {
+ this.leave(data, event);
+ }
+};
+
+
+/**
+ * Triggers a combination of 'pointerover' and 'pointerevents' events.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.enterOver = function(data, event) {
+ this.over(data, event);
+ if (!this.contains_(data.target, data.relatedTarget)) {
+ this.enter(data, event);
+ }
+};
+
+
+/**
+ * @private
+ * @param {Element} container The container element.
+ * @param {Element} contained The contained element.
+ * @return {boolean} Returns true if the container element
+ * contains the other element.
+ */
+ol.pointer.PointerEventHandler.prototype.contains_ = function(container, contained) {
+ if (!container || !contained) {
+ return false;
+ }
+ return container.contains(contained);
+};
+
+
+// EVENT CREATION AND TRACKING
+/**
+ * Creates a new Event of type `inType`, based on the information in
+ * `data`.
+ *
+ * @param {string} inType A string representing the type of event to create.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ * @return {ol.pointer.PointerEvent} A PointerEvent of type `inType`.
+ */
+ol.pointer.PointerEventHandler.prototype.makeEvent = function(inType, data, event) {
+ return new ol.pointer.PointerEvent(inType, event, data);
+};
+
+
+/**
+ * Make and dispatch an event in one call.
+ * @param {string} inType A string representing the type of event.
+ * @param {Object} data Pointer event data.
+ * @param {Event} event The event.
+ */
+ol.pointer.PointerEventHandler.prototype.fireEvent = function(inType, data, event) {
+ var e = this.makeEvent(inType, data, event);
+ this.dispatchEvent(e);
+};
+
+
+/**
+ * Creates a pointer event from a native pointer event
+ * and dispatches this event.
+ * @param {Event} event A platform event with a target.
+ */
+ol.pointer.PointerEventHandler.prototype.fireNativeEvent = function(event) {
+ var e = this.makeEvent(event.type, event, event);
+ this.dispatchEvent(e);
+};
+
+
+/**
+ * Wrap a native mouse event into a pointer event.
+ * This proxy method is required for the legacy IE support.
+ * @param {string} eventType The pointer event type.
+ * @param {Event} event The event.
+ * @return {ol.pointer.PointerEvent} The wrapped event.
+ */
+ol.pointer.PointerEventHandler.prototype.wrapMouseEvent = function(eventType, event) {
+ var pointerEvent = this.makeEvent(
+ eventType, ol.pointer.MouseSource.prepareEvent(event, this), event);
+ return pointerEvent;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.pointer.PointerEventHandler.prototype.disposeInternal = function() {
+ this.unregister_();
+ ol.events.EventTarget.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * Constants for event names.
+ * @enum {string}
+ */
+ol.pointer.EventType = {
+ POINTERMOVE: 'pointermove',
+ POINTERDOWN: 'pointerdown',
+ POINTERUP: 'pointerup',
+ POINTEROVER: 'pointerover',
+ POINTEROUT: 'pointerout',
+ POINTERENTER: 'pointerenter',
+ POINTERLEAVE: 'pointerleave',
+ POINTERCANCEL: 'pointercancel'
+};
+
+
+/**
+ * Properties to copy when cloning an event, with default values.
+ * @type {Array.<Array>}
+ */
+ol.pointer.CLONE_PROPS = [
+ // MouseEvent
+ ['bubbles', false],
+ ['cancelable', false],
+ ['view', null],
+ ['detail', null],
+ ['screenX', 0],
+ ['screenY', 0],
+ ['clientX', 0],
+ ['clientY', 0],
+ ['ctrlKey', false],
+ ['altKey', false],
+ ['shiftKey', false],
+ ['metaKey', false],
+ ['button', 0],
+ ['relatedTarget', null],
+ // DOM Level 3
+ ['buttons', 0],
+ // PointerEvent
+ ['pointerId', 0],
+ ['width', 0],
+ ['height', 0],
+ ['pressure', 0],
+ ['tiltX', 0],
+ ['tiltY', 0],
+ ['pointerType', ''],
+ ['hwTimestamp', 0],
+ ['isPrimary', false],
+ // event instance
+ ['type', ''],
+ ['target', null],
+ ['currentTarget', null],
+ ['which', 0]
+];
+
+goog.provide('ol.MapBrowserEvent');
+goog.provide('ol.MapBrowserEvent.EventType');
+goog.provide('ol.MapBrowserEventHandler');
+goog.provide('ol.MapBrowserPointerEvent');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.MapEvent');
+goog.require('ol.events');
+goog.require('ol.events.EventTarget');
+goog.require('ol.events.EventType');
+goog.require('ol.pointer.PointerEvent');
+goog.require('ol.pointer.PointerEventHandler');
+
+
+/**
+ * @classdesc
+ * Events emitted as map browser events are instances of this type.
+ * See {@link ol.Map} for which events trigger a map browser event.
+ *
+ * @constructor
+ * @extends {ol.MapEvent}
+ * @implements {oli.MapBrowserEvent}
+ * @param {string} type Event type.
+ * @param {ol.Map} map Map.
+ * @param {Event} browserEvent Browser event.
+ * @param {boolean=} opt_dragging Is the map currently being dragged?
+ * @param {?olx.FrameState=} opt_frameState Frame state.
+ */
+ol.MapBrowserEvent = function(type, map, browserEvent, opt_dragging,
+ opt_frameState) {
+
+ ol.MapEvent.call(this, type, map, opt_frameState);
+
+ /**
+ * The original browser event.
+ * @const
+ * @type {Event}
+ * @api stable
+ */
+ this.originalEvent = browserEvent;
+
+ /**
+ * The pixel of the original browser event.
+ * @type {ol.Pixel}
+ * @api stable
+ */
+ this.pixel = map.getEventPixel(browserEvent);
+
+ /**
+ * The coordinate of the original browser event.
+ * @type {ol.Coordinate}
+ * @api stable
+ */
+ this.coordinate = map.getCoordinateFromPixel(this.pixel);
+
+ /**
+ * Indicates if the map is currently being dragged. Only set for
+ * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`.
+ *
+ * @type {boolean}
+ * @api stable
+ */
+ this.dragging = opt_dragging !== undefined ? opt_dragging : false;
+
+};
+ol.inherits(ol.MapBrowserEvent, ol.MapEvent);
+
+
+/**
+ * Prevents the default browser action.
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
+ * @override
+ * @api stable
+ */
+ol.MapBrowserEvent.prototype.preventDefault = function() {
+ ol.MapEvent.prototype.preventDefault.call(this);
+ this.originalEvent.preventDefault();
+};
+
+
+/**
+ * Prevents further propagation of the current event.
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
+ * @override
+ * @api stable
+ */
+ol.MapBrowserEvent.prototype.stopPropagation = function() {
+ ol.MapEvent.prototype.stopPropagation.call(this);
+ this.originalEvent.stopPropagation();
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.MapBrowserEvent}
+ * @param {string} type Event type.
+ * @param {ol.Map} map Map.
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @param {boolean=} opt_dragging Is the map currently being dragged?
+ * @param {?olx.FrameState=} opt_frameState Frame state.
+ */
+ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging,
+ opt_frameState) {
+
+ ol.MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging,
+ opt_frameState);
+
+ /**
+ * @const
+ * @type {ol.pointer.PointerEvent}
+ */
+ this.pointerEvent = pointerEvent;
+
+};
+ol.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent);
+
+
+/**
+ * @param {ol.Map} map The map with the viewport to listen to events on.
+ * @constructor
+ * @extends {ol.events.EventTarget}
+ */
+ol.MapBrowserEventHandler = function(map) {
+
+ ol.events.EventTarget.call(this);
+
+ /**
+ * This is the element that we will listen to the real events on.
+ * @type {ol.Map}
+ * @private
+ */
+ this.map_ = map;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.clickTimeoutId_ = 0;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.dragging_ = false;
+
+ /**
+ * @type {!Array.<ol.EventsKey>}
+ * @private
+ */
+ this.dragListenerKeys_ = [];
+
+ /**
+ * The most recent "down" type event (or null if none have occurred).
+ * Set on pointerdown.
+ * @type {ol.pointer.PointerEvent}
+ * @private
+ */
+ this.down_ = null;
+
+ var element = this.map_.getViewport();
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.activePointers_ = 0;
+
+ /**
+ * @type {!Object.<number, boolean>}
+ * @private
+ */
+ this.trackedTouches_ = {};
+
+ /**
+ * Event handler which generates pointer events for
+ * the viewport element.
+ *
+ * @type {ol.pointer.PointerEventHandler}
+ * @private
+ */
+ this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element);
+
+ /**
+ * Event handler which generates pointer events for
+ * the document (used when dragging).
+ *
+ * @type {ol.pointer.PointerEventHandler}
+ * @private
+ */
+ this.documentPointerEventHandler_ = null;
+
+ /**
+ * @type {?ol.EventsKey}
+ * @private
+ */
+ this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_,
+ ol.pointer.EventType.POINTERDOWN,
+ this.handlePointerDown_, this);
+
+ /**
+ * @type {?ol.EventsKey}
+ * @private
+ */
+ this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_,
+ ol.pointer.EventType.POINTERMOVE,
+ this.relayEvent_, this);
+
+};
+ol.inherits(ol.MapBrowserEventHandler, ol.events.EventTarget);
+
+
+/**
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) {
+ var newEvent;
+ newEvent = new ol.MapBrowserPointerEvent(
+ ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent);
+ this.dispatchEvent(newEvent);
+ if (this.clickTimeoutId_ !== 0) {
+ // double-click
+ ol.global.clearTimeout(this.clickTimeoutId_);
+ this.clickTimeoutId_ = 0;
+ newEvent = new ol.MapBrowserPointerEvent(
+ ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent);
+ this.dispatchEvent(newEvent);
+ } else {
+ // click
+ this.clickTimeoutId_ = ol.global.setTimeout(function() {
+ this.clickTimeoutId_ = 0;
+ var newEvent = new ol.MapBrowserPointerEvent(
+ ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent);
+ this.dispatchEvent(newEvent);
+ }.bind(this), 250);
+ }
+};
+
+
+/**
+ * Keeps track on how many pointers are currently active.
+ *
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) {
+ var event = pointerEvent;
+
+ if (event.type == ol.MapBrowserEvent.EventType.POINTERUP ||
+ event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) {
+ delete this.trackedTouches_[event.pointerId];
+ } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) {
+ this.trackedTouches_[event.pointerId] = true;
+ }
+ this.activePointers_ = Object.keys(this.trackedTouches_).length;
+};
+
+
+/**
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) {
+ this.updateActivePointers_(pointerEvent);
+ var newEvent = new ol.MapBrowserPointerEvent(
+ ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent);
+ this.dispatchEvent(newEvent);
+
+ // We emulate click events on left mouse button click, touch contact, and pen
+ // contact. isMouseActionButton returns true in these cases (evt.button is set
+ // to 0).
+ // See http://www.w3.org/TR/pointerevents/#button-states
+ if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) {
+ goog.asserts.assert(this.down_, 'this.down_ must be truthy');
+ this.emulateClick_(this.down_);
+ }
+
+ goog.asserts.assert(this.activePointers_ >= 0,
+ 'this.activePointers_ should be equal to or larger than 0');
+ if (this.activePointers_ === 0) {
+ this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.dragListenerKeys_.length = 0;
+ this.dragging_ = false;
+ this.down_ = null;
+ this.documentPointerEventHandler_.dispose();
+ this.documentPointerEventHandler_ = null;
+ }
+};
+
+
+/**
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @return {boolean} If the left mouse button was pressed.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) {
+ return pointerEvent.button === 0;
+};
+
+
+/**
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) {
+ this.updateActivePointers_(pointerEvent);
+ var newEvent = new ol.MapBrowserPointerEvent(
+ ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent);
+ this.dispatchEvent(newEvent);
+
+ this.down_ = pointerEvent;
+
+ if (this.dragListenerKeys_.length === 0) {
+ /* Set up a pointer event handler on the `document`,
+ * which is required when the pointer is moved outside
+ * the viewport when dragging.
+ */
+ this.documentPointerEventHandler_ =
+ new ol.pointer.PointerEventHandler(document);
+
+ this.dragListenerKeys_.push(
+ ol.events.listen(this.documentPointerEventHandler_,
+ ol.MapBrowserEvent.EventType.POINTERMOVE,
+ this.handlePointerMove_, this),
+ ol.events.listen(this.documentPointerEventHandler_,
+ ol.MapBrowserEvent.EventType.POINTERUP,
+ this.handlePointerUp_, this),
+ /* Note that the listener for `pointercancel is set up on
+ * `pointerEventHandler_` and not `documentPointerEventHandler_` like
+ * the `pointerup` and `pointermove` listeners.
+ *
+ * The reason for this is the following: `TouchSource.vacuumTouches_()`
+ * issues `pointercancel` events, when there was no `touchend` for a
+ * `touchstart`. Now, let's say a first `touchstart` is registered on
+ * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.
+ * But `documentPointerEventHandler_` doesn't know about the first
+ * `touchstart`. If there is no `touchend` for the `touchstart`, we can
+ * only receive a `touchcancel` from `pointerEventHandler_`, because it is
+ * only registered there.
+ */
+ ol.events.listen(this.pointerEventHandler_,
+ ol.MapBrowserEvent.EventType.POINTERCANCEL,
+ this.handlePointerUp_, this)
+ );
+ }
+};
+
+
+/**
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) {
+ // Fix IE10 on windows Surface : When you tap the tablet, it triggers
+ // multiple pointermove events between pointerdown and pointerup with
+ // the exact same coordinates of the pointerdown event. To avoid a
+ // 'false' touchmove event to be dispatched , we test if the pointer
+ // effectively moved.
+ if (this.isMoving_(pointerEvent)) {
+ this.dragging_ = true;
+ var newEvent = new ol.MapBrowserPointerEvent(
+ ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent,
+ this.dragging_);
+ this.dispatchEvent(newEvent);
+ }
+
+ // Some native android browser triggers mousemove events during small period
+ // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or
+ // https://code.google.com/p/android/issues/detail?id=19827
+ // ex: Galaxy Tab P3110 + Android 4.1.1
+ pointerEvent.preventDefault();
+};
+
+
+/**
+ * Wrap and relay a pointer event. Note that this requires that the type
+ * string for the MapBrowserPointerEvent matches the PointerEvent type.
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) {
+ var dragging = !!(this.down_ && this.isMoving_(pointerEvent));
+ this.dispatchEvent(new ol.MapBrowserPointerEvent(
+ pointerEvent.type, this.map_, pointerEvent, dragging));
+};
+
+
+/**
+ * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
+ * @return {boolean} Is moving.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) {
+ return pointerEvent.clientX != this.down_.clientX ||
+ pointerEvent.clientY != this.down_.clientY;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
+ if (this.relayedListenerKey_) {
+ ol.events.unlistenByKey(this.relayedListenerKey_);
+ this.relayedListenerKey_ = null;
+ }
+ if (this.pointerdownListenerKey_) {
+ ol.events.unlistenByKey(this.pointerdownListenerKey_);
+ this.pointerdownListenerKey_ = null;
+ }
+
+ this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.dragListenerKeys_.length = 0;
+
+ if (this.documentPointerEventHandler_) {
+ this.documentPointerEventHandler_.dispose();
+ this.documentPointerEventHandler_ = null;
+ }
+ if (this.pointerEventHandler_) {
+ this.pointerEventHandler_.dispose();
+ this.pointerEventHandler_ = null;
+ }
+ ol.events.EventTarget.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * Constants for event names.
+ * @enum {string}
+ */
+ol.MapBrowserEvent.EventType = {
+
+ /**
+ * A true single click with no dragging and no double click. Note that this
+ * event is delayed by 250 ms to ensure that it is not a double click.
+ * @event ol.MapBrowserEvent#singleclick
+ * @api stable
+ */
+ SINGLECLICK: 'singleclick',
+
+ /**
+ * A click with no dragging. A double click will fire two of this.
+ * @event ol.MapBrowserEvent#click
+ * @api stable
+ */
+ CLICK: ol.events.EventType.CLICK,
+
+ /**
+ * A true double click, with no dragging.
+ * @event ol.MapBrowserEvent#dblclick
+ * @api stable
+ */
+ DBLCLICK: ol.events.EventType.DBLCLICK,
+
+ /**
+ * Triggered when a pointer is dragged.
+ * @event ol.MapBrowserEvent#pointerdrag
+ * @api
+ */
+ POINTERDRAG: 'pointerdrag',
+
+ /**
+ * Triggered when a pointer is moved. Note that on touch devices this is
+ * triggered when the map is panned, so is not the same as mousemove.
+ * @event ol.MapBrowserEvent#pointermove
+ * @api stable
+ */
+ POINTERMOVE: 'pointermove',
+
+ POINTERDOWN: 'pointerdown',
+ POINTERUP: 'pointerup',
+ POINTEROVER: 'pointerover',
+ POINTEROUT: 'pointerout',
+ POINTERENTER: 'pointerenter',
+ POINTERLEAVE: 'pointerleave',
+ POINTERCANCEL: 'pointercancel'
+};
+
+goog.provide('ol.layer.Base');
+goog.provide('ol.layer.LayerProperty');
+
+goog.require('ol');
+goog.require('ol.Object');
+goog.require('ol.math');
+goog.require('ol.object');
+goog.require('ol.source.State');
+
+
+/**
+ * @enum {string}
+ */
+ol.layer.LayerProperty = {
+ OPACITY: 'opacity',
+ VISIBLE: 'visible',
+ EXTENT: 'extent',
+ Z_INDEX: 'zIndex',
+ MAX_RESOLUTION: 'maxResolution',
+ MIN_RESOLUTION: 'minResolution',
+ SOURCE: 'source'
+};
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Note that with `ol.layer.Base` and all its subclasses, any property set in
+ * the options is set as a {@link ol.Object} property on the layer object, so
+ * is observable, and has get/set accessors.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {olx.layer.BaseOptions} options Layer options.
+ * @api stable
+ */
+ol.layer.Base = function(options) {
+
+ ol.Object.call(this);
+
+ /**
+ * @type {Object.<string, *>}
+ */
+ var properties = ol.object.assign({}, options);
+ properties[ol.layer.LayerProperty.OPACITY] =
+ options.opacity !== undefined ? options.opacity : 1;
+ properties[ol.layer.LayerProperty.VISIBLE] =
+ options.visible !== undefined ? options.visible : true;
+ properties[ol.layer.LayerProperty.Z_INDEX] =
+ options.zIndex !== undefined ? options.zIndex : 0;
+ properties[ol.layer.LayerProperty.MAX_RESOLUTION] =
+ options.maxResolution !== undefined ? options.maxResolution : Infinity;
+ properties[ol.layer.LayerProperty.MIN_RESOLUTION] =
+ options.minResolution !== undefined ? options.minResolution : 0;
+
+ this.setProperties(properties);
+};
+ol.inherits(ol.layer.Base, ol.Object);
+
+
+/**
+ * @return {ol.LayerState} Layer state.
+ */
+ol.layer.Base.prototype.getLayerState = function() {
+ var opacity = this.getOpacity();
+ var sourceState = this.getSourceState();
+ var visible = this.getVisible();
+ var extent = this.getExtent();
+ var zIndex = this.getZIndex();
+ var maxResolution = this.getMaxResolution();
+ var minResolution = this.getMinResolution();
+ return {
+ layer: /** @type {ol.layer.Layer} */ (this),
+ opacity: ol.math.clamp(opacity, 0, 1),
+ sourceState: sourceState,
+ visible: visible,
+ managed: true,
+ extent: extent,
+ zIndex: zIndex,
+ maxResolution: maxResolution,
+ minResolution: Math.max(minResolution, 0)
+ };
+};
+
+
+/**
+ * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be
+ * modified in place).
+ * @return {Array.<ol.layer.Layer>} Array of layers.
+ */
+ol.layer.Base.prototype.getLayersArray = goog.abstractMethod;
+
+
+/**
+ * @param {Array.<ol.LayerState>=} opt_states Optional list of layer
+ * states (to be modified in place).
+ * @return {Array.<ol.LayerState>} List of layer states.
+ */
+ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod;
+
+
+/**
+ * Return the {@link ol.Extent extent} of the layer or `undefined` if it
+ * will be visible regardless of extent.
+ * @return {ol.Extent|undefined} The layer extent.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.getExtent = function() {
+ return /** @type {ol.Extent|undefined} */ (
+ this.get(ol.layer.LayerProperty.EXTENT));
+};
+
+
+/**
+ * Return the maximum resolution of the layer.
+ * @return {number} The maximum resolution of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.getMaxResolution = function() {
+ return /** @type {number} */ (
+ this.get(ol.layer.LayerProperty.MAX_RESOLUTION));
+};
+
+
+/**
+ * Return the minimum resolution of the layer.
+ * @return {number} The minimum resolution of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.getMinResolution = function() {
+ return /** @type {number} */ (
+ this.get(ol.layer.LayerProperty.MIN_RESOLUTION));
+};
+
+
+/**
+ * Return the opacity of the layer (between 0 and 1).
+ * @return {number} The opacity of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.getOpacity = function() {
+ return /** @type {number} */ (this.get(ol.layer.LayerProperty.OPACITY));
+};
+
+
+/**
+ * @return {ol.source.State} Source state.
+ */
+ol.layer.Base.prototype.getSourceState = goog.abstractMethod;
+
+
+/**
+ * Return the visibility of the layer (`true` or `false`).
+ * @return {boolean} The visibility of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.getVisible = function() {
+ return /** @type {boolean} */ (this.get(ol.layer.LayerProperty.VISIBLE));
+};
+
+
+/**
+ * Return the Z-index of the layer, which is used to order layers before
+ * rendering. The default Z-index is 0.
+ * @return {number} The Z-index of the layer.
+ * @observable
+ * @api
+ */
+ol.layer.Base.prototype.getZIndex = function() {
+ return /** @type {number} */ (this.get(ol.layer.LayerProperty.Z_INDEX));
+};
+
+
+/**
+ * Set the extent at which the layer is visible. If `undefined`, the layer
+ * will be visible at all extents.
+ * @param {ol.Extent|undefined} extent The extent of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.setExtent = function(extent) {
+ this.set(ol.layer.LayerProperty.EXTENT, extent);
+};
+
+
+/**
+ * Set the maximum resolution at which the layer is visible.
+ * @param {number} maxResolution The maximum resolution of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.setMaxResolution = function(maxResolution) {
+ this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution);
+};
+
+
+/**
+ * Set the minimum resolution at which the layer is visible.
+ * @param {number} minResolution The minimum resolution of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.setMinResolution = function(minResolution) {
+ this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution);
+};
+
+
+/**
+ * Set the opacity of the layer, allowed values range from 0 to 1.
+ * @param {number} opacity The opacity of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.setOpacity = function(opacity) {
+ this.set(ol.layer.LayerProperty.OPACITY, opacity);
+};
+
+
+/**
+ * Set the visibility of the layer (`true` or `false`).
+ * @param {boolean} visible The visibility of the layer.
+ * @observable
+ * @api stable
+ */
+ol.layer.Base.prototype.setVisible = function(visible) {
+ this.set(ol.layer.LayerProperty.VISIBLE, visible);
+};
+
+
+/**
+ * Set Z-index of the layer, which is used to order layers before rendering.
+ * The default Z-index is 0.
+ * @param {number} zindex The z-index of the layer.
+ * @observable
+ * @api
+ */
+ol.layer.Base.prototype.setZIndex = function(zindex) {
+ this.set(ol.layer.LayerProperty.Z_INDEX, zindex);
+};
+
+goog.provide('ol.render.VectorContext');
+
+
+/**
+ * Context for drawing geometries. A vector context is available on render
+ * events and does not need to be constructed directly.
+ * @constructor
+ * @struct
+ * @api
+ */
+ol.render.VectorContext = function() {
+};
+
+
+/**
+ * Render a geometry.
+ *
+ * @param {ol.geom.Geometry} geometry The geometry to render.
+ */
+ol.render.VectorContext.prototype.drawGeometry = goog.abstractMethod;
+
+
+/**
+ * Set the rendering style.
+ *
+ * @param {ol.style.Style} style The rendering style.
+ */
+ol.render.VectorContext.prototype.setStyle = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.Circle} circleGeometry Circle geometry.
+ * @param {ol.Feature} feature Feature,
+ */
+ol.render.VectorContext.prototype.drawCircle = goog.abstractMethod;
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {ol.style.Style} style Style.
+ */
+ol.render.VectorContext.prototype.drawFeature = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry
+ * collection.
+ * @param {ol.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawGeometryCollection = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line
+ * string geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawLineString = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry
+ * MultiLineString geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawMultiLineString = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint
+ * geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawMultiPoint = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry.
+ * @param {ol.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawMultiPolygon = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawPoint = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon
+ * geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawPolygon = goog.abstractMethod;
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.VectorContext.prototype.drawText = goog.abstractMethod;
+
+
+/**
+ * @param {ol.style.Fill} fillStyle Fill style.
+ * @param {ol.style.Stroke} strokeStyle Stroke style.
+ */
+ol.render.VectorContext.prototype.setFillStrokeStyle = goog.abstractMethod;
+
+
+/**
+ * @param {ol.style.Image} imageStyle Image style.
+ */
+ol.render.VectorContext.prototype.setImageStyle = goog.abstractMethod;
+
+
+/**
+ * @param {ol.style.Text} textStyle Text style.
+ */
+ol.render.VectorContext.prototype.setTextStyle = goog.abstractMethod;
+
+goog.provide('ol.render.Event');
+goog.provide('ol.render.EventType');
+
+goog.require('ol.events.Event');
+goog.require('ol.render.VectorContext');
+
+
+/**
+ * @enum {string}
+ */
+ol.render.EventType = {
+ /**
+ * @event ol.render.Event#postcompose
+ * @api
+ */
+ POSTCOMPOSE: 'postcompose',
+ /**
+ * @event ol.render.Event#precompose
+ * @api
+ */
+ PRECOMPOSE: 'precompose',
+ /**
+ * @event ol.render.Event#render
+ * @api
+ */
+ RENDER: 'render'
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.render.Event}
+ * @param {ol.render.EventType} type Type.
+ * @param {Object=} opt_target Target.
+ * @param {ol.render.VectorContext=} opt_vectorContext Vector context.
+ * @param {olx.FrameState=} opt_frameState Frame state.
+ * @param {?CanvasRenderingContext2D=} opt_context Context.
+ * @param {?ol.webgl.Context=} opt_glContext WebGL Context.
+ */
+ol.render.Event = function(
+ type, opt_target, opt_vectorContext, opt_frameState, opt_context,
+ opt_glContext) {
+
+ ol.events.Event.call(this, type, opt_target);
+
+ /**
+ * For canvas, this is an instance of {@link ol.render.canvas.Immediate}.
+ * @type {ol.render.VectorContext|undefined}
+ * @api
+ */
+ this.vectorContext = opt_vectorContext;
+
+ /**
+ * An object representing the current render frame state.
+ * @type {olx.FrameState|undefined}
+ * @api
+ */
+ this.frameState = opt_frameState;
+
+ /**
+ * Canvas context. Only available when a Canvas renderer is used, null
+ * otherwise.
+ * @type {CanvasRenderingContext2D|null|undefined}
+ * @api
+ */
+ this.context = opt_context;
+
+ /**
+ * WebGL context. Only available when a WebGL renderer is used, null
+ * otherwise.
+ * @type {ol.webgl.Context|null|undefined}
+ * @api
+ */
+ this.glContext = opt_glContext;
+
+};
+ol.inherits(ol.render.Event, ol.events.Event);
+
+goog.provide('ol.layer.Layer');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.Object');
+goog.require('ol.layer.Base');
+goog.require('ol.layer.LayerProperty');
+goog.require('ol.object');
+goog.require('ol.render.EventType');
+goog.require('ol.source.State');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * A visual representation of raster or vector map data.
+ * Layers group together those properties that pertain to how the data is to be
+ * displayed, irrespective of the source of that data.
+ *
+ * Layers are usually added to a map with {@link ol.Map#addLayer}. Components
+ * like {@link ol.interaction.Select} use unmanaged layers internally. These
+ * unmanaged layers are associated with the map using
+ * {@link ol.layer.Layer#setMap} instead.
+ *
+ * A generic `change` event is fired when the state of the source changes.
+ *
+ * @constructor
+ * @extends {ol.layer.Base}
+ * @fires ol.render.Event
+ * @param {olx.layer.LayerOptions} options Layer options.
+ * @api stable
+ */
+ol.layer.Layer = function(options) {
+
+ var baseOptions = ol.object.assign({}, options);
+ delete baseOptions.source;
+
+ ol.layer.Base.call(this, /** @type {olx.layer.BaseOptions} */ (baseOptions));
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.mapPrecomposeKey_ = null;
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.mapRenderKey_ = null;
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.sourceChangeKey_ = null;
+
+ if (options.map) {
+ this.setMap(options.map);
+ }
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.layer.LayerProperty.SOURCE),
+ this.handleSourcePropertyChange_, this);
+
+ var source = options.source ? options.source : null;
+ this.setSource(source);
+};
+ol.inherits(ol.layer.Layer, ol.layer.Base);
+
+
+/**
+ * Return `true` if the layer is visible, and if the passed resolution is
+ * between the layer's minResolution and maxResolution. The comparison is
+ * inclusive for `minResolution` and exclusive for `maxResolution`.
+ * @param {ol.LayerState} layerState Layer state.
+ * @param {number} resolution Resolution.
+ * @return {boolean} The layer is visible at the given resolution.
+ */
+ol.layer.Layer.visibleAtResolution = function(layerState, resolution) {
+ return layerState.visible && resolution >= layerState.minResolution &&
+ resolution < layerState.maxResolution;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.layer.Layer.prototype.getLayersArray = function(opt_array) {
+ var array = opt_array ? opt_array : [];
+ array.push(this);
+ return array;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) {
+ var states = opt_states ? opt_states : [];
+ states.push(this.getLayerState());
+ return states;
+};
+
+
+/**
+ * Get the layer source.
+ * @return {ol.source.Source} The layer source (or `null` if not yet set).
+ * @observable
+ * @api stable
+ */
+ol.layer.Layer.prototype.getSource = function() {
+ var source = this.get(ol.layer.LayerProperty.SOURCE);
+ return /** @type {ol.source.Source} */ (source) || null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.layer.Layer.prototype.getSourceState = function() {
+ var source = this.getSource();
+ return !source ? ol.source.State.UNDEFINED : source.getState();
+};
+
+
+/**
+ * @private
+ */
+ol.layer.Layer.prototype.handleSourceChange_ = function() {
+ this.changed();
+};
+
+
+/**
+ * @private
+ */
+ol.layer.Layer.prototype.handleSourcePropertyChange_ = function() {
+ if (this.sourceChangeKey_) {
+ ol.events.unlistenByKey(this.sourceChangeKey_);
+ this.sourceChangeKey_ = null;
+ }
+ var source = this.getSource();
+ if (source) {
+ this.sourceChangeKey_ = ol.events.listen(source,
+ ol.events.EventType.CHANGE, this.handleSourceChange_, this);
+ }
+ this.changed();
+};
+
+
+/**
+ * Sets the layer to be rendered on top of other layers on a map. The map will
+ * not manage this layer in its layers collection, and the callback in
+ * {@link ol.Map#forEachLayerAtPixel} will receive `null` as layer. This
+ * is useful for temporary layers. To remove an unmanaged layer from the map,
+ * use `#setMap(null)`.
+ *
+ * To add the layer to a map and have it managed by the map, use
+ * {@link ol.Map#addLayer} instead.
+ * @param {ol.Map} map Map.
+ * @api
+ */
+ol.layer.Layer.prototype.setMap = function(map) {
+ if (this.mapPrecomposeKey_) {
+ ol.events.unlistenByKey(this.mapPrecomposeKey_);
+ this.mapPrecomposeKey_ = null;
+ }
+ if (!map) {
+ this.changed();
+ }
+ if (this.mapRenderKey_) {
+ ol.events.unlistenByKey(this.mapRenderKey_);
+ this.mapRenderKey_ = null;
+ }
+ if (map) {
+ this.mapPrecomposeKey_ = ol.events.listen(
+ map, ol.render.EventType.PRECOMPOSE, function(evt) {
+ var layerState = this.getLayerState();
+ layerState.managed = false;
+ layerState.zIndex = Infinity;
+ evt.frameState.layerStatesArray.push(layerState);
+ evt.frameState.layerStates[goog.getUid(this)] = layerState;
+ }, this);
+ this.mapRenderKey_ = ol.events.listen(
+ this, ol.events.EventType.CHANGE, map.render, map);
+ this.changed();
+ }
+};
+
+
+/**
+ * Set the layer source.
+ * @param {ol.source.Source} source The layer source.
+ * @observable
+ * @api stable
+ */
+ol.layer.Layer.prototype.setSource = function(source) {
+ this.set(ol.layer.LayerProperty.SOURCE, source);
+};
+
+goog.provide('ol.ImageBase');
+goog.provide('ol.ImageState');
+
+goog.require('goog.asserts');
+goog.require('ol.events.EventTarget');
+goog.require('ol.events.EventType');
+goog.require('ol.Attribution');
+
+
+/**
+ * @enum {number}
+ */
+ol.ImageState = {
+ IDLE: 0,
+ LOADING: 1,
+ LOADED: 2,
+ ERROR: 3
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.events.EventTarget}
+ * @param {ol.Extent} extent Extent.
+ * @param {number|undefined} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.ImageState} state State.
+ * @param {Array.<ol.Attribution>} attributions Attributions.
+ */
+ol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) {
+
+ ol.events.EventTarget.call(this);
+
+ /**
+ * @private
+ * @type {Array.<ol.Attribution>}
+ */
+ this.attributions_ = attributions;
+
+ /**
+ * @protected
+ * @type {ol.Extent}
+ */
+ this.extent = extent;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.pixelRatio_ = pixelRatio;
+
+ /**
+ * @protected
+ * @type {number|undefined}
+ */
+ this.resolution = resolution;
+
+ /**
+ * @protected
+ * @type {ol.ImageState}
+ */
+ this.state = state;
+
+};
+ol.inherits(ol.ImageBase, ol.events.EventTarget);
+
+
+/**
+ * @protected
+ */
+ol.ImageBase.prototype.changed = function() {
+ this.dispatchEvent(ol.events.EventType.CHANGE);
+};
+
+
+/**
+ * @return {Array.<ol.Attribution>} Attributions.
+ */
+ol.ImageBase.prototype.getAttributions = function() {
+ return this.attributions_;
+};
+
+
+/**
+ * @return {ol.Extent} Extent.
+ */
+ol.ImageBase.prototype.getExtent = function() {
+ return this.extent;
+};
+
+
+/**
+ * @param {Object=} opt_context Object.
+ * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.
+ */
+ol.ImageBase.prototype.getImage = goog.abstractMethod;
+
+
+/**
+ * @return {number} PixelRatio.
+ */
+ol.ImageBase.prototype.getPixelRatio = function() {
+ return this.pixelRatio_;
+};
+
+
+/**
+ * @return {number} Resolution.
+ */
+ol.ImageBase.prototype.getResolution = function() {
+ goog.asserts.assert(this.resolution !== undefined, 'resolution not yet set');
+ return this.resolution;
+};
+
+
+/**
+ * @return {ol.ImageState} State.
+ */
+ol.ImageBase.prototype.getState = function() {
+ return this.state;
+};
+
+
+/**
+ * Load not yet loaded URI.
+ */
+ol.ImageBase.prototype.load = goog.abstractMethod;
+
+goog.provide('ol.vec.Mat4');
+goog.provide('ol.vec.Mat4.Number');
+
+goog.require('goog.vec.Mat4');
+
+
+/**
+ * A alias for the goog.vec.Number type.
+ * @typedef {goog.vec.Number}
+ */
+ol.vec.Mat4.Number;
+
+
+/**
+ * @param {!goog.vec.Mat4.Number} mat Matrix.
+ * @param {number} translateX1 Translate X1.
+ * @param {number} translateY1 Translate Y1.
+ * @param {number} scaleX Scale X.
+ * @param {number} scaleY Scale Y.
+ * @param {number} rotation Rotation.
+ * @param {number} translateX2 Translate X2.
+ * @param {number} translateY2 Translate Y2.
+ * @return {!goog.vec.Mat4.Number} Matrix.
+ */
+ol.vec.Mat4.makeTransform2D = function(mat, translateX1, translateY1,
+ scaleX, scaleY, rotation, translateX2, translateY2) {
+ goog.vec.Mat4.makeIdentity(mat);
+ if (translateX1 !== 0 || translateY1 !== 0) {
+ goog.vec.Mat4.translate(mat, translateX1, translateY1, 0);
+ }
+ if (scaleX != 1 || scaleY != 1) {
+ goog.vec.Mat4.scale(mat, scaleX, scaleY, 1);
+ }
+ if (rotation !== 0) {
+ goog.vec.Mat4.rotateZ(mat, rotation);
+ }
+ if (translateX2 !== 0 || translateY2 !== 0) {
+ goog.vec.Mat4.translate(mat, translateX2, translateY2, 0);
+ }
+ return mat;
+};
+
+
+/**
+ * Returns true if mat1 and mat2 represent the same 2D transformation.
+ * @param {goog.vec.Mat4.Number} mat1 Matrix 1.
+ * @param {goog.vec.Mat4.Number} mat2 Matrix 2.
+ * @return {boolean} Equal 2D.
+ */
+ol.vec.Mat4.equals2D = function(mat1, mat2) {
+ return (
+ goog.vec.Mat4.getElement(mat1, 0, 0) ==
+ goog.vec.Mat4.getElement(mat2, 0, 0) &&
+ goog.vec.Mat4.getElement(mat1, 1, 0) ==
+ goog.vec.Mat4.getElement(mat2, 1, 0) &&
+ goog.vec.Mat4.getElement(mat1, 0, 1) ==
+ goog.vec.Mat4.getElement(mat2, 0, 1) &&
+ goog.vec.Mat4.getElement(mat1, 1, 1) ==
+ goog.vec.Mat4.getElement(mat2, 1, 1) &&
+ goog.vec.Mat4.getElement(mat1, 0, 3) ==
+ goog.vec.Mat4.getElement(mat2, 0, 3) &&
+ goog.vec.Mat4.getElement(mat1, 1, 3) ==
+ goog.vec.Mat4.getElement(mat2, 1, 3));
+};
+
+
+/**
+ * Transforms the given vector with the given matrix storing the resulting,
+ * transformed vector into resultVec. The input vector is multiplied against the
+ * upper 2x4 matrix omitting the projective component.
+ *
+ * @param {goog.vec.Mat4.Number} mat The matrix supplying the transformation.
+ * @param {Array.<number>} vec The 3 element vector to transform.
+ * @param {Array.<number>} resultVec The 3 element vector to receive the results
+ * (may be vec).
+ * @return {Array.<number>} return resultVec so that operations can be
+ * chained together.
+ */
+ol.vec.Mat4.multVec2 = function(mat, vec, resultVec) {
+ var m00 = goog.vec.Mat4.getElement(mat, 0, 0);
+ var m10 = goog.vec.Mat4.getElement(mat, 1, 0);
+ var m01 = goog.vec.Mat4.getElement(mat, 0, 1);
+ var m11 = goog.vec.Mat4.getElement(mat, 1, 1);
+ var m03 = goog.vec.Mat4.getElement(mat, 0, 3);
+ var m13 = goog.vec.Mat4.getElement(mat, 1, 3);
+ var x = vec[0], y = vec[1];
+ resultVec[0] = m00 * x + m01 * y + m03;
+ resultVec[1] = m10 * x + m11 * y + m13;
+ return resultVec;
+};
+
+goog.provide('ol.renderer.Layer');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.functions');
+goog.require('ol.ImageState');
+goog.require('ol.Observable');
+goog.require('ol.TileRange');
+goog.require('ol.TileState');
+goog.require('ol.layer.Layer');
+goog.require('ol.source.Source');
+goog.require('ol.source.State');
+goog.require('ol.source.Tile');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.Observable}
+ * @param {ol.layer.Layer} layer Layer.
+ * @struct
+ */
+ol.renderer.Layer = function(layer) {
+
+ ol.Observable.call(this);
+
+ /**
+ * @private
+ * @type {ol.layer.Layer}
+ */
+ this.layer_ = layer;
+
+
+};
+ol.inherits(ol.renderer.Layer, ol.Observable);
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T}
+ * callback Feature callback.
+ * @param {S} thisArg Value to use as `this` when executing `callback`.
+ * @return {T|undefined} Callback result.
+ * @template S,T
+ */
+ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction;
+
+
+/**
+ * @param {ol.Pixel} pixel Pixel.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {function(this: S, ol.layer.Layer): T} callback Layer callback.
+ * @param {S} thisArg Value to use as `this` when executing `callback`.
+ * @return {T|undefined} Callback result.
+ * @template S,T
+ */
+ol.renderer.Layer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
+ var coordinate = pixel.slice();
+ ol.vec.Mat4.multVec2(
+ frameState.pixelToCoordinateMatrix, coordinate, coordinate);
+
+ var hasFeature = this.forEachFeatureAtCoordinate(
+ coordinate, frameState, ol.functions.TRUE, this);
+
+ if (hasFeature) {
+ return callback.call(thisArg, this.layer_);
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {olx.FrameState} frameState Frame state.
+ * @return {boolean} Is there a feature at the given coordinate?
+ */
+ol.renderer.Layer.prototype.hasFeatureAtCoordinate = ol.functions.FALSE;
+
+
+/**
+ * Create a function that adds loaded tiles to the tile lookup.
+ * @param {ol.source.Tile} source Tile source.
+ * @param {ol.proj.Projection} projection Projection of the tiles.
+ * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded
+ * tiles by zoom level.
+ * @return {function(number, ol.TileRange):boolean} A function that can be
+ * called with a zoom level and a tile range to add loaded tiles to the
+ * lookup.
+ * @protected
+ */
+ol.renderer.Layer.prototype.createLoadedTileFinder = function(source, projection, tiles) {
+ return (
+ /**
+ * @param {number} zoom Zoom level.
+ * @param {ol.TileRange} tileRange Tile range.
+ * @return {boolean} The tile range is fully loaded.
+ */
+ function(zoom, tileRange) {
+ function callback(tile) {
+ if (!tiles[zoom]) {
+ tiles[zoom] = {};
+ }
+ tiles[zoom][tile.tileCoord.toString()] = tile;
+ }
+ return source.forEachLoadedTile(projection, zoom, tileRange, callback);
+ });
+};
+
+
+/**
+ * @return {ol.layer.Layer} Layer.
+ */
+ol.renderer.Layer.prototype.getLayer = function() {
+ return this.layer_;
+};
+
+
+/**
+ * Handle changes in image state.
+ * @param {ol.events.Event} event Image change event.
+ * @private
+ */
+ol.renderer.Layer.prototype.handleImageChange_ = function(event) {
+ var image = /** @type {ol.Image} */ (event.target);
+ if (image.getState() === ol.ImageState.LOADED) {
+ this.renderIfReadyAndVisible();
+ }
+};
+
+
+/**
+ * Load the image if not already loaded, and register the image change
+ * listener if needed.
+ * @param {ol.ImageBase} image Image.
+ * @return {boolean} `true` if the image is already loaded, `false`
+ * otherwise.
+ * @protected
+ */
+ol.renderer.Layer.prototype.loadImage = function(image) {
+ var imageState = image.getState();
+ if (imageState != ol.ImageState.LOADED &&
+ imageState != ol.ImageState.ERROR) {
+ // the image is either "idle" or "loading", register the change
+ // listener (a noop if the listener was already registered)
+ goog.asserts.assert(imageState == ol.ImageState.IDLE ||
+ imageState == ol.ImageState.LOADING,
+ 'imageState is "idle" or "loading"');
+ ol.events.listen(image, ol.events.EventType.CHANGE,
+ this.handleImageChange_, this);
+ }
+ if (imageState == ol.ImageState.IDLE) {
+ image.load();
+ imageState = image.getState();
+ goog.asserts.assert(imageState == ol.ImageState.LOADING ||
+ imageState == ol.ImageState.LOADED,
+ 'imageState is "loading" or "loaded"');
+ }
+ return imageState == ol.ImageState.LOADED;
+};
+
+
+/**
+ * @protected
+ */
+ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() {
+ var layer = this.getLayer();
+ if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) {
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.source.Tile} tileSource Tile source.
+ * @protected
+ */
+ol.renderer.Layer.prototype.scheduleExpireCache = function(frameState, tileSource) {
+ if (tileSource.canExpireCache()) {
+ /**
+ * @param {ol.source.Tile} tileSource Tile source.
+ * @param {ol.Map} map Map.
+ * @param {olx.FrameState} frameState Frame state.
+ */
+ var postRenderFunction = function(tileSource, map, frameState) {
+ var tileSourceKey = goog.getUid(tileSource).toString();
+ tileSource.expireCache(frameState.viewState.projection,
+ frameState.usedTiles[tileSourceKey]);
+ }.bind(null, tileSource);
+
+ frameState.postRenderFunctions.push(
+ /** @type {ol.PostRenderFunction} */ (postRenderFunction)
+ );
+ }
+};
+
+
+/**
+ * @param {Object.<string, ol.Attribution>} attributionsSet Attributions
+ * set (target).
+ * @param {Array.<ol.Attribution>} attributions Attributions (source).
+ * @protected
+ */
+ol.renderer.Layer.prototype.updateAttributions = function(attributionsSet, attributions) {
+ if (attributions) {
+ var attribution, i, ii;
+ for (i = 0, ii = attributions.length; i < ii; ++i) {
+ attribution = attributions[i];
+ attributionsSet[goog.getUid(attribution).toString()] = attribution;
+ }
+ }
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.source.Source} source Source.
+ * @protected
+ */
+ol.renderer.Layer.prototype.updateLogos = function(frameState, source) {
+ var logo = source.getLogo();
+ if (logo !== undefined) {
+ if (typeof logo === 'string') {
+ frameState.logos[logo] = '';
+ } else if (goog.isObject(logo)) {
+ goog.asserts.assertString(logo.href, 'logo.href is a string');
+ goog.asserts.assertString(logo.src, 'logo.src is a string');
+ frameState.logos[logo.src] = logo.href;
+ }
+ }
+};
+
+
+/**
+ * @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles.
+ * @param {ol.source.Tile} tileSource Tile source.
+ * @param {number} z Z.
+ * @param {ol.TileRange} tileRange Tile range.
+ * @protected
+ */
+ol.renderer.Layer.prototype.updateUsedTiles = function(usedTiles, tileSource, z, tileRange) {
+ // FIXME should we use tilesToDrawByZ instead?
+ var tileSourceKey = goog.getUid(tileSource).toString();
+ var zKey = z.toString();
+ if (tileSourceKey in usedTiles) {
+ if (zKey in usedTiles[tileSourceKey]) {
+ usedTiles[tileSourceKey][zKey].extend(tileRange);
+ } else {
+ usedTiles[tileSourceKey][zKey] = tileRange;
+ }
+ } else {
+ usedTiles[tileSourceKey] = {};
+ usedTiles[tileSourceKey][zKey] = tileRange;
+ }
+};
+
+
+/**
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {ol.Size} size Size.
+ * @protected
+ * @return {ol.Coordinate} Snapped center.
+ */
+ol.renderer.Layer.prototype.snapCenterToPixel = function(center, resolution, size) {
+ return [
+ resolution * (Math.round(center[0] / resolution) + (size[0] % 2) / 2),
+ resolution * (Math.round(center[1] / resolution) + (size[1] % 2) / 2)
+ ];
+};
+
+
+/**
+ * Manage tile pyramid.
+ * This function performs a number of functions related to the tiles at the
+ * current zoom and lower zoom levels:
+ * - registers idle tiles in frameState.wantedTiles so that they are not
+ * discarded by the tile queue
+ * - enqueues missing tiles
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.source.Tile} tileSource Tile source.
+ * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} currentZ Current Z.
+ * @param {number} preload Load low resolution tiles up to 'preload' levels.
+ * @param {function(this: T, ol.Tile)=} opt_tileCallback Tile callback.
+ * @param {T=} opt_this Object to use as `this` in `opt_tileCallback`.
+ * @protected
+ * @template T
+ */
+ol.renderer.Layer.prototype.manageTilePyramid = function(
+ frameState, tileSource, tileGrid, pixelRatio, projection, extent,
+ currentZ, preload, opt_tileCallback, opt_this) {
+ var tileSourceKey = goog.getUid(tileSource).toString();
+ if (!(tileSourceKey in frameState.wantedTiles)) {
+ frameState.wantedTiles[tileSourceKey] = {};
+ }
+ var wantedTiles = frameState.wantedTiles[tileSourceKey];
+ var tileQueue = frameState.tileQueue;
+ var minZoom = tileGrid.getMinZoom();
+ var tile, tileRange, tileResolution, x, y, z;
+ for (z = currentZ; z >= minZoom; --z) {
+ tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange);
+ tileResolution = tileGrid.getResolution(z);
+ for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
+ for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
+ if (currentZ - z <= preload) {
+ tile = tileSource.getTile(z, x, y, pixelRatio, projection);
+ if (tile.getState() == ol.TileState.IDLE) {
+ wantedTiles[tile.tileCoord.toString()] = true;
+ if (!tileQueue.isKeyQueued(tile.getKey())) {
+ tileQueue.enqueue([tile, tileSourceKey,
+ tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]);
+ }
+ }
+ if (opt_tileCallback !== undefined) {
+ opt_tileCallback.call(opt_this, tile);
+ }
+ } else {
+ tileSource.useTile(z, x, y, projection);
+ }
+ }
+ }
+ }
+};
+
+goog.provide('ol.style.Image');
+goog.provide('ol.style.ImageState');
+
+
+/**
+ * @enum {number}
+ */
+ol.style.ImageState = {
+ IDLE: 0,
+ LOADING: 1,
+ LOADED: 2,
+ ERROR: 3
+};
+
+
+/**
+ * @classdesc
+ * A base class used for creating subclasses and not instantiated in
+ * apps. Base class for {@link ol.style.Icon}, {@link ol.style.Circle} and
+ * {@link ol.style.RegularShape}.
+ *
+ * @constructor
+ * @param {ol.StyleImageOptions} options Options.
+ * @api
+ */
+ol.style.Image = function(options) {
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.opacity_ = options.opacity;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.rotateWithView_ = options.rotateWithView;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.rotation_ = options.rotation;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.scale_ = options.scale;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.snapToPixel_ = options.snapToPixel;
+
+};
+
+
+/**
+ * Get the symbolizer opacity.
+ * @return {number} Opacity.
+ * @api
+ */
+ol.style.Image.prototype.getOpacity = function() {
+ return this.opacity_;
+};
+
+
+/**
+ * Determine whether the symbolizer rotates with the map.
+ * @return {boolean} Rotate with map.
+ * @api
+ */
+ol.style.Image.prototype.getRotateWithView = function() {
+ return this.rotateWithView_;
+};
+
+
+/**
+ * Get the symoblizer rotation.
+ * @return {number} Rotation.
+ * @api
+ */
+ol.style.Image.prototype.getRotation = function() {
+ return this.rotation_;
+};
+
+
+/**
+ * Get the symbolizer scale.
+ * @return {number} Scale.
+ * @api
+ */
+ol.style.Image.prototype.getScale = function() {
+ return this.scale_;
+};
+
+
+/**
+ * Determine whether the symbolizer should be snapped to a pixel.
+ * @return {boolean} The symbolizer should snap to a pixel.
+ * @api
+ */
+ol.style.Image.prototype.getSnapToPixel = function() {
+ return this.snapToPixel_;
+};
+
+
+/**
+ * Get the anchor point. The anchor determines the center point for the
+ * symbolizer. Its units are determined by `anchorXUnits` and `anchorYUnits`.
+ * @function
+ * @return {Array.<number>} Anchor.
+ */
+ol.style.Image.prototype.getAnchor = goog.abstractMethod;
+
+
+/**
+ * Get the image element for the symbolizer.
+ * @function
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.
+ */
+ol.style.Image.prototype.getImage = goog.abstractMethod;
+
+
+/**
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.
+ */
+ol.style.Image.prototype.getHitDetectionImage = goog.abstractMethod;
+
+
+/**
+ * @return {ol.style.ImageState} Image state.
+ */
+ol.style.Image.prototype.getImageState = goog.abstractMethod;
+
+
+/**
+ * @return {ol.Size} Image size.
+ */
+ol.style.Image.prototype.getImageSize = goog.abstractMethod;
+
+
+/**
+ * @return {ol.Size} Size of the hit-detection image.
+ */
+ol.style.Image.prototype.getHitDetectionImageSize = goog.abstractMethod;
+
+
+/**
+ * Get the origin of the symbolizer.
+ * @function
+ * @return {Array.<number>} Origin.
+ */
+ol.style.Image.prototype.getOrigin = goog.abstractMethod;
+
+
+/**
+ * Get the size of the symbolizer (in pixels).
+ * @function
+ * @return {ol.Size} Size.
+ */
+ol.style.Image.prototype.getSize = goog.abstractMethod;
+
+
+/**
+ * Set the opacity.
+ *
+ * @param {number} opacity Opacity.
+ * @api
+ */
+ol.style.Image.prototype.setOpacity = function(opacity) {
+ this.opacity_ = opacity;
+};
+
+
+/**
+ * Set whether to rotate the style with the view.
+ *
+ * @param {boolean} rotateWithView Rotate with map.
+ */
+ol.style.Image.prototype.setRotateWithView = function(rotateWithView) {
+ this.rotateWithView_ = rotateWithView;
+};
+
+
+/**
+ * Set the rotation.
+ *
+ * @param {number} rotation Rotation.
+ * @api
+ */
+ol.style.Image.prototype.setRotation = function(rotation) {
+ this.rotation_ = rotation;
+};
+
+
+/**
+ * Set the scale.
+ *
+ * @param {number} scale Scale.
+ * @api
+ */
+ol.style.Image.prototype.setScale = function(scale) {
+ this.scale_ = scale;
+};
+
+
+/**
+ * Set whether to snap the image to the closest pixel.
+ *
+ * @param {boolean} snapToPixel Snap to pixel?
+ */
+ol.style.Image.prototype.setSnapToPixel = function(snapToPixel) {
+ this.snapToPixel_ = snapToPixel;
+};
+
+
+/**
+ * @param {function(this: T, ol.events.Event)} listener Listener function.
+ * @param {T} thisArg Value to use as `this` when executing `listener`.
+ * @return {ol.EventsKey|undefined} Listener key.
+ * @template T
+ */
+ol.style.Image.prototype.listenImageChange = goog.abstractMethod;
+
+
+/**
+ * Load not yet loaded URI.
+ */
+ol.style.Image.prototype.load = goog.abstractMethod;
+
+
+/**
+ * @param {function(this: T, ol.events.Event)} listener Listener function.
+ * @param {T} thisArg Value to use as `this` when executing `listener`.
+ * @template T
+ */
+ol.style.Image.prototype.unlistenImageChange = goog.abstractMethod;
+
+goog.provide('ol.style.Icon');
+goog.provide('ol.style.IconAnchorUnits');
+goog.provide('ol.style.IconImageCache');
+goog.provide('ol.style.IconOrigin');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventTarget');
+goog.require('ol.events.EventType');
+goog.require('ol.color');
+goog.require('ol.dom');
+goog.require('ol.style.Image');
+goog.require('ol.style.ImageState');
+
+
+/**
+ * Icon anchor units. One of 'fraction', 'pixels'.
+ * @enum {string}
+ */
+ol.style.IconAnchorUnits = {
+ FRACTION: 'fraction',
+ PIXELS: 'pixels'
+};
+
+
+/**
+ * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'.
+ * @enum {string}
+ */
+ol.style.IconOrigin = {
+ BOTTOM_LEFT: 'bottom-left',
+ BOTTOM_RIGHT: 'bottom-right',
+ TOP_LEFT: 'top-left',
+ TOP_RIGHT: 'top-right'
+};
+
+
+/**
+ * @classdesc
+ * Set icon style for vector features.
+ *
+ * @constructor
+ * @param {olx.style.IconOptions=} opt_options Options.
+ * @extends {ol.style.Image}
+ * @api
+ */
+ol.style.Icon = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5];
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.normalizedAnchor_ = null;
+
+ /**
+ * @private
+ * @type {ol.style.IconOrigin}
+ */
+ this.anchorOrigin_ = options.anchorOrigin !== undefined ?
+ options.anchorOrigin : ol.style.IconOrigin.TOP_LEFT;
+
+ /**
+ * @private
+ * @type {ol.style.IconAnchorUnits}
+ */
+ this.anchorXUnits_ = options.anchorXUnits !== undefined ?
+ options.anchorXUnits : ol.style.IconAnchorUnits.FRACTION;
+
+ /**
+ * @private
+ * @type {ol.style.IconAnchorUnits}
+ */
+ this.anchorYUnits_ = options.anchorYUnits !== undefined ?
+ options.anchorYUnits : ol.style.IconAnchorUnits.FRACTION;
+
+ /**
+ * @type {?string}
+ */
+ var crossOrigin =
+ options.crossOrigin !== undefined ? options.crossOrigin : null;
+
+ /**
+ * @type {Image|HTMLCanvasElement}
+ */
+ var image = options.img !== undefined ? options.img : null;
+
+ /**
+ * @type {ol.Size}
+ */
+ var imgSize = options.imgSize !== undefined ? options.imgSize : null;
+
+ /**
+ * @type {string|undefined}
+ */
+ var src = options.src;
+
+ goog.asserts.assert(!(src !== undefined && image),
+ 'image and src can not provided at the same time');
+ goog.asserts.assert(
+ !image || (image && imgSize),
+ 'imgSize must be set when image is provided');
+
+ if ((src === undefined || src.length === 0) && image) {
+ src = image.src || goog.getUid(image).toString();
+ }
+ goog.asserts.assert(src !== undefined && src.length > 0,
+ 'must provide a defined and non-empty src or image');
+
+ /**
+ * @type {ol.style.ImageState}
+ */
+ var imageState = options.src !== undefined ?
+ ol.style.ImageState.IDLE : ol.style.ImageState.LOADED;
+
+ /**
+ * @type {ol.Color}
+ */
+ var color = options.color !== undefined ? ol.color.asArray(options.color) :
+ null;
+
+ /**
+ * @private
+ * @type {ol.style.IconImage_}
+ */
+ this.iconImage_ = ol.style.IconImage_.get(
+ image, src, imgSize, crossOrigin, imageState, color);
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
+
+ /**
+ * @private
+ * @type {ol.style.IconOrigin}
+ */
+ this.offsetOrigin_ = options.offsetOrigin !== undefined ?
+ options.offsetOrigin : ol.style.IconOrigin.TOP_LEFT;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.origin_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.size_ = options.size !== undefined ? options.size : null;
+
+ /**
+ * @type {number}
+ */
+ var opacity = options.opacity !== undefined ? options.opacity : 1;
+
+ /**
+ * @type {boolean}
+ */
+ var rotateWithView = options.rotateWithView !== undefined ?
+ options.rotateWithView : false;
+
+ /**
+ * @type {number}
+ */
+ var rotation = options.rotation !== undefined ? options.rotation : 0;
+
+ /**
+ * @type {number}
+ */
+ var scale = options.scale !== undefined ? options.scale : 1;
+
+ /**
+ * @type {boolean}
+ */
+ var snapToPixel = options.snapToPixel !== undefined ?
+ options.snapToPixel : true;
+
+ ol.style.Image.call(this, {
+ opacity: opacity,
+ rotation: rotation,
+ scale: scale,
+ snapToPixel: snapToPixel,
+ rotateWithView: rotateWithView
+ });
+
+};
+ol.inherits(ol.style.Icon, ol.style.Image);
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.Icon.prototype.getAnchor = function() {
+ if (this.normalizedAnchor_) {
+ return this.normalizedAnchor_;
+ }
+ var anchor = this.anchor_;
+ var size = this.getSize();
+ if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION ||
+ this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) {
+ if (!size) {
+ return null;
+ }
+ anchor = this.anchor_.slice();
+ if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION) {
+ anchor[0] *= size[0];
+ }
+ if (this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) {
+ anchor[1] *= size[1];
+ }
+ }
+
+ if (this.anchorOrigin_ != ol.style.IconOrigin.TOP_LEFT) {
+ if (!size) {
+ return null;
+ }
+ if (anchor === this.anchor_) {
+ anchor = this.anchor_.slice();
+ }
+ if (this.anchorOrigin_ == ol.style.IconOrigin.TOP_RIGHT ||
+ this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
+ anchor[0] = -anchor[0] + size[0];
+ }
+ if (this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT ||
+ this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
+ anchor[1] = -anchor[1] + size[1];
+ }
+ }
+ this.normalizedAnchor_ = anchor;
+ return this.normalizedAnchor_;
+};
+
+
+/**
+ * Get the image icon.
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {Image|HTMLCanvasElement} Image or Canvas element.
+ * @api
+ */
+ol.style.Icon.prototype.getImage = function(pixelRatio) {
+ return this.iconImage_.getImage(pixelRatio);
+};
+
+
+/**
+ * Real Image size used.
+ * @return {ol.Size} Size.
+ */
+ol.style.Icon.prototype.getImageSize = function() {
+ return this.iconImage_.getSize();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Icon.prototype.getHitDetectionImageSize = function() {
+ return this.getImageSize();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Icon.prototype.getImageState = function() {
+ return this.iconImage_.getImageState();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) {
+ return this.iconImage_.getHitDetectionImage(pixelRatio);
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.Icon.prototype.getOrigin = function() {
+ if (this.origin_) {
+ return this.origin_;
+ }
+ var offset = this.offset_;
+
+ if (this.offsetOrigin_ != ol.style.IconOrigin.TOP_LEFT) {
+ var size = this.getSize();
+ var iconImageSize = this.iconImage_.getSize();
+ if (!size || !iconImageSize) {
+ return null;
+ }
+ offset = offset.slice();
+ if (this.offsetOrigin_ == ol.style.IconOrigin.TOP_RIGHT ||
+ this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
+ offset[0] = iconImageSize[0] - size[0] - offset[0];
+ }
+ if (this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT ||
+ this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
+ offset[1] = iconImageSize[1] - size[1] - offset[1];
+ }
+ }
+ this.origin_ = offset;
+ return this.origin_;
+};
+
+
+/**
+ * Get the image URL.
+ * @return {string|undefined} Image src.
+ * @api
+ */
+ol.style.Icon.prototype.getSrc = function() {
+ return this.iconImage_.getSrc();
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.Icon.prototype.getSize = function() {
+ return !this.size_ ? this.iconImage_.getSize() : this.size_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Icon.prototype.listenImageChange = function(listener, thisArg) {
+ return ol.events.listen(this.iconImage_, ol.events.EventType.CHANGE,
+ listener, thisArg);
+};
+
+
+/**
+ * Load not yet loaded URI.
+ * When rendering a feature with an icon style, the vector renderer will
+ * automatically call this method. However, you might want to call this
+ * method yourself for preloading or other purposes.
+ * @api
+ */
+ol.style.Icon.prototype.load = function() {
+ this.iconImage_.load();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) {
+ ol.events.unlisten(this.iconImage_, ol.events.EventType.CHANGE,
+ listener, thisArg);
+};
+
+
+/**
+ * @constructor
+ * @param {Image|HTMLCanvasElement} image Image.
+ * @param {string|undefined} src Src.
+ * @param {ol.Size} size Size.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.style.ImageState} imageState Image state.
+ * @param {ol.Color} color Color.
+ * @extends {ol.events.EventTarget}
+ * @private
+ */
+ol.style.IconImage_ = function(image, src, size, crossOrigin, imageState,
+ color) {
+
+ ol.events.EventTarget.call(this);
+
+ /**
+ * @private
+ * @type {Image|HTMLCanvasElement}
+ */
+ this.hitDetectionImage_ = null;
+
+ /**
+ * @private
+ * @type {Image|HTMLCanvasElement}
+ */
+ this.image_ = !image ? new Image() : image;
+
+ if (crossOrigin !== null) {
+ this.image_.crossOrigin = crossOrigin;
+ }
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = color ?
+ /** @type {HTMLCanvasElement} */ (document.createElement('CANVAS')) :
+ null;
+
+ /**
+ * @private
+ * @type {ol.Color}
+ */
+ this.color_ = color;
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.imageListenerKeys_ = null;
+
+ /**
+ * @private
+ * @type {ol.style.ImageState}
+ */
+ this.imageState_ = imageState;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.size_ = size;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.src_ = src;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.tainting_ = false;
+ if (this.imageState_ == ol.style.ImageState.LOADED) {
+ this.determineTainting_();
+ }
+
+};
+ol.inherits(ol.style.IconImage_, ol.events.EventTarget);
+
+
+/**
+ * @param {Image|HTMLCanvasElement} image Image.
+ * @param {string} src Src.
+ * @param {ol.Size} size Size.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.style.ImageState} imageState Image state.
+ * @param {ol.Color} color Color.
+ * @return {ol.style.IconImage_} Icon image.
+ */
+ol.style.IconImage_.get = function(image, src, size, crossOrigin, imageState,
+ color) {
+ var iconImageCache = ol.style.IconImageCache.getInstance();
+ var iconImage = iconImageCache.get(src, crossOrigin, color);
+ if (!iconImage) {
+ iconImage = new ol.style.IconImage_(
+ image, src, size, crossOrigin, imageState, color);
+ iconImageCache.set(src, crossOrigin, color, iconImage);
+ }
+ return iconImage;
+};
+
+
+/**
+ * @private
+ */
+ol.style.IconImage_.prototype.determineTainting_ = function() {
+ var context = ol.dom.createCanvasContext2D(1, 1);
+ try {
+ context.drawImage(this.image_, 0, 0);
+ context.getImageData(0, 0, 1, 1);
+ } catch (e) {
+ this.tainting_ = true;
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.style.IconImage_.prototype.dispatchChangeEvent_ = function() {
+ this.dispatchEvent(ol.events.EventType.CHANGE);
+};
+
+
+/**
+ * @private
+ */
+ol.style.IconImage_.prototype.handleImageError_ = function() {
+ this.imageState_ = ol.style.ImageState.ERROR;
+ this.unlistenImage_();
+ this.dispatchChangeEvent_();
+};
+
+
+/**
+ * @private
+ */
+ol.style.IconImage_.prototype.handleImageLoad_ = function() {
+ this.imageState_ = ol.style.ImageState.LOADED;
+ if (this.size_) {
+ this.image_.width = this.size_[0];
+ this.image_.height = this.size_[1];
+ }
+ this.size_ = [this.image_.width, this.image_.height];
+ this.unlistenImage_();
+ this.determineTainting_();
+ this.replaceColor_();
+ this.dispatchChangeEvent_();
+};
+
+
+/**
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {Image|HTMLCanvasElement} Image or Canvas element.
+ */
+ol.style.IconImage_.prototype.getImage = function(pixelRatio) {
+ return this.canvas_ ? this.canvas_ : this.image_;
+};
+
+
+/**
+ * @return {ol.style.ImageState} Image state.
+ */
+ol.style.IconImage_.prototype.getImageState = function() {
+ return this.imageState_;
+};
+
+
+/**
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {Image|HTMLCanvasElement} Image element.
+ */
+ol.style.IconImage_.prototype.getHitDetectionImage = function(pixelRatio) {
+ if (!this.hitDetectionImage_) {
+ if (this.tainting_) {
+ var width = this.size_[0];
+ var height = this.size_[1];
+ var context = ol.dom.createCanvasContext2D(width, height);
+ context.fillRect(0, 0, width, height);
+ this.hitDetectionImage_ = context.canvas;
+ } else {
+ this.hitDetectionImage_ = this.image_;
+ }
+ }
+ return this.hitDetectionImage_;
+};
+
+
+/**
+ * @return {ol.Size} Image size.
+ */
+ol.style.IconImage_.prototype.getSize = function() {
+ return this.size_;
+};
+
+
+/**
+ * @return {string|undefined} Image src.
+ */
+ol.style.IconImage_.prototype.getSrc = function() {
+ return this.src_;
+};
+
+
+/**
+ * Load not yet loaded URI.
+ */
+ol.style.IconImage_.prototype.load = function() {
+ if (this.imageState_ == ol.style.ImageState.IDLE) {
+ goog.asserts.assert(this.src_ !== undefined,
+ 'this.src_ must not be undefined');
+ goog.asserts.assert(!this.imageListenerKeys_,
+ 'no listener keys existing');
+ this.imageState_ = ol.style.ImageState.LOADING;
+ this.imageListenerKeys_ = [
+ ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,
+ this.handleImageError_, this),
+ ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,
+ this.handleImageLoad_, this)
+ ];
+ try {
+ this.image_.src = this.src_;
+ } catch (e) {
+ this.handleImageError_();
+ }
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.style.IconImage_.prototype.replaceColor_ = function() {
+ if (this.tainting_ || this.color_ === null) {
+ return;
+ }
+
+ goog.asserts.assert(this.canvas_ !== null,
+ 'this.canvas_ must not be null');
+
+ this.canvas_.width = this.image_.width;
+ this.canvas_.height = this.image_.height;
+
+ var ctx = this.canvas_.getContext('2d');
+ ctx.drawImage(this.image_, 0, 0);
+
+ var imgData = ctx.getImageData(0, 0, this.image_.width, this.image_.height);
+ var data = imgData.data;
+ var r = this.color_[0] / 255.0;
+ var g = this.color_[1] / 255.0;
+ var b = this.color_[2] / 255.0;
+
+ for (var i = 0, ii = data.length; i < ii; i += 4) {
+ data[i] *= r;
+ data[i + 1] *= g;
+ data[i + 2] *= b;
+ }
+ ctx.putImageData(imgData, 0, 0);
+};
+
+
+/**
+ * Discards event handlers which listen for load completion or errors.
+ *
+ * @private
+ */
+ol.style.IconImage_.prototype.unlistenImage_ = function() {
+ goog.asserts.assert(this.imageListenerKeys_,
+ 'we must have listeners registered');
+ this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.imageListenerKeys_ = null;
+};
+
+
+/**
+ * @constructor
+ */
+ol.style.IconImageCache = function() {
+
+ /**
+ * @type {Object.<string, ol.style.IconImage_>}
+ * @private
+ */
+ this.cache_ = {};
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.cacheSize_ = 0;
+
+ /**
+ * @const
+ * @type {number}
+ * @private
+ */
+ this.maxCacheSize_ = 32;
+};
+goog.addSingletonGetter(ol.style.IconImageCache);
+
+
+/**
+ * @param {string} src Src.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.Color} color Color.
+ * @return {string} Cache key.
+ */
+ol.style.IconImageCache.getKey = function(src, crossOrigin, color) {
+ goog.asserts.assert(crossOrigin !== undefined,
+ 'argument crossOrigin must be defined');
+ var colorString = color ? ol.color.asString(color) : 'null';
+ return crossOrigin + ':' + src + ':' + colorString;
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.style.IconImageCache.prototype.clear = function() {
+ this.cache_ = {};
+ this.cacheSize_ = 0;
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.style.IconImageCache.prototype.expire = function() {
+ if (this.cacheSize_ > this.maxCacheSize_) {
+ var i = 0;
+ var key, iconImage;
+ for (key in this.cache_) {
+ iconImage = this.cache_[key];
+ if ((i++ & 3) === 0 && !iconImage.hasListener()) {
+ delete this.cache_[key];
+ --this.cacheSize_;
+ }
+ }
+ }
+};
+
+
+/**
+ * @param {string} src Src.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.Color} color Color.
+ * @return {ol.style.IconImage_} Icon image.
+ */
+ol.style.IconImageCache.prototype.get = function(src, crossOrigin, color) {
+ var key = ol.style.IconImageCache.getKey(src, crossOrigin, color);
+ return key in this.cache_ ? this.cache_[key] : null;
+};
+
+
+/**
+ * @param {string} src Src.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.Color} color Color.
+ * @param {ol.style.IconImage_} iconImage Icon image.
+ */
+ol.style.IconImageCache.prototype.set = function(src, crossOrigin, color,
+ iconImage) {
+ var key = ol.style.IconImageCache.getKey(src, crossOrigin, color);
+ this.cache_[key] = iconImage;
+ ++this.cacheSize_;
+};
+
+goog.provide('ol.RendererType');
+goog.provide('ol.renderer.Map');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol');
+goog.require('ol.Disposable');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.functions');
+goog.require('ol.layer.Layer');
+goog.require('ol.renderer.Layer');
+goog.require('ol.style.IconImageCache');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * Available renderers: `'canvas'`, `'dom'` or `'webgl'`.
+ * @enum {string}
+ */
+ol.RendererType = {
+ CANVAS: 'canvas',
+ DOM: 'dom',
+ WEBGL: 'webgl'
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.Disposable}
+ * @param {Element} container Container.
+ * @param {ol.Map} map Map.
+ * @struct
+ */
+ol.renderer.Map = function(container, map) {
+
+ ol.Disposable.call(this);
+
+
+ /**
+ * @private
+ * @type {ol.Map}
+ */
+ this.map_ = map;
+
+ /**
+ * @private
+ * @type {Object.<string, ol.renderer.Layer>}
+ */
+ this.layerRenderers_ = {};
+
+ /**
+ * @private
+ * @type {Object.<string, ol.EventsKey>}
+ */
+ this.layerRendererListeners_ = {};
+
+};
+ol.inherits(ol.renderer.Map, ol.Disposable);
+
+
+/**
+ * @param {olx.FrameState} frameState FrameState.
+ * @protected
+ */
+ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) {
+ var viewState = frameState.viewState;
+ var coordinateToPixelMatrix = frameState.coordinateToPixelMatrix;
+ goog.asserts.assert(coordinateToPixelMatrix,
+ 'frameState has a coordinateToPixelMatrix');
+ ol.vec.Mat4.makeTransform2D(coordinateToPixelMatrix,
+ frameState.size[0] / 2, frameState.size[1] / 2,
+ 1 / viewState.resolution, -1 / viewState.resolution,
+ -viewState.rotation,
+ -viewState.center[0], -viewState.center[1]);
+ var inverted = goog.vec.Mat4.invert(
+ coordinateToPixelMatrix, frameState.pixelToCoordinateMatrix);
+ goog.asserts.assert(inverted, 'matrix could be inverted');
+};
+
+
+/**
+ * @param {ol.layer.Layer} layer Layer.
+ * @protected
+ * @return {ol.renderer.Layer} layerRenderer Layer renderer.
+ */
+ol.renderer.Map.prototype.createLayerRenderer = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.Map.prototype.disposeInternal = function() {
+ for (var id in this.layerRenderers_) {
+ this.layerRenderers_[id].dispose();
+ }
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.Map.expireIconCache_ = function(map, frameState) {
+ ol.style.IconImageCache.getInstance().expire();
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {olx.FrameState} frameState FrameState.
+ * @param {function(this: S, (ol.Feature|ol.render.Feature),
+ * ol.layer.Layer): T} callback Feature callback.
+ * @param {S} thisArg Value to use as `this` when executing `callback`.
+ * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter
+ * function, only layers which are visible and for which this function
+ * returns `true` will be tested for features. By default, all visible
+ * layers will be tested.
+ * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.
+ * @return {T|undefined} Callback result.
+ * @template S,T,U
+ */
+ol.renderer.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg,
+ layerFilter, thisArg2) {
+ var result;
+ var viewState = frameState.viewState;
+ var viewResolution = viewState.resolution;
+
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {?} Callback result.
+ */
+ function forEachFeatureAtCoordinate(feature, layer) {
+ goog.asserts.assert(feature !== undefined, 'received a feature');
+ var key = goog.getUid(feature).toString();
+ var managed = frameState.layerStates[goog.getUid(layer)].managed;
+ if (!(key in frameState.skippedFeatureUids && !managed)) {
+ return callback.call(thisArg, feature, managed ? layer : null);
+ }
+ }
+
+ var projection = viewState.projection;
+
+ var translatedCoordinate = coordinate;
+ if (projection.canWrapX()) {
+ var projectionExtent = projection.getExtent();
+ var worldWidth = ol.extent.getWidth(projectionExtent);
+ var x = coordinate[0];
+ if (x < projectionExtent[0] || x > projectionExtent[2]) {
+ var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
+ translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];
+ }
+ }
+
+ var layerStates = frameState.layerStatesArray;
+ var numLayers = layerStates.length;
+ var i;
+ for (i = numLayers - 1; i >= 0; --i) {
+ var layerState = layerStates[i];
+ var layer = layerState.layer;
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
+ layerFilter.call(thisArg2, layer)) {
+ var layerRenderer = this.getLayerRenderer(layer);
+ if (layer.getSource()) {
+ result = layerRenderer.forEachFeatureAtCoordinate(
+ layer.getSource().getWrapX() ? translatedCoordinate : coordinate,
+ frameState, forEachFeatureAtCoordinate, thisArg);
+ }
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @param {ol.Pixel} pixel Pixel.
+ * @param {olx.FrameState} frameState FrameState.
+ * @param {function(this: S, ol.layer.Layer): T} callback Layer
+ * callback.
+ * @param {S} thisArg Value to use as `this` when executing `callback`.
+ * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter
+ * function, only layers which are visible and for which this function
+ * returns `true` will be tested for features. By default, all visible
+ * layers will be tested.
+ * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.
+ * @return {T|undefined} Callback result.
+ * @template S,T,U
+ */
+ol.renderer.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
+ layerFilter, thisArg2) {
+ var result;
+ var viewState = frameState.viewState;
+ var viewResolution = viewState.resolution;
+
+ var layerStates = frameState.layerStatesArray;
+ var numLayers = layerStates.length;
+ var i;
+ for (i = numLayers - 1; i >= 0; --i) {
+ var layerState = layerStates[i];
+ var layer = layerState.layer;
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
+ layerFilter.call(thisArg2, layer)) {
+ var layerRenderer = this.getLayerRenderer(layer);
+ result = layerRenderer.forEachLayerAtPixel(
+ pixel, frameState, callback, thisArg);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {olx.FrameState} frameState FrameState.
+ * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter
+ * function, only layers which are visible and for which this function
+ * returns `true` will be tested for features. By default, all visible
+ * layers will be tested.
+ * @param {U} thisArg Value to use as `this` when executing `layerFilter`.
+ * @return {boolean} Is there a feature at the given coordinate?
+ * @template U
+ */
+ol.renderer.Map.prototype.hasFeatureAtCoordinate = function(coordinate, frameState, layerFilter, thisArg) {
+ var hasFeature = this.forEachFeatureAtCoordinate(
+ coordinate, frameState, ol.functions.TRUE, this, layerFilter, thisArg);
+
+ return hasFeature !== undefined;
+};
+
+
+/**
+ * @param {ol.layer.Layer} layer Layer.
+ * @protected
+ * @return {ol.renderer.Layer} Layer renderer.
+ */
+ol.renderer.Map.prototype.getLayerRenderer = function(layer) {
+ var layerKey = goog.getUid(layer).toString();
+ if (layerKey in this.layerRenderers_) {
+ return this.layerRenderers_[layerKey];
+ } else {
+ var layerRenderer = this.createLayerRenderer(layer);
+ this.layerRenderers_[layerKey] = layerRenderer;
+ this.layerRendererListeners_[layerKey] = ol.events.listen(layerRenderer,
+ ol.events.EventType.CHANGE, this.handleLayerRendererChange_, this);
+
+ return layerRenderer;
+ }
+};
+
+
+/**
+ * @param {string} layerKey Layer key.
+ * @protected
+ * @return {ol.renderer.Layer} Layer renderer.
+ */
+ol.renderer.Map.prototype.getLayerRendererByKey = function(layerKey) {
+ goog.asserts.assert(layerKey in this.layerRenderers_,
+ 'given layerKey (%s) exists in layerRenderers', layerKey);
+ return this.layerRenderers_[layerKey];
+};
+
+
+/**
+ * @protected
+ * @return {Object.<string, ol.renderer.Layer>} Layer renderers.
+ */
+ol.renderer.Map.prototype.getLayerRenderers = function() {
+ return this.layerRenderers_;
+};
+
+
+/**
+ * @return {ol.Map} Map.
+ */
+ol.renderer.Map.prototype.getMap = function() {
+ return this.map_;
+};
+
+
+/**
+ * @return {string} Type
+ */
+ol.renderer.Map.prototype.getType = goog.abstractMethod;
+
+
+/**
+ * Handle changes in a layer renderer.
+ * @private
+ */
+ol.renderer.Map.prototype.handleLayerRendererChange_ = function() {
+ this.map_.render();
+};
+
+
+/**
+ * @param {string} layerKey Layer key.
+ * @return {ol.renderer.Layer} Layer renderer.
+ * @private
+ */
+ol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) {
+ goog.asserts.assert(layerKey in this.layerRenderers_,
+ 'given layerKey (%s) exists in layerRenderers', layerKey);
+ var layerRenderer = this.layerRenderers_[layerKey];
+ delete this.layerRenderers_[layerKey];
+
+ goog.asserts.assert(layerKey in this.layerRendererListeners_,
+ 'given layerKey (%s) exists in layerRendererListeners', layerKey);
+ ol.events.unlistenByKey(this.layerRendererListeners_[layerKey]);
+ delete this.layerRendererListeners_[layerKey];
+
+ return layerRenderer;
+};
+
+
+/**
+ * Render.
+ * @param {?olx.FrameState} frameState Frame state.
+ */
+ol.renderer.Map.prototype.renderFrame = ol.nullFunction;
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.Map.prototype.removeUnusedLayerRenderers_ = function(map, frameState) {
+ var layerKey;
+ for (layerKey in this.layerRenderers_) {
+ if (!frameState || !(layerKey in frameState.layerStates)) {
+ this.removeLayerRendererByKey_(layerKey).dispose();
+ }
+ }
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @protected
+ */
+ol.renderer.Map.prototype.scheduleExpireIconCache = function(frameState) {
+ frameState.postRenderFunctions.push(
+ /** @type {ol.PostRenderFunction} */ (ol.renderer.Map.expireIconCache_)
+ );
+};
+
+
+/**
+ * @param {!olx.FrameState} frameState Frame state.
+ * @protected
+ */
+ol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers = function(frameState) {
+ var layerKey;
+ for (layerKey in this.layerRenderers_) {
+ if (!(layerKey in frameState.layerStates)) {
+ frameState.postRenderFunctions.push(
+ /** @type {ol.PostRenderFunction} */ (this.removeUnusedLayerRenderers_.bind(this))
+ );
+ return;
+ }
+ }
+};
+
+
+/**
+ * @param {ol.LayerState} state1 First layer state.
+ * @param {ol.LayerState} state2 Second layer state.
+ * @return {number} The zIndex difference.
+ */
+ol.renderer.Map.sortByZIndex = function(state1, state2) {
+ return state1.zIndex - state2.zIndex;
+};
+
+goog.provide('ol.structs.PriorityQueue');
+
+goog.require('goog.asserts');
+goog.require('ol.object');
+
+
+/**
+ * Priority queue.
+ *
+ * The implementation is inspired from the Closure Library's Heap class and
+ * Python's heapq module.
+ *
+ * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html
+ * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py
+ *
+ * @constructor
+ * @param {function(T): number} priorityFunction Priority function.
+ * @param {function(T): string} keyFunction Key function.
+ * @struct
+ * @template T
+ */
+ol.structs.PriorityQueue = function(priorityFunction, keyFunction) {
+
+ /**
+ * @type {function(T): number}
+ * @private
+ */
+ this.priorityFunction_ = priorityFunction;
+
+ /**
+ * @type {function(T): string}
+ * @private
+ */
+ this.keyFunction_ = keyFunction;
+
+ /**
+ * @type {Array.<T>}
+ * @private
+ */
+ this.elements_ = [];
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.priorities_ = [];
+
+ /**
+ * @type {Object.<string, boolean>}
+ * @private
+ */
+ this.queuedElements_ = {};
+
+};
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.structs.PriorityQueue.DROP = Infinity;
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.structs.PriorityQueue.prototype.assertValid = function() {
+ var elements = this.elements_;
+ var priorities = this.priorities_;
+ var n = elements.length;
+ goog.asserts.assert(priorities.length == n);
+ var i, priority;
+ for (i = 0; i < (n >> 1) - 1; ++i) {
+ priority = priorities[i];
+ goog.asserts.assert(priority <= priorities[this.getLeftChildIndex_(i)],
+ 'priority smaller than or equal to priority of left child (%s <= %s)',
+ priority, priorities[this.getLeftChildIndex_(i)]);
+ goog.asserts.assert(priority <= priorities[this.getRightChildIndex_(i)],
+ 'priority smaller than or equal to priority of right child (%s <= %s)',
+ priority, priorities[this.getRightChildIndex_(i)]);
+ }
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.structs.PriorityQueue.prototype.clear = function() {
+ this.elements_.length = 0;
+ this.priorities_.length = 0;
+ ol.object.clear(this.queuedElements_);
+};
+
+
+/**
+ * Remove and return the highest-priority element. O(log N).
+ * @return {T} Element.
+ */
+ol.structs.PriorityQueue.prototype.dequeue = function() {
+ var elements = this.elements_;
+ goog.asserts.assert(elements.length > 0,
+ 'must have elements in order to be able to dequeue');
+ var priorities = this.priorities_;
+ var element = elements[0];
+ if (elements.length == 1) {
+ elements.length = 0;
+ priorities.length = 0;
+ } else {
+ elements[0] = elements.pop();
+ priorities[0] = priorities.pop();
+ this.siftUp_(0);
+ }
+ var elementKey = this.keyFunction_(element);
+ goog.asserts.assert(elementKey in this.queuedElements_,
+ 'key %s is not listed as queued', elementKey);
+ delete this.queuedElements_[elementKey];
+ return element;
+};
+
+
+/**
+ * Enqueue an element. O(log N).
+ * @param {T} element Element.
+ * @return {boolean} The element was added to the queue.
+ */
+ol.structs.PriorityQueue.prototype.enqueue = function(element) {
+ goog.asserts.assert(!(this.keyFunction_(element) in this.queuedElements_),
+ 'key %s is already listed as queued', this.keyFunction_(element));
+ var priority = this.priorityFunction_(element);
+ if (priority != ol.structs.PriorityQueue.DROP) {
+ this.elements_.push(element);
+ this.priorities_.push(priority);
+ this.queuedElements_[this.keyFunction_(element)] = true;
+ this.siftDown_(0, this.elements_.length - 1);
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * @return {number} Count.
+ */
+ol.structs.PriorityQueue.prototype.getCount = function() {
+ return this.elements_.length;
+};
+
+
+/**
+ * Gets the index of the left child of the node at the given index.
+ * @param {number} index The index of the node to get the left child for.
+ * @return {number} The index of the left child.
+ * @private
+ */
+ol.structs.PriorityQueue.prototype.getLeftChildIndex_ = function(index) {
+ return index * 2 + 1;
+};
+
+
+/**
+ * Gets the index of the right child of the node at the given index.
+ * @param {number} index The index of the node to get the right child for.
+ * @return {number} The index of the right child.
+ * @private
+ */
+ol.structs.PriorityQueue.prototype.getRightChildIndex_ = function(index) {
+ return index * 2 + 2;
+};
+
+
+/**
+ * Gets the index of the parent of the node at the given index.
+ * @param {number} index The index of the node to get the parent for.
+ * @return {number} The index of the parent.
+ * @private
+ */
+ol.structs.PriorityQueue.prototype.getParentIndex_ = function(index) {
+ return (index - 1) >> 1;
+};
+
+
+/**
+ * Make this a heap. O(N).
+ * @private
+ */
+ol.structs.PriorityQueue.prototype.heapify_ = function() {
+ var i;
+ for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {
+ this.siftUp_(i);
+ }
+};
+
+
+/**
+ * @return {boolean} Is empty.
+ */
+ol.structs.PriorityQueue.prototype.isEmpty = function() {
+ return this.elements_.length === 0;
+};
+
+
+/**
+ * @param {string} key Key.
+ * @return {boolean} Is key queued.
+ */
+ol.structs.PriorityQueue.prototype.isKeyQueued = function(key) {
+ return key in this.queuedElements_;
+};
+
+
+/**
+ * @param {T} element Element.
+ * @return {boolean} Is queued.
+ */
+ol.structs.PriorityQueue.prototype.isQueued = function(element) {
+ return this.isKeyQueued(this.keyFunction_(element));
+};
+
+
+/**
+ * @param {number} index The index of the node to move down.
+ * @private
+ */
+ol.structs.PriorityQueue.prototype.siftUp_ = function(index) {
+ var elements = this.elements_;
+ var priorities = this.priorities_;
+ var count = elements.length;
+ var element = elements[index];
+ var priority = priorities[index];
+ var startIndex = index;
+
+ while (index < (count >> 1)) {
+ var lIndex = this.getLeftChildIndex_(index);
+ var rIndex = this.getRightChildIndex_(index);
+
+ var smallerChildIndex = rIndex < count &&
+ priorities[rIndex] < priorities[lIndex] ?
+ rIndex : lIndex;
+
+ elements[index] = elements[smallerChildIndex];
+ priorities[index] = priorities[smallerChildIndex];
+ index = smallerChildIndex;
+ }
+
+ elements[index] = element;
+ priorities[index] = priority;
+ this.siftDown_(startIndex, index);
+};
+
+
+/**
+ * @param {number} startIndex The index of the root.
+ * @param {number} index The index of the node to move up.
+ * @private
+ */
+ol.structs.PriorityQueue.prototype.siftDown_ = function(startIndex, index) {
+ var elements = this.elements_;
+ var priorities = this.priorities_;
+ var element = elements[index];
+ var priority = priorities[index];
+
+ while (index > startIndex) {
+ var parentIndex = this.getParentIndex_(index);
+ if (priorities[parentIndex] > priority) {
+ elements[index] = elements[parentIndex];
+ priorities[index] = priorities[parentIndex];
+ index = parentIndex;
+ } else {
+ break;
+ }
+ }
+ elements[index] = element;
+ priorities[index] = priority;
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.structs.PriorityQueue.prototype.reprioritize = function() {
+ var priorityFunction = this.priorityFunction_;
+ var elements = this.elements_;
+ var priorities = this.priorities_;
+ var index = 0;
+ var n = elements.length;
+ var element, i, priority;
+ for (i = 0; i < n; ++i) {
+ element = elements[i];
+ priority = priorityFunction(element);
+ if (priority == ol.structs.PriorityQueue.DROP) {
+ delete this.queuedElements_[this.keyFunction_(element)];
+ } else {
+ priorities[index] = priority;
+ elements[index++] = element;
+ }
+ }
+ elements.length = index;
+ priorities.length = index;
+ this.heapify_();
+};
+
+goog.provide('ol.TileQueue');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.TileState');
+goog.require('ol.structs.PriorityQueue');
+
+
+/**
+ * @constructor
+ * @extends {ol.structs.PriorityQueue.<Array>}
+ * @param {ol.TilePriorityFunction} tilePriorityFunction
+ * Tile priority function.
+ * @param {function(): ?} tileChangeCallback
+ * Function called on each tile change event.
+ * @struct
+ */
+ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) {
+
+ ol.structs.PriorityQueue.call(
+ this,
+ /**
+ * @param {Array} element Element.
+ * @return {number} Priority.
+ */
+ function(element) {
+ return tilePriorityFunction.apply(null, element);
+ },
+ /**
+ * @param {Array} element Element.
+ * @return {string} Key.
+ */
+ function(element) {
+ return /** @type {ol.Tile} */ (element[0]).getKey();
+ });
+
+ /**
+ * @private
+ * @type {function(): ?}
+ */
+ this.tileChangeCallback_ = tileChangeCallback;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.tilesLoading_ = 0;
+
+ /**
+ * @private
+ * @type {!Object.<string,boolean>}
+ */
+ this.tilesLoadingKeys_ = {};
+
+};
+ol.inherits(ol.TileQueue, ol.structs.PriorityQueue);
+
+
+/**
+ * @inheritDoc
+ */
+ol.TileQueue.prototype.enqueue = function(element) {
+ var added = ol.structs.PriorityQueue.prototype.enqueue.call(this, element);
+ if (added) {
+ var tile = element[0];
+ ol.events.listen(tile, ol.events.EventType.CHANGE,
+ this.handleTileChange, this);
+ }
+ return added;
+};
+
+
+/**
+ * @return {number} Number of tiles loading.
+ */
+ol.TileQueue.prototype.getTilesLoading = function() {
+ return this.tilesLoading_;
+};
+
+
+/**
+ * @param {ol.events.Event} event Event.
+ * @protected
+ */
+ol.TileQueue.prototype.handleTileChange = function(event) {
+ var tile = /** @type {ol.Tile} */ (event.target);
+ var state = tile.getState();
+ if (state === ol.TileState.LOADED || state === ol.TileState.ERROR ||
+ state === ol.TileState.EMPTY || state === ol.TileState.ABORT) {
+ ol.events.unlisten(tile, ol.events.EventType.CHANGE,
+ this.handleTileChange, this);
+ var tileKey = tile.getKey();
+ if (tileKey in this.tilesLoadingKeys_) {
+ delete this.tilesLoadingKeys_[tileKey];
+ --this.tilesLoading_;
+ }
+ this.tileChangeCallback_();
+ }
+ goog.asserts.assert(Object.keys(this.tilesLoadingKeys_).length === this.tilesLoading_);
+};
+
+
+/**
+ * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
+ * @param {number} maxNewLoads Maximum number of new tiles to load.
+ */
+ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {
+ var newLoads = 0;
+ var tile, tileKey;
+ while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&
+ this.getCount() > 0) {
+ tile = /** @type {ol.Tile} */ (this.dequeue()[0]);
+ tileKey = tile.getKey();
+ if (tile.getState() === ol.TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
+ this.tilesLoadingKeys_[tileKey] = true;
+ ++this.tilesLoading_;
+ ++newLoads;
+ tile.load();
+ }
+ goog.asserts.assert(Object.keys(this.tilesLoadingKeys_).length === this.tilesLoading_);
+ }
+};
+
+goog.provide('ol.Kinetic');
+
+goog.require('ol.animation');
+
+
+/**
+ * @classdesc
+ * Implementation of inertial deceleration for map movement.
+ *
+ * @constructor
+ * @param {number} decay Rate of decay (must be negative).
+ * @param {number} minVelocity Minimum velocity (pixels/millisecond).
+ * @param {number} delay Delay to consider to calculate the kinetic
+ * initial values (milliseconds).
+ * @struct
+ * @api
+ */
+ol.Kinetic = function(decay, minVelocity, delay) {
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.decay_ = decay;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.minVelocity_ = minVelocity;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.delay_ = delay;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.points_ = [];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.angle_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.initialVelocity_ = 0;
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.Kinetic.prototype.begin = function() {
+ this.points_.length = 0;
+ this.angle_ = 0;
+ this.initialVelocity_ = 0;
+};
+
+
+/**
+ * @param {number} x X.
+ * @param {number} y Y.
+ */
+ol.Kinetic.prototype.update = function(x, y) {
+ this.points_.push(x, y, Date.now());
+};
+
+
+/**
+ * @return {boolean} Whether we should do kinetic animation.
+ */
+ol.Kinetic.prototype.end = function() {
+ if (this.points_.length < 6) {
+ // at least 2 points are required (i.e. there must be at least 6 elements
+ // in the array)
+ return false;
+ }
+ var delay = Date.now() - this.delay_;
+ var lastIndex = this.points_.length - 3;
+ if (this.points_[lastIndex + 2] < delay) {
+ // the last tracked point is too old, which means that the user stopped
+ // panning before releasing the map
+ return false;
+ }
+
+ // get the first point which still falls into the delay time
+ var firstIndex = lastIndex - 3;
+ while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {
+ firstIndex -= 3;
+ }
+ var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];
+ var dx = this.points_[lastIndex] - this.points_[firstIndex];
+ var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];
+ this.angle_ = Math.atan2(dy, dx);
+ this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;
+ return this.initialVelocity_ > this.minVelocity_;
+};
+
+
+/**
+ * @param {ol.Coordinate} source Source coordinate for the animation.
+ * @return {ol.PreRenderFunction} Pre-render function for kinetic animation.
+ */
+ol.Kinetic.prototype.pan = function(source) {
+ var decay = this.decay_;
+ var initialVelocity = this.initialVelocity_;
+ var velocity = this.minVelocity_ - initialVelocity;
+ var duration = this.getDuration_();
+ var easingFunction = (
+ /**
+ * @param {number} t T.
+ * @return {number} Easing.
+ */
+ function(t) {
+ return initialVelocity * (Math.exp((decay * t) * duration) - 1) /
+ velocity;
+ });
+ return ol.animation.pan({
+ source: source,
+ duration: duration,
+ easing: easingFunction
+ });
+};
+
+
+/**
+ * @private
+ * @return {number} Duration of animation (milliseconds).
+ */
+ol.Kinetic.prototype.getDuration_ = function() {
+ return Math.log(this.minVelocity_ / this.initialVelocity_) / this.decay_;
+};
+
+
+/**
+ * @return {number} Total distance travelled (pixels).
+ */
+ol.Kinetic.prototype.getDistance = function() {
+ return (this.minVelocity_ - this.initialVelocity_) / this.decay_;
+};
+
+
+/**
+ * @return {number} Angle of the kinetic panning animation (radians).
+ */
+ol.Kinetic.prototype.getAngle = function() {
+ return this.angle_;
+};
+
+// FIXME factor out key precondition (shift et. al)
+
+goog.provide('ol.interaction.Interaction');
+goog.provide('ol.interaction.InteractionProperty');
+
+goog.require('ol');
+goog.require('ol.MapBrowserEvent');
+goog.require('ol.Object');
+goog.require('ol.animation');
+goog.require('ol.easing');
+
+
+/**
+ * @enum {string}
+ */
+ol.interaction.InteractionProperty = {
+ ACTIVE: 'active'
+};
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * User actions that change the state of the map. Some are similar to controls,
+ * but are not associated with a DOM element.
+ * For example, {@link ol.interaction.KeyboardZoom} is functionally the same as
+ * {@link ol.control.Zoom}, but triggered by a keyboard event not a button
+ * element event.
+ * Although interactions do not have a DOM element, some of them do render
+ * vectors and so are visible on the screen.
+ *
+ * @constructor
+ * @param {olx.interaction.InteractionOptions} options Options.
+ * @extends {ol.Object}
+ * @api
+ */
+ol.interaction.Interaction = function(options) {
+
+ ol.Object.call(this);
+
+ /**
+ * @private
+ * @type {ol.Map}
+ */
+ this.map_ = null;
+
+ this.setActive(true);
+
+ /**
+ * @type {function(ol.MapBrowserEvent):boolean}
+ */
+ this.handleEvent = options.handleEvent;
+
+};
+ol.inherits(ol.interaction.Interaction, ol.Object);
+
+
+/**
+ * Return whether the interaction is currently active.
+ * @return {boolean} `true` if the interaction is active, `false` otherwise.
+ * @observable
+ * @api
+ */
+ol.interaction.Interaction.prototype.getActive = function() {
+ return /** @type {boolean} */ (
+ this.get(ol.interaction.InteractionProperty.ACTIVE));
+};
+
+
+/**
+ * Get the map associated with this interaction.
+ * @return {ol.Map} Map.
+ * @api
+ */
+ol.interaction.Interaction.prototype.getMap = function() {
+ return this.map_;
+};
+
+
+/**
+ * Activate or deactivate the interaction.
+ * @param {boolean} active Active.
+ * @observable
+ * @api
+ */
+ol.interaction.Interaction.prototype.setActive = function(active) {
+ this.set(ol.interaction.InteractionProperty.ACTIVE, active);
+};
+
+
+/**
+ * Remove the interaction from its current map and attach it to the new map.
+ * Subclasses may set up event handlers to get notified about changes to
+ * the map here.
+ * @param {ol.Map} map Map.
+ */
+ol.interaction.Interaction.prototype.setMap = function(map) {
+ this.map_ = map;
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {ol.View} view View.
+ * @param {ol.Coordinate} delta Delta.
+ * @param {number=} opt_duration Duration.
+ */
+ol.interaction.Interaction.pan = function(map, view, delta, opt_duration) {
+ var currentCenter = view.getCenter();
+ if (currentCenter) {
+ if (opt_duration && opt_duration > 0) {
+ map.beforeRender(ol.animation.pan({
+ source: currentCenter,
+ duration: opt_duration,
+ easing: ol.easing.linear
+ }));
+ }
+ var center = view.constrainCenter(
+ [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]);
+ view.setCenter(center);
+ }
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {ol.View} view View.
+ * @param {number|undefined} rotation Rotation.
+ * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
+ * @param {number=} opt_duration Duration.
+ */
+ol.interaction.Interaction.rotate = function(map, view, rotation, opt_anchor, opt_duration) {
+ rotation = view.constrainRotation(rotation, 0);
+ ol.interaction.Interaction.rotateWithoutConstraints(
+ map, view, rotation, opt_anchor, opt_duration);
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {ol.View} view View.
+ * @param {number|undefined} rotation Rotation.
+ * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
+ * @param {number=} opt_duration Duration.
+ */
+ol.interaction.Interaction.rotateWithoutConstraints = function(map, view, rotation, opt_anchor, opt_duration) {
+ if (rotation !== undefined) {
+ var currentRotation = view.getRotation();
+ var currentCenter = view.getCenter();
+ if (currentRotation !== undefined && currentCenter &&
+ opt_duration && opt_duration > 0) {
+ map.beforeRender(ol.animation.rotate({
+ rotation: currentRotation,
+ duration: opt_duration,
+ easing: ol.easing.easeOut
+ }));
+ if (opt_anchor) {
+ map.beforeRender(ol.animation.pan({
+ source: currentCenter,
+ duration: opt_duration,
+ easing: ol.easing.easeOut
+ }));
+ }
+ }
+ view.rotate(rotation, opt_anchor);
+ }
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {ol.View} view View.
+ * @param {number|undefined} resolution Resolution to go to.
+ * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
+ * @param {number=} opt_duration Duration.
+ * @param {number=} opt_direction Zooming direction; > 0 indicates
+ * zooming out, in which case the constraints system will select
+ * the largest nearest resolution; < 0 indicates zooming in, in
+ * which case the constraints system will select the smallest
+ * nearest resolution; == 0 indicates that the zooming direction
+ * is unknown/not relevant, in which case the constraints system
+ * will select the nearest resolution. If not defined 0 is
+ * assumed.
+ */
+ol.interaction.Interaction.zoom = function(map, view, resolution, opt_anchor, opt_duration, opt_direction) {
+ resolution = view.constrainResolution(resolution, 0, opt_direction);
+ ol.interaction.Interaction.zoomWithoutConstraints(
+ map, view, resolution, opt_anchor, opt_duration);
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {ol.View} view View.
+ * @param {number} delta Delta from previous zoom level.
+ * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
+ * @param {number=} opt_duration Duration.
+ */
+ol.interaction.Interaction.zoomByDelta = function(map, view, delta, opt_anchor, opt_duration) {
+ var currentResolution = view.getResolution();
+ var resolution = view.constrainResolution(currentResolution, delta, 0);
+ ol.interaction.Interaction.zoomWithoutConstraints(
+ map, view, resolution, opt_anchor, opt_duration);
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {ol.View} view View.
+ * @param {number|undefined} resolution Resolution to go to.
+ * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
+ * @param {number=} opt_duration Duration.
+ */
+ol.interaction.Interaction.zoomWithoutConstraints = function(map, view, resolution, opt_anchor, opt_duration) {
+ if (resolution) {
+ var currentResolution = view.getResolution();
+ var currentCenter = view.getCenter();
+ if (currentResolution !== undefined && currentCenter &&
+ resolution !== currentResolution &&
+ opt_duration && opt_duration > 0) {
+ map.beforeRender(ol.animation.zoom({
+ resolution: currentResolution,
+ duration: opt_duration,
+ easing: ol.easing.easeOut
+ }));
+ if (opt_anchor) {
+ map.beforeRender(ol.animation.pan({
+ source: currentCenter,
+ duration: opt_duration,
+ easing: ol.easing.easeOut
+ }));
+ }
+ }
+ if (opt_anchor) {
+ var center = view.calculateCenterZoom(resolution, opt_anchor);
+ view.setCenter(center);
+ }
+ view.setResolution(resolution);
+ }
+};
+
+goog.provide('ol.interaction.DoubleClickZoom');
+
+goog.require('goog.asserts');
+goog.require('ol.MapBrowserEvent');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.interaction.Interaction');
+
+
+/**
+ * @classdesc
+ * Allows the user to zoom by double-clicking on the map.
+ *
+ * @constructor
+ * @extends {ol.interaction.Interaction}
+ * @param {olx.interaction.DoubleClickZoomOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DoubleClickZoom = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.delta_ = options.delta ? options.delta : 1;
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: ol.interaction.DoubleClickZoom.handleEvent
+ });
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 250;
+
+};
+ol.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction);
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a
+ * doubleclick) and eventually zooms the map.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.DoubleClickZoom}
+ * @api
+ */
+ol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) {
+ var stopEvent = false;
+ var browserEvent = mapBrowserEvent.originalEvent;
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK) {
+ var map = mapBrowserEvent.map;
+ var anchor = mapBrowserEvent.coordinate;
+ var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;
+ var view = map.getView();
+ goog.asserts.assert(view, 'map must have a view');
+ ol.interaction.Interaction.zoomByDelta(
+ map, view, delta, anchor, this.duration_);
+ mapBrowserEvent.preventDefault();
+ stopEvent = true;
+ }
+ return !stopEvent;
+};
+
+goog.provide('ol.events.condition');
+
+goog.require('goog.asserts');
+goog.require('ol.functions');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.MapBrowserPointerEvent');
+
+
+/**
+ * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when
+ * additionally the shift-key is pressed).
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if only the alt key is pressed.
+ * @api stable
+ */
+ol.events.condition.altKeyOnly = function(mapBrowserEvent) {
+ var originalEvent = mapBrowserEvent.originalEvent;
+ return (
+ originalEvent.altKey &&
+ !(originalEvent.metaKey || originalEvent.ctrlKey) &&
+ !originalEvent.shiftKey);
+};
+
+
+/**
+ * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise
+ * (e.g. when additionally the platform-modifier-key is pressed).
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if only the alt and shift keys are pressed.
+ * @api stable
+ */
+ol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) {
+ var originalEvent = mapBrowserEvent.originalEvent;
+ return (
+ originalEvent.altKey &&
+ !(originalEvent.metaKey || originalEvent.ctrlKey) &&
+ originalEvent.shiftKey);
+};
+
+
+/**
+ * Return always true.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True.
+ * @function
+ * @api stable
+ */
+ol.events.condition.always = ol.functions.TRUE;
+
+
+/**
+ * Return `true` if the event is a `click` event, `false` otherwise.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if the event is a map `click` event.
+ * @api stable
+ */
+ol.events.condition.click = function(mapBrowserEvent) {
+ return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.CLICK;
+};
+
+
+/**
+ * Return `true` if the event has an "action"-producing mouse button.
+ *
+ * By definition, this includes left-click on windows/linux, and left-click
+ * without the ctrl key on Macs.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} The result.
+ */
+ol.events.condition.mouseActionButton = function(mapBrowserEvent) {
+ var originalEvent = mapBrowserEvent.originalEvent;
+ return originalEvent.button == 0 &&
+ !(goog.userAgent.WEBKIT && ol.has.MAC && originalEvent.ctrlKey);
+};
+
+
+/**
+ * Return always false.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} False.
+ * @function
+ * @api stable
+ */
+ol.events.condition.never = ol.functions.FALSE;
+
+
+/**
+ * Return `true` if the browser event is a `pointermove` event, `false`
+ * otherwise.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if the browser event is a `pointermove` event.
+ * @api
+ */
+ol.events.condition.pointerMove = function(mapBrowserEvent) {
+ return mapBrowserEvent.type == 'pointermove';
+};
+
+
+/**
+ * Return `true` if the event is a map `singleclick` event, `false` otherwise.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if the event is a map `singleclick` event.
+ * @api stable
+ */
+ol.events.condition.singleClick = function(mapBrowserEvent) {
+ return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK;
+};
+
+
+/**
+ * Return `true` if the event is a map `dblclick` event, `false` otherwise.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if the event is a map `dblclick` event.
+ * @api stable
+ */
+ol.events.condition.doubleClick = function(mapBrowserEvent) {
+ return mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK;
+};
+
+
+/**
+ * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is
+ * pressed.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True only if there no modifier keys are pressed.
+ * @api stable
+ */
+ol.events.condition.noModifierKeys = function(mapBrowserEvent) {
+ var originalEvent = mapBrowserEvent.originalEvent;
+ return (
+ !originalEvent.altKey &&
+ !(originalEvent.metaKey || originalEvent.ctrlKey) &&
+ !originalEvent.shiftKey);
+};
+
+
+/**
+ * Return `true` if only the platform-modifier-key (the meta-key on Mac,
+ * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally
+ * the shift-key is pressed).
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if only the platform modifier key is pressed.
+ * @api stable
+ */
+ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) {
+ var originalEvent = mapBrowserEvent.originalEvent;
+ return (
+ !originalEvent.altKey &&
+ (ol.has.MAC ? originalEvent.metaKey : originalEvent.ctrlKey) &&
+ !originalEvent.shiftKey);
+};
+
+
+/**
+ * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when
+ * additionally the alt-key is pressed).
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if only the shift key is pressed.
+ * @api stable
+ */
+ol.events.condition.shiftKeyOnly = function(mapBrowserEvent) {
+ var originalEvent = mapBrowserEvent.originalEvent;
+ return (
+ !originalEvent.altKey &&
+ !(originalEvent.metaKey || originalEvent.ctrlKey) &&
+ originalEvent.shiftKey);
+};
+
+
+/**
+ * Return `true` if the target element is not editable, i.e. not a `<input>`-,
+ * `<select>`- or `<textarea>`-element, `false` otherwise.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True only if the target element is not editable.
+ * @api
+ */
+ol.events.condition.targetNotEditable = function(mapBrowserEvent) {
+ var target = mapBrowserEvent.originalEvent.target;
+ goog.asserts.assertInstanceof(target, Element,
+ 'target should be an Element');
+ var tagName = target.tagName;
+ return (
+ tagName !== 'INPUT' &&
+ tagName !== 'SELECT' &&
+ tagName !== 'TEXTAREA');
+};
+
+
+/**
+ * Return `true` if the event originates from a mouse device.
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if the event originates from a mouse device.
+ * @api stable
+ */
+ol.events.condition.mouseOnly = function(mapBrowserEvent) {
+ // see http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
+ goog.asserts.assertInstanceof(mapBrowserEvent, ol.MapBrowserPointerEvent,
+ 'Requires an ol.MapBrowserPointerEvent to work.');
+ return mapBrowserEvent.pointerEvent.pointerType == 'mouse';
+};
+
+
+/**
+ * Return `true` if the event originates from a primary pointer in
+ * contact with the surface or if the left mouse button is pressed.
+ * @see http://www.w3.org/TR/pointerevents/#button-states
+ *
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} True if the event originates from a primary pointer.
+ * @api
+ */
+ol.events.condition.primaryAction = function(mapBrowserEvent) {
+ var pointerEvent = mapBrowserEvent.pointerEvent;
+ return pointerEvent.isPrimary && pointerEvent.button === 0;
+};
+
+goog.provide('ol.interaction.Pointer');
+
+goog.require('ol');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.MapBrowserPointerEvent');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.object');
+
+
+/**
+ * @classdesc
+ * Base class that calls user-defined functions on `down`, `move` and `up`
+ * events. This class also manages "drag sequences".
+ *
+ * When the `handleDownEvent` user function returns `true` a drag sequence is
+ * started. During a drag sequence the `handleDragEvent` user function is
+ * called on `move` events. The drag sequence ends when the `handleUpEvent`
+ * user function is called and returns `false`.
+ *
+ * @constructor
+ * @param {olx.interaction.PointerOptions=} opt_options Options.
+ * @extends {ol.interaction.Interaction}
+ * @api
+ */
+ol.interaction.Pointer = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var handleEvent = options.handleEvent ?
+ options.handleEvent : ol.interaction.Pointer.handleEvent;
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: handleEvent
+ });
+
+ /**
+ * @type {function(ol.MapBrowserPointerEvent):boolean}
+ * @private
+ */
+ this.handleDownEvent_ = options.handleDownEvent ?
+ options.handleDownEvent : ol.interaction.Pointer.handleDownEvent;
+
+ /**
+ * @type {function(ol.MapBrowserPointerEvent)}
+ * @private
+ */
+ this.handleDragEvent_ = options.handleDragEvent ?
+ options.handleDragEvent : ol.interaction.Pointer.handleDragEvent;
+
+ /**
+ * @type {function(ol.MapBrowserPointerEvent)}
+ * @private
+ */
+ this.handleMoveEvent_ = options.handleMoveEvent ?
+ options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent;
+
+ /**
+ * @type {function(ol.MapBrowserPointerEvent):boolean}
+ * @private
+ */
+ this.handleUpEvent_ = options.handleUpEvent ?
+ options.handleUpEvent : ol.interaction.Pointer.handleUpEvent;
+
+ /**
+ * @type {boolean}
+ * @protected
+ */
+ this.handlingDownUpSequence = false;
+
+ /**
+ * @type {Object.<number, ol.pointer.PointerEvent>}
+ * @private
+ */
+ this.trackedPointers_ = {};
+
+ /**
+ * @type {Array.<ol.pointer.PointerEvent>}
+ * @protected
+ */
+ this.targetPointers = [];
+
+};
+ol.inherits(ol.interaction.Pointer, ol.interaction.Interaction);
+
+
+/**
+ * @param {Array.<ol.pointer.PointerEvent>} pointerEvents List of events.
+ * @return {ol.Pixel} Centroid pixel.
+ */
+ol.interaction.Pointer.centroid = function(pointerEvents) {
+ var length = pointerEvents.length;
+ var clientX = 0;
+ var clientY = 0;
+ for (var i = 0; i < length; i++) {
+ clientX += pointerEvents[i].clientX;
+ clientY += pointerEvents[i].clientY;
+ }
+ return [clientX / length, clientY / length];
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Whether the event is a pointerdown, pointerdrag
+ * or pointerup event.
+ * @private
+ */
+ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = function(mapBrowserEvent) {
+ var type = mapBrowserEvent.type;
+ return (
+ type === ol.MapBrowserEvent.EventType.POINTERDOWN ||
+ type === ol.MapBrowserEvent.EventType.POINTERDRAG ||
+ type === ol.MapBrowserEvent.EventType.POINTERUP);
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @private
+ */
+ol.interaction.Pointer.prototype.updateTrackedPointers_ = function(mapBrowserEvent) {
+ if (this.isPointerDraggingEvent_(mapBrowserEvent)) {
+ var event = mapBrowserEvent.pointerEvent;
+
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) {
+ delete this.trackedPointers_[event.pointerId];
+ } else if (mapBrowserEvent.type ==
+ ol.MapBrowserEvent.EventType.POINTERDOWN) {
+ this.trackedPointers_[event.pointerId] = event;
+ } else if (event.pointerId in this.trackedPointers_) {
+ // update only when there was a pointerdown event for this pointer
+ this.trackedPointers_[event.pointerId] = event;
+ }
+ this.targetPointers = ol.object.getValues(this.trackedPointers_);
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.Pointer}
+ */
+ol.interaction.Pointer.handleDragEvent = ol.nullFunction;
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Capture dragging.
+ * @this {ol.interaction.Pointer}
+ */
+ol.interaction.Pointer.handleUpEvent = ol.functions.FALSE;
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Capture dragging.
+ * @this {ol.interaction.Pointer}
+ */
+ol.interaction.Pointer.handleDownEvent = ol.functions.FALSE;
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.Pointer}
+ */
+ol.interaction.Pointer.handleMoveEvent = ol.nullFunction;
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} and may call into
+ * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
+ * detected.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.Pointer}
+ * @api
+ */
+ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) {
+ if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
+ return true;
+ }
+
+ var stopEvent = false;
+ this.updateTrackedPointers_(mapBrowserEvent);
+ if (this.handlingDownUpSequence) {
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDRAG) {
+ this.handleDragEvent_(mapBrowserEvent);
+ } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) {
+ this.handlingDownUpSequence = this.handleUpEvent_(mapBrowserEvent);
+ }
+ }
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDOWN) {
+ var handled = this.handleDownEvent_(mapBrowserEvent);
+ this.handlingDownUpSequence = handled;
+ stopEvent = this.shouldStopEvent(handled);
+ } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE) {
+ this.handleMoveEvent_(mapBrowserEvent);
+ }
+ return !stopEvent;
+};
+
+
+/**
+ * This method is used to determine if "down" events should be propagated to
+ * other interactions or should be stopped.
+ *
+ * The method receives the return code of the "handleDownEvent" function.
+ *
+ * By default this function is the "identity" function. It's overidden in
+ * child classes.
+ *
+ * @param {boolean} handled Was the event handled by the interaction?
+ * @return {boolean} Should the event be stopped?
+ * @protected
+ */
+ol.interaction.Pointer.prototype.shouldStopEvent = function(handled) {
+ return handled;
+};
+
+goog.provide('ol.interaction.DragPan');
+
+goog.require('goog.asserts');
+goog.require('ol.Kinetic');
+
+goog.require('ol.ViewHint');
+goog.require('ol.coordinate');
+goog.require('ol.functions');
+goog.require('ol.events.condition');
+goog.require('ol.interaction.Pointer');
+
+
+/**
+ * @classdesc
+ * Allows the user to pan the map by dragging the map.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.DragPanOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DragPan = function(opt_options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.DragPan.handleDownEvent_,
+ handleDragEvent: ol.interaction.DragPan.handleDragEvent_,
+ handleUpEvent: ol.interaction.DragPan.handleUpEvent_
+ });
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {ol.Kinetic|undefined}
+ */
+ this.kinetic_ = options.kinetic;
+
+ /**
+ * @private
+ * @type {?ol.PreRenderFunction}
+ */
+ this.kineticPreRenderFn_ = null;
+
+ /**
+ * @type {ol.Pixel}
+ */
+ this.lastCentroid = null;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.noModifierKeys;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.noKinetic_ = false;
+
+};
+ol.inherits(ol.interaction.DragPan, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.DragPan}
+ * @private
+ */
+ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) {
+ goog.asserts.assert(this.targetPointers.length >= 1,
+ 'the length of this.targetPointers should be more than 1');
+ var centroid =
+ ol.interaction.Pointer.centroid(this.targetPointers);
+ if (this.kinetic_) {
+ this.kinetic_.update(centroid[0], centroid[1]);
+ }
+ if (this.lastCentroid) {
+ var deltaX = this.lastCentroid[0] - centroid[0];
+ var deltaY = centroid[1] - this.lastCentroid[1];
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ var viewState = view.getState();
+ var center = [deltaX, deltaY];
+ ol.coordinate.scale(center, viewState.resolution);
+ ol.coordinate.rotate(center, viewState.rotation);
+ ol.coordinate.add(center, viewState.center);
+ center = view.constrainCenter(center);
+ map.render();
+ view.setCenter(center);
+ }
+ this.lastCentroid = centroid;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.DragPan}
+ * @private
+ */
+ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ if (this.targetPointers.length === 0) {
+ if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
+ var distance = this.kinetic_.getDistance();
+ var angle = this.kinetic_.getAngle();
+ var center = view.getCenter();
+ goog.asserts.assert(center !== undefined, 'center should be defined');
+ this.kineticPreRenderFn_ = this.kinetic_.pan(center);
+ map.beforeRender(this.kineticPreRenderFn_);
+ var centerpx = map.getPixelFromCoordinate(center);
+ var dest = map.getCoordinateFromPixel([
+ centerpx[0] - distance * Math.cos(angle),
+ centerpx[1] - distance * Math.sin(angle)
+ ]);
+ dest = view.constrainCenter(dest);
+ view.setCenter(dest);
+ }
+ view.setHint(ol.ViewHint.INTERACTING, -1);
+ map.render();
+ return false;
+ } else {
+ this.lastCentroid = null;
+ return true;
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.DragPan}
+ * @private
+ */
+ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) {
+ if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ this.lastCentroid = null;
+ if (!this.handlingDownUpSequence) {
+ view.setHint(ol.ViewHint.INTERACTING, 1);
+ }
+ map.render();
+ if (this.kineticPreRenderFn_ &&
+ map.removePreRenderFunction(this.kineticPreRenderFn_)) {
+ view.setCenter(mapBrowserEvent.frameState.viewState.center);
+ this.kineticPreRenderFn_ = null;
+ }
+ if (this.kinetic_) {
+ this.kinetic_.begin();
+ }
+ // No kinetic as soon as more than one pointer on the screen is
+ // detected. This is to prevent nasty pans after pinch.
+ this.noKinetic_ = this.targetPointers.length > 1;
+ return true;
+ } else {
+ return false;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.DragPan.prototype.shouldStopEvent = ol.functions.FALSE;
+
+goog.provide('ol.interaction.DragRotate');
+
+goog.require('ol');
+goog.require('ol.ViewHint');
+goog.require('ol.functions');
+goog.require('ol.events.condition');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.interaction.Pointer');
+
+
+/**
+ * @classdesc
+ * Allows the user to rotate the map by clicking and dragging on the map,
+ * normally combined with an {@link ol.events.condition} that limits
+ * it to when the alt and shift keys are held down.
+ *
+ * This interaction is only supported for mouse devices.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.DragRotateOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DragRotate = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.DragRotate.handleDownEvent_,
+ handleDragEvent: ol.interaction.DragRotate.handleDragEvent_,
+ handleUpEvent: ol.interaction.DragRotate.handleUpEvent_
+ });
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.altShiftKeysOnly;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastAngle_ = undefined;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 250;
+};
+ol.inherits(ol.interaction.DragRotate, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.DragRotate}
+ * @private
+ */
+ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return;
+ }
+
+ var map = mapBrowserEvent.map;
+ var size = map.getSize();
+ var offset = mapBrowserEvent.pixel;
+ var theta =
+ Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
+ if (this.lastAngle_ !== undefined) {
+ var delta = theta - this.lastAngle_;
+ var view = map.getView();
+ var rotation = view.getRotation();
+ map.render();
+ ol.interaction.Interaction.rotateWithoutConstraints(
+ map, view, rotation - delta);
+ }
+ this.lastAngle_ = theta;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.DragRotate}
+ * @private
+ */
+ol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return true;
+ }
+
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ view.setHint(ol.ViewHint.INTERACTING, -1);
+ var rotation = view.getRotation();
+ ol.interaction.Interaction.rotate(map, view, rotation,
+ undefined, this.duration_);
+ return false;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.DragRotate}
+ * @private
+ */
+ol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return false;
+ }
+
+ if (ol.events.condition.mouseActionButton(mapBrowserEvent) &&
+ this.condition_(mapBrowserEvent)) {
+ var map = mapBrowserEvent.map;
+ map.getView().setHint(ol.ViewHint.INTERACTING, 1);
+ map.render();
+ this.lastAngle_ = undefined;
+ return true;
+ } else {
+ return false;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.DragRotate.prototype.shouldStopEvent = ol.functions.FALSE;
+
+// FIXME add rotation
+
+goog.provide('ol.render.Box');
+
+goog.require('goog.asserts');
+goog.require('ol.Disposable');
+goog.require('ol.geom.Polygon');
+
+
+/**
+ * @constructor
+ * @extends {ol.Disposable}
+ * @param {string} className CSS class name.
+ */
+ol.render.Box = function(className) {
+
+ /**
+ * @type {ol.geom.Polygon}
+ * @private
+ */
+ this.geometry_ = null;
+
+ /**
+ * @type {HTMLDivElement}
+ * @private
+ */
+ this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div'));
+ this.element_.style.position = 'absolute';
+ this.element_.className = 'ol-box ' + className;
+
+ /**
+ * @private
+ * @type {ol.Map}
+ */
+ this.map_ = null;
+
+ /**
+ * @private
+ * @type {ol.Pixel}
+ */
+ this.startPixel_ = null;
+
+ /**
+ * @private
+ * @type {ol.Pixel}
+ */
+ this.endPixel_ = null;
+
+};
+ol.inherits(ol.render.Box, ol.Disposable);
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.Box.prototype.disposeInternal = function() {
+ this.setMap(null);
+};
+
+
+/**
+ * @private
+ */
+ol.render.Box.prototype.render_ = function() {
+ var startPixel = this.startPixel_;
+ var endPixel = this.endPixel_;
+ goog.asserts.assert(startPixel, 'this.startPixel_ must be truthy');
+ goog.asserts.assert(endPixel, 'this.endPixel_ must be truthy');
+ var px = 'px';
+ var style = this.element_.style;
+ style.left = Math.min(startPixel[0], endPixel[0]) + px;
+ style.top = Math.min(startPixel[1], endPixel[1]) + px;
+ style.width = Math.abs(endPixel[0] - startPixel[0]) + px;
+ style.height = Math.abs(endPixel[1] - startPixel[1]) + px;
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ */
+ol.render.Box.prototype.setMap = function(map) {
+ if (this.map_) {
+ this.map_.getOverlayContainer().removeChild(this.element_);
+ var style = this.element_.style;
+ style.left = style.top = style.width = style.height = 'inherit';
+ }
+ this.map_ = map;
+ if (this.map_) {
+ this.map_.getOverlayContainer().appendChild(this.element_);
+ }
+};
+
+
+/**
+ * @param {ol.Pixel} startPixel Start pixel.
+ * @param {ol.Pixel} endPixel End pixel.
+ */
+ol.render.Box.prototype.setPixels = function(startPixel, endPixel) {
+ this.startPixel_ = startPixel;
+ this.endPixel_ = endPixel;
+ this.createOrUpdateGeometry();
+ this.render_();
+};
+
+
+/**
+ * Creates or updates the cached geometry.
+ */
+ol.render.Box.prototype.createOrUpdateGeometry = function() {
+ goog.asserts.assert(this.startPixel_,
+ 'this.startPixel_ must be truthy');
+ goog.asserts.assert(this.endPixel_,
+ 'this.endPixel_ must be truthy');
+ goog.asserts.assert(this.map_, 'this.map_ must be truthy');
+ var startPixel = this.startPixel_;
+ var endPixel = this.endPixel_;
+ var pixels = [
+ startPixel,
+ [startPixel[0], endPixel[1]],
+ endPixel,
+ [endPixel[0], startPixel[1]]
+ ];
+ var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_);
+ // close the polygon
+ coordinates[4] = coordinates[0].slice();
+ if (!this.geometry_) {
+ this.geometry_ = new ol.geom.Polygon([coordinates]);
+ } else {
+ this.geometry_.setCoordinates([coordinates]);
+ }
+};
+
+
+/**
+ * @return {ol.geom.Polygon} Geometry.
+ */
+ol.render.Box.prototype.getGeometry = function() {
+ return this.geometry_;
+};
+
+// FIXME draw drag box
+goog.provide('ol.DragBoxEvent');
+goog.provide('ol.interaction.DragBox');
+
+goog.require('ol.events.Event');
+goog.require('ol');
+goog.require('ol.events.condition');
+goog.require('ol.interaction.Pointer');
+goog.require('ol.render.Box');
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED =
+ ol.DRAG_BOX_HYSTERESIS_PIXELS *
+ ol.DRAG_BOX_HYSTERESIS_PIXELS;
+
+
+/**
+ * @enum {string}
+ */
+ol.DragBoxEventType = {
+ /**
+ * Triggered upon drag box start.
+ * @event ol.DragBoxEvent#boxstart
+ * @api stable
+ */
+ BOXSTART: 'boxstart',
+
+ /**
+ * Triggered on drag when box is active.
+ * @event ol.DragBoxEvent#boxdrag
+ * @api
+ */
+ BOXDRAG: 'boxdrag',
+
+ /**
+ * Triggered upon drag box end.
+ * @event ol.DragBoxEvent#boxend
+ * @api stable
+ */
+ BOXEND: 'boxend'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.interaction.DragBox} instances are instances of
+ * this type.
+ *
+ * @param {string} type The event type.
+ * @param {ol.Coordinate} coordinate The event coordinate.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Originating event.
+ * @extends {ol.events.Event}
+ * @constructor
+ * @implements {oli.DragBoxEvent}
+ */
+ol.DragBoxEvent = function(type, coordinate, mapBrowserEvent) {
+ ol.events.Event.call(this, type);
+
+ /**
+ * The coordinate of the drag event.
+ * @const
+ * @type {ol.Coordinate}
+ * @api stable
+ */
+ this.coordinate = coordinate;
+
+ /**
+ * @const
+ * @type {ol.MapBrowserEvent}
+ * @api
+ */
+ this.mapBrowserEvent = mapBrowserEvent;
+
+};
+ol.inherits(ol.DragBoxEvent, ol.events.Event);
+
+
+/**
+ * @classdesc
+ * Allows the user to draw a vector box by clicking and dragging on the map,
+ * normally combined with an {@link ol.events.condition} that limits
+ * it to when the shift or other key is held down. This is used, for example,
+ * for zooming to a specific area of the map
+ * (see {@link ol.interaction.DragZoom} and
+ * {@link ol.interaction.DragRotateAndZoom}).
+ *
+ * This interaction is only supported for mouse devices.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @fires ol.DragBoxEvent
+ * @param {olx.interaction.DragBoxOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DragBox = function(opt_options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.DragBox.handleDownEvent_,
+ handleDragEvent: ol.interaction.DragBox.handleDragEvent_,
+ handleUpEvent: ol.interaction.DragBox.handleUpEvent_
+ });
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @type {ol.render.Box}
+ * @private
+ */
+ this.box_ = new ol.render.Box(options.className || 'ol-dragbox');
+
+ /**
+ * @type {ol.Pixel}
+ * @private
+ */
+ this.startPixel_ = null;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.always;
+
+ /**
+ * @private
+ * @type {ol.DragBoxEndConditionType}
+ */
+ this.boxEndCondition_ = options.boxEndCondition ?
+ options.boxEndCondition : ol.interaction.DragBox.defaultBoxEndCondition;
+};
+ol.inherits(ol.interaction.DragBox, ol.interaction.Pointer);
+
+
+/**
+ * The default condition for determining whether the boxend event
+ * should fire.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent The originating MapBrowserEvent
+ * leading to the box end.
+ * @param {ol.Pixel} startPixel The starting pixel of the box.
+ * @param {ol.Pixel} endPixel The end pixel of the box.
+ * @return {boolean} Whether or not the boxend condition should be fired.
+ */
+ol.interaction.DragBox.defaultBoxEndCondition = function(mapBrowserEvent,
+ startPixel, endPixel) {
+ var width = endPixel[0] - startPixel[0];
+ var height = endPixel[1] - startPixel[1];
+ return width * width + height * height >=
+ ol.DRAG_BOX_HYSTERESIS_PIXELS_SQUARED;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.DragBox}
+ * @private
+ */
+ol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return;
+ }
+
+ this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel);
+
+ this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXDRAG,
+ mapBrowserEvent.coordinate, mapBrowserEvent));
+};
+
+
+/**
+ * Returns geometry of last drawn box.
+ * @return {ol.geom.Polygon} Geometry.
+ * @api stable
+ */
+ol.interaction.DragBox.prototype.getGeometry = function() {
+ return this.box_.getGeometry();
+};
+
+
+/**
+ * To be overriden by child classes.
+ * FIXME: use constructor option instead of relying on overridding.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @protected
+ */
+ol.interaction.DragBox.prototype.onBoxEnd = ol.nullFunction;
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.DragBox}
+ * @private
+ */
+ol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return true;
+ }
+
+ this.box_.setMap(null);
+
+ if (this.boxEndCondition_(mapBrowserEvent,
+ this.startPixel_, mapBrowserEvent.pixel)) {
+ this.onBoxEnd(mapBrowserEvent);
+ this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXEND,
+ mapBrowserEvent.coordinate, mapBrowserEvent));
+ }
+ return false;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.DragBox}
+ * @private
+ */
+ol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return false;
+ }
+
+ if (ol.events.condition.mouseActionButton(mapBrowserEvent) &&
+ this.condition_(mapBrowserEvent)) {
+ this.startPixel_ = mapBrowserEvent.pixel;
+ this.box_.setMap(mapBrowserEvent.map);
+ this.box_.setPixels(this.startPixel_, this.startPixel_);
+ this.dispatchEvent(new ol.DragBoxEvent(ol.DragBoxEventType.BOXSTART,
+ mapBrowserEvent.coordinate, mapBrowserEvent));
+ return true;
+ } else {
+ return false;
+ }
+};
+
+goog.provide('ol.interaction.DragZoom');
+
+goog.require('goog.asserts');
+goog.require('ol.animation');
+goog.require('ol.easing');
+goog.require('ol.events.condition');
+goog.require('ol.extent');
+goog.require('ol.interaction.DragBox');
+
+
+/**
+ * @classdesc
+ * Allows the user to zoom the map by clicking and dragging on the map,
+ * normally combined with an {@link ol.events.condition} that limits
+ * it to when a key, shift by default, is held down.
+ *
+ * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or
+ * your custom one configured with `className`.
+ *
+ * @constructor
+ * @extends {ol.interaction.DragBox}
+ * @param {olx.interaction.DragZoomOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DragZoom = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+
+ var condition = options.condition ?
+ options.condition : ol.events.condition.shiftKeyOnly;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 200;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.out_ = options.out !== undefined ? options.out : false;
+
+ ol.interaction.DragBox.call(this, {
+ condition: condition,
+ className: options.className || 'ol-dragzoom'
+ });
+
+};
+ol.inherits(ol.interaction.DragZoom, ol.interaction.DragBox);
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.DragZoom.prototype.onBoxEnd = function() {
+ var map = this.getMap();
+
+ var view = map.getView();
+ goog.asserts.assert(view, 'map must have view');
+
+ var size = map.getSize();
+ goog.asserts.assert(size !== undefined, 'size should be defined');
+
+ var extent = this.getGeometry().getExtent();
+
+ if (this.out_) {
+ var mapExtent = view.calculateExtent(size);
+ var boxPixelExtent = ol.extent.createOrUpdateFromCoordinates([
+ map.getPixelFromCoordinate(ol.extent.getBottomLeft(extent)),
+ map.getPixelFromCoordinate(ol.extent.getTopRight(extent))]);
+ var factor = view.getResolutionForExtent(boxPixelExtent, size);
+
+ ol.extent.scaleFromCenter(mapExtent, 1 / factor);
+ extent = mapExtent;
+ }
+
+ var resolution = view.constrainResolution(
+ view.getResolutionForExtent(extent, size));
+
+ var currentResolution = view.getResolution();
+ goog.asserts.assert(currentResolution !== undefined, 'res should be defined');
+
+ var currentCenter = view.getCenter();
+ goog.asserts.assert(currentCenter !== undefined, 'center should be defined');
+
+ map.beforeRender(ol.animation.zoom({
+ resolution: currentResolution,
+ duration: this.duration_,
+ easing: ol.easing.easeOut
+ }));
+ map.beforeRender(ol.animation.pan({
+ source: currentCenter,
+ duration: this.duration_,
+ easing: ol.easing.easeOut
+ }));
+
+ view.setCenter(ol.extent.getCenter(extent));
+ view.setResolution(resolution);
+};
+
+goog.provide('ol.interaction.KeyboardPan');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.coordinate');
+goog.require('ol.events.EventType');
+goog.require('ol.events.KeyCode');
+goog.require('ol.events.condition');
+goog.require('ol.interaction.Interaction');
+
+
+/**
+ * @classdesc
+ * Allows the user to pan the map using keyboard arrows.
+ * Note that, although this interaction is by default included in maps,
+ * the keys can only be used when browser focus is on the element to which
+ * the keyboard events are attached. By default, this is the map div,
+ * though you can change this with the `keyboardEventTarget` in
+ * {@link ol.Map}. `document` never loses focus but, for any other element,
+ * focus will have to be on, and returned to, this element if the keys are to
+ * function.
+ * See also {@link ol.interaction.KeyboardZoom}.
+ *
+ * @constructor
+ * @extends {ol.interaction.Interaction}
+ * @param {olx.interaction.KeyboardPanOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.KeyboardPan = function(opt_options) {
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: ol.interaction.KeyboardPan.handleEvent
+ });
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
+ * @return {boolean} Combined condition result.
+ */
+ this.defaultCondition_ = function(mapBrowserEvent) {
+ return ol.events.condition.noModifierKeys(mapBrowserEvent) &&
+ ol.events.condition.targetNotEditable(mapBrowserEvent);
+ };
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition !== undefined ?
+ options.condition : this.defaultCondition_;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 100;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.pixelDelta_ = options.pixelDelta !== undefined ?
+ options.pixelDelta : 128;
+
+};
+ol.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction);
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} if it was a
+ * `KeyEvent`, and decides the direction to pan to (if an arrow key was
+ * pressed).
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.KeyboardPan}
+ * @api
+ */
+ol.interaction.KeyboardPan.handleEvent = function(mapBrowserEvent) {
+ var stopEvent = false;
+ if (mapBrowserEvent.type == ol.events.EventType.KEYDOWN) {
+ var keyEvent = mapBrowserEvent.originalEvent;
+ var keyCode = keyEvent.keyCode;
+ if (this.condition_(mapBrowserEvent) &&
+ (keyCode == ol.events.KeyCode.DOWN ||
+ keyCode == ol.events.KeyCode.LEFT ||
+ keyCode == ol.events.KeyCode.RIGHT ||
+ keyCode == ol.events.KeyCode.UP)) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ goog.asserts.assert(view, 'map must have view');
+ var mapUnitsDelta = view.getResolution() * this.pixelDelta_;
+ var deltaX = 0, deltaY = 0;
+ if (keyCode == ol.events.KeyCode.DOWN) {
+ deltaY = -mapUnitsDelta;
+ } else if (keyCode == ol.events.KeyCode.LEFT) {
+ deltaX = -mapUnitsDelta;
+ } else if (keyCode == ol.events.KeyCode.RIGHT) {
+ deltaX = mapUnitsDelta;
+ } else {
+ deltaY = mapUnitsDelta;
+ }
+ var delta = [deltaX, deltaY];
+ ol.coordinate.rotate(delta, view.getRotation());
+ ol.interaction.Interaction.pan(map, view, delta, this.duration_);
+ mapBrowserEvent.preventDefault();
+ stopEvent = true;
+ }
+ }
+ return !stopEvent;
+};
+
+goog.provide('ol.interaction.KeyboardZoom');
+
+goog.require('goog.asserts');
+goog.require('ol.events.EventType');
+goog.require('ol.events.condition');
+goog.require('ol.interaction.Interaction');
+
+
+/**
+ * @classdesc
+ * Allows the user to zoom the map using keyboard + and -.
+ * Note that, although this interaction is by default included in maps,
+ * the keys can only be used when browser focus is on the element to which
+ * the keyboard events are attached. By default, this is the map div,
+ * though you can change this with the `keyboardEventTarget` in
+ * {@link ol.Map}. `document` never loses focus but, for any other element,
+ * focus will have to be on, and returned to, this element if the keys are to
+ * function.
+ * See also {@link ol.interaction.KeyboardPan}.
+ *
+ * @constructor
+ * @param {olx.interaction.KeyboardZoomOptions=} opt_options Options.
+ * @extends {ol.interaction.Interaction}
+ * @api stable
+ */
+ol.interaction.KeyboardZoom = function(opt_options) {
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: ol.interaction.KeyboardZoom.handleEvent
+ });
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ? options.condition :
+ ol.events.condition.targetNotEditable;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.delta_ = options.delta ? options.delta : 1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 100;
+
+};
+ol.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} if it was a
+ * `KeyEvent`, and decides whether to zoom in or out (depending on whether the
+ * key pressed was '+' or '-').
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.KeyboardZoom}
+ * @api
+ */
+ol.interaction.KeyboardZoom.handleEvent = function(mapBrowserEvent) {
+ var stopEvent = false;
+ if (mapBrowserEvent.type == ol.events.EventType.KEYDOWN ||
+ mapBrowserEvent.type == ol.events.EventType.KEYPRESS) {
+ var keyEvent = mapBrowserEvent.originalEvent;
+ var charCode = keyEvent.charCode;
+ if (this.condition_(mapBrowserEvent) &&
+ (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) {
+ var map = mapBrowserEvent.map;
+ var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_;
+ map.render();
+ var view = map.getView();
+ goog.asserts.assert(view, 'map must have view');
+ ol.interaction.Interaction.zoomByDelta(
+ map, view, delta, undefined, this.duration_);
+ mapBrowserEvent.preventDefault();
+ stopEvent = true;
+ }
+ }
+ return !stopEvent;
+};
+
+goog.provide('ol.interaction.MouseWheelZoom');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.events.EventType');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * Allows the user to zoom the map by scrolling the mouse wheel.
+ *
+ * @constructor
+ * @extends {ol.interaction.Interaction}
+ * @param {olx.interaction.MouseWheelZoomOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.MouseWheelZoom = function(opt_options) {
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: ol.interaction.MouseWheelZoom.handleEvent
+ });
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.delta_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 250;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true;
+
+ /**
+ * @private
+ * @type {?ol.Coordinate}
+ */
+ this.lastAnchor_ = null;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.startTime_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.timeoutId_ = undefined;
+
+};
+ol.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a
+ * mousewheel-event) and eventually zooms the map.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.MouseWheelZoom}
+ * @api
+ */
+ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) {
+ var stopEvent = false;
+ if (mapBrowserEvent.type == ol.events.EventType.WHEEL ||
+ mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {
+ var map = mapBrowserEvent.map;
+ var wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);
+
+ if (this.useAnchor_) {
+ this.lastAnchor_ = mapBrowserEvent.coordinate;
+ }
+
+ // Delta normalisation inspired by
+ // https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js
+ //TODO There's more good stuff in there for inspiration to improve this interaction.
+ var delta;
+ if (mapBrowserEvent.type == ol.events.EventType.WHEEL) {
+ delta = wheelEvent.deltaY;
+ if (ol.has.FIREFOX &&
+ wheelEvent.deltaMode === ol.global.WheelEvent.DOM_DELTA_PIXEL) {
+ delta /= ol.has.DEVICE_PIXEL_RATIO;
+ }
+ if (wheelEvent.deltaMode === ol.global.WheelEvent.DOM_DELTA_LINE) {
+ delta *= 40;
+ }
+ } else if (mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {
+ delta = -wheelEvent.wheelDeltaY;
+ if (ol.has.SAFARI) {
+ delta /= 3;
+ }
+ }
+
+ this.delta_ += delta;
+
+ if (this.startTime_ === undefined) {
+ this.startTime_ = Date.now();
+ }
+
+ var duration = ol.MOUSEWHEELZOOM_TIMEOUT_DURATION;
+ var timeLeft = Math.max(duration - (Date.now() - this.startTime_), 0);
+
+ ol.global.clearTimeout(this.timeoutId_);
+ this.timeoutId_ = ol.global.setTimeout(
+ this.doZoom_.bind(this, map), timeLeft);
+
+ mapBrowserEvent.preventDefault();
+ stopEvent = true;
+ }
+ return !stopEvent;
+};
+
+
+/**
+ * @private
+ * @param {ol.Map} map Map.
+ */
+ol.interaction.MouseWheelZoom.prototype.doZoom_ = function(map) {
+ var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA;
+ var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta);
+
+ var view = map.getView();
+ goog.asserts.assert(view, 'map must have view');
+
+ map.render();
+ ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_,
+ this.duration_);
+
+ this.delta_ = 0;
+ this.lastAnchor_ = null;
+ this.startTime_ = undefined;
+ this.timeoutId_ = undefined;
+};
+
+
+/**
+ * Enable or disable using the mouse's location as an anchor when zooming
+ * @param {boolean} useAnchor true to zoom to the mouse's location, false
+ * to zoom to the center of the map
+ * @api
+ */
+ol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) {
+ this.useAnchor_ = useAnchor;
+ if (!useAnchor) {
+ this.lastAnchor_ = null;
+ }
+};
+
+goog.provide('ol.interaction.PinchRotate');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.functions');
+goog.require('ol.ViewHint');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.interaction.Pointer');
+
+
+/**
+ * @classdesc
+ * Allows the user to rotate the map by twisting with two fingers
+ * on a touch screen.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.PinchRotateOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.PinchRotate = function(opt_options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_,
+ handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_,
+ handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_
+ });
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.anchor_ = null;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastAngle_ = undefined;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.rotating_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.rotationDelta_ = 0.0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 250;
+
+};
+ol.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.PinchRotate}
+ * @private
+ */
+ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {
+ goog.asserts.assert(this.targetPointers.length >= 2,
+ 'length of this.targetPointers should be greater than or equal to 2');
+ var rotationDelta = 0.0;
+
+ var touch0 = this.targetPointers[0];
+ var touch1 = this.targetPointers[1];
+
+ // angle between touches
+ var angle = Math.atan2(
+ touch1.clientY - touch0.clientY,
+ touch1.clientX - touch0.clientX);
+
+ if (this.lastAngle_ !== undefined) {
+ var delta = angle - this.lastAngle_;
+ this.rotationDelta_ += delta;
+ if (!this.rotating_ &&
+ Math.abs(this.rotationDelta_) > this.threshold_) {
+ this.rotating_ = true;
+ }
+ rotationDelta = delta;
+ }
+ this.lastAngle_ = angle;
+
+ var map = mapBrowserEvent.map;
+
+ // rotate anchor point.
+ // FIXME: should be the intersection point between the lines:
+ // touch0,touch1 and previousTouch0,previousTouch1
+ var viewportPosition = map.getViewport().getBoundingClientRect();
+ var centroid = ol.interaction.Pointer.centroid(this.targetPointers);
+ centroid[0] -= viewportPosition.left;
+ centroid[1] -= viewportPosition.top;
+ this.anchor_ = map.getCoordinateFromPixel(centroid);
+
+ // rotate
+ if (this.rotating_) {
+ var view = map.getView();
+ var rotation = view.getRotation();
+ map.render();
+ ol.interaction.Interaction.rotateWithoutConstraints(map, view,
+ rotation + rotationDelta, this.anchor_);
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.PinchRotate}
+ * @private
+ */
+ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) {
+ if (this.targetPointers.length < 2) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ view.setHint(ol.ViewHint.INTERACTING, -1);
+ if (this.rotating_) {
+ var rotation = view.getRotation();
+ ol.interaction.Interaction.rotate(
+ map, view, rotation, this.anchor_, this.duration_);
+ }
+ return false;
+ } else {
+ return true;
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.PinchRotate}
+ * @private
+ */
+ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) {
+ if (this.targetPointers.length >= 2) {
+ var map = mapBrowserEvent.map;
+ this.anchor_ = null;
+ this.lastAngle_ = undefined;
+ this.rotating_ = false;
+ this.rotationDelta_ = 0.0;
+ if (!this.handlingDownUpSequence) {
+ map.getView().setHint(ol.ViewHint.INTERACTING, 1);
+ }
+ map.render();
+ return true;
+ } else {
+ return false;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.PinchRotate.prototype.shouldStopEvent = ol.functions.FALSE;
+
+goog.provide('ol.interaction.PinchZoom');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.functions');
+goog.require('ol.ViewHint');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.interaction.Pointer');
+
+
+/**
+ * @classdesc
+ * Allows the user to zoom the map by pinching with two fingers
+ * on a touch screen.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.PinchZoomOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.PinchZoom = function(opt_options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_,
+ handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_,
+ handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_
+ });
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.anchor_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 400;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastDistance_ = undefined;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.lastScaleDelta_ = 1;
+
+};
+ol.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.PinchZoom}
+ * @private
+ */
+ol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) {
+ goog.asserts.assert(this.targetPointers.length >= 2,
+ 'length of this.targetPointers should be 2 or more');
+ var scaleDelta = 1.0;
+
+ var touch0 = this.targetPointers[0];
+ var touch1 = this.targetPointers[1];
+ var dx = touch0.clientX - touch1.clientX;
+ var dy = touch0.clientY - touch1.clientY;
+
+ // distance between touches
+ var distance = Math.sqrt(dx * dx + dy * dy);
+
+ if (this.lastDistance_ !== undefined) {
+ scaleDelta = this.lastDistance_ / distance;
+ }
+ this.lastDistance_ = distance;
+ if (scaleDelta != 1.0) {
+ this.lastScaleDelta_ = scaleDelta;
+ }
+
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ var resolution = view.getResolution();
+
+ // scale anchor point.
+ var viewportPosition = map.getViewport().getBoundingClientRect();
+ var centroid = ol.interaction.Pointer.centroid(this.targetPointers);
+ centroid[0] -= viewportPosition.left;
+ centroid[1] -= viewportPosition.top;
+ this.anchor_ = map.getCoordinateFromPixel(centroid);
+
+ // scale, bypass the resolution constraint
+ map.render();
+ ol.interaction.Interaction.zoomWithoutConstraints(
+ map, view, resolution * scaleDelta, this.anchor_);
+
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.PinchZoom}
+ * @private
+ */
+ol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) {
+ if (this.targetPointers.length < 2) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ view.setHint(ol.ViewHint.INTERACTING, -1);
+ var resolution = view.getResolution();
+ // Zoom to final resolution, with an animation, and provide a
+ // direction not to zoom out/in if user was pinching in/out.
+ // Direction is > 0 if pinching out, and < 0 if pinching in.
+ var direction = this.lastScaleDelta_ - 1;
+ ol.interaction.Interaction.zoom(map, view, resolution,
+ this.anchor_, this.duration_, direction);
+ return false;
+ } else {
+ return true;
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.PinchZoom}
+ * @private
+ */
+ol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) {
+ if (this.targetPointers.length >= 2) {
+ var map = mapBrowserEvent.map;
+ this.anchor_ = null;
+ this.lastDistance_ = undefined;
+ this.lastScaleDelta_ = 1;
+ if (!this.handlingDownUpSequence) {
+ map.getView().setHint(ol.ViewHint.INTERACTING, 1);
+ }
+ map.render();
+ return true;
+ } else {
+ return false;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.PinchZoom.prototype.shouldStopEvent = ol.functions.FALSE;
+
+goog.provide('ol.interaction');
+
+goog.require('ol');
+goog.require('ol.Collection');
+goog.require('ol.Kinetic');
+goog.require('ol.interaction.DoubleClickZoom');
+goog.require('ol.interaction.DragPan');
+goog.require('ol.interaction.DragRotate');
+goog.require('ol.interaction.DragZoom');
+goog.require('ol.interaction.KeyboardPan');
+goog.require('ol.interaction.KeyboardZoom');
+goog.require('ol.interaction.MouseWheelZoom');
+goog.require('ol.interaction.PinchRotate');
+goog.require('ol.interaction.PinchZoom');
+
+
+/**
+ * Set of interactions included in maps by default. Specific interactions can be
+ * excluded by setting the appropriate option to false in the constructor
+ * options, but the order of the interactions is fixed. If you want to specify
+ * a different order for interactions, you will need to create your own
+ * {@link ol.interaction.Interaction} instances and insert them into a
+ * {@link ol.Collection} in the order you want before creating your
+ * {@link ol.Map} instance. The default set of interactions, in sequence, is:
+ * * {@link ol.interaction.DragRotate}
+ * * {@link ol.interaction.DoubleClickZoom}
+ * * {@link ol.interaction.DragPan}
+ * * {@link ol.interaction.PinchRotate}
+ * * {@link ol.interaction.PinchZoom}
+ * * {@link ol.interaction.KeyboardPan}
+ * * {@link ol.interaction.KeyboardZoom}
+ * * {@link ol.interaction.MouseWheelZoom}
+ * * {@link ol.interaction.DragZoom}
+ *
+ * @param {olx.interaction.DefaultsOptions=} opt_options Defaults options.
+ * @return {ol.Collection.<ol.interaction.Interaction>} A collection of
+ * interactions to be used with the ol.Map constructor's interactions option.
+ * @api stable
+ */
+ol.interaction.defaults = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var interactions = new ol.Collection();
+
+ var kinetic = new ol.Kinetic(-0.005, 0.05, 100);
+
+ var altShiftDragRotate = options.altShiftDragRotate !== undefined ?
+ options.altShiftDragRotate : true;
+ if (altShiftDragRotate) {
+ interactions.push(new ol.interaction.DragRotate());
+ }
+
+ var doubleClickZoom = options.doubleClickZoom !== undefined ?
+ options.doubleClickZoom : true;
+ if (doubleClickZoom) {
+ interactions.push(new ol.interaction.DoubleClickZoom({
+ delta: options.zoomDelta,
+ duration: options.zoomDuration
+ }));
+ }
+
+ var dragPan = options.dragPan !== undefined ? options.dragPan : true;
+ if (dragPan) {
+ interactions.push(new ol.interaction.DragPan({
+ kinetic: kinetic
+ }));
+ }
+
+ var pinchRotate = options.pinchRotate !== undefined ? options.pinchRotate :
+ true;
+ if (pinchRotate) {
+ interactions.push(new ol.interaction.PinchRotate());
+ }
+
+ var pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;
+ if (pinchZoom) {
+ interactions.push(new ol.interaction.PinchZoom({
+ duration: options.zoomDuration
+ }));
+ }
+
+ var keyboard = options.keyboard !== undefined ? options.keyboard : true;
+ if (keyboard) {
+ interactions.push(new ol.interaction.KeyboardPan());
+ interactions.push(new ol.interaction.KeyboardZoom({
+ delta: options.zoomDelta,
+ duration: options.zoomDuration
+ }));
+ }
+
+ var mouseWheelZoom = options.mouseWheelZoom !== undefined ?
+ options.mouseWheelZoom : true;
+ if (mouseWheelZoom) {
+ interactions.push(new ol.interaction.MouseWheelZoom({
+ duration: options.zoomDuration
+ }));
+ }
+
+ var shiftDragZoom = options.shiftDragZoom !== undefined ?
+ options.shiftDragZoom : true;
+ if (shiftDragZoom) {
+ interactions.push(new ol.interaction.DragZoom({
+ duration: options.zoomDuration
+ }));
+ }
+
+ return interactions;
+
+};
+
+goog.provide('ol.layer.Group');
+
+goog.require('goog.asserts');
+goog.require('ol.Collection');
+goog.require('ol.CollectionEvent');
+goog.require('ol.CollectionEventType');
+goog.require('ol.Object');
+goog.require('ol.ObjectEventType');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.layer.Base');
+goog.require('ol.object');
+goog.require('ol.source.State');
+
+
+/**
+ * @enum {string}
+ */
+ol.layer.GroupProperty = {
+ LAYERS: 'layers'
+};
+
+
+/**
+ * @classdesc
+ * A {@link ol.Collection} of layers that are handled together.
+ *
+ * A generic `change` event is triggered when the group/Collection changes.
+ *
+ * @constructor
+ * @extends {ol.layer.Base}
+ * @param {olx.layer.GroupOptions=} opt_options Layer options.
+ * @api stable
+ */
+ol.layer.Group = function(opt_options) {
+
+ var options = opt_options || {};
+ var baseOptions = /** @type {olx.layer.GroupOptions} */
+ (ol.object.assign({}, options));
+ delete baseOptions.layers;
+
+ var layers = options.layers;
+
+ ol.layer.Base.call(this, baseOptions);
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.layersListenerKeys_ = [];
+
+ /**
+ * @private
+ * @type {Object.<string, Array.<ol.EventsKey>>}
+ */
+ this.listenerKeys_ = {};
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.layer.GroupProperty.LAYERS),
+ this.handleLayersChanged_, this);
+
+ if (layers) {
+ if (Array.isArray(layers)) {
+ layers = new ol.Collection(layers.slice());
+ } else {
+ goog.asserts.assertInstanceof(layers, ol.Collection,
+ 'layers should be an ol.Collection');
+ layers = layers;
+ }
+ } else {
+ layers = new ol.Collection();
+ }
+
+ this.setLayers(layers);
+
+};
+ol.inherits(ol.layer.Group, ol.layer.Base);
+
+
+/**
+ * @private
+ */
+ol.layer.Group.prototype.handleLayerChange_ = function() {
+ if (this.getVisible()) {
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.events.Event} event Event.
+ * @private
+ */
+ol.layer.Group.prototype.handleLayersChanged_ = function(event) {
+ this.layersListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.layersListenerKeys_.length = 0;
+
+ var layers = this.getLayers();
+ this.layersListenerKeys_.push(
+ ol.events.listen(layers, ol.CollectionEventType.ADD,
+ this.handleLayersAdd_, this),
+ ol.events.listen(layers, ol.CollectionEventType.REMOVE,
+ this.handleLayersRemove_, this));
+
+ for (var id in this.listenerKeys_) {
+ this.listenerKeys_[id].forEach(ol.events.unlistenByKey);
+ }
+ ol.object.clear(this.listenerKeys_);
+
+ var layersArray = layers.getArray();
+ var i, ii, layer;
+ for (i = 0, ii = layersArray.length; i < ii; i++) {
+ layer = layersArray[i];
+ this.listenerKeys_[goog.getUid(layer).toString()] = [
+ ol.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE,
+ this.handleLayerChange_, this),
+ ol.events.listen(layer, ol.events.EventType.CHANGE,
+ this.handleLayerChange_, this)
+ ];
+ }
+
+ this.changed();
+};
+
+
+/**
+ * @param {ol.CollectionEvent} collectionEvent Collection event.
+ * @private
+ */
+ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) {
+ var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
+ var key = goog.getUid(layer).toString();
+ goog.asserts.assert(!(key in this.listenerKeys_),
+ 'listeners already registered');
+ this.listenerKeys_[key] = [
+ ol.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE,
+ this.handleLayerChange_, this),
+ ol.events.listen(layer, ol.events.EventType.CHANGE,
+ this.handleLayerChange_, this)
+ ];
+ this.changed();
+};
+
+
+/**
+ * @param {ol.CollectionEvent} collectionEvent Collection event.
+ * @private
+ */
+ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) {
+ var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
+ var key = goog.getUid(layer).toString();
+ goog.asserts.assert(key in this.listenerKeys_, 'no listeners to unregister');
+ this.listenerKeys_[key].forEach(ol.events.unlistenByKey);
+ delete this.listenerKeys_[key];
+ this.changed();
+};
+
+
+/**
+ * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
+ * in this group.
+ * @return {!ol.Collection.<ol.layer.Base>} Collection of
+ * {@link ol.layer.Base layers} that are part of this group.
+ * @observable
+ * @api stable
+ */
+ol.layer.Group.prototype.getLayers = function() {
+ return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get(
+ ol.layer.GroupProperty.LAYERS));
+};
+
+
+/**
+ * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
+ * in this group.
+ * @param {!ol.Collection.<ol.layer.Base>} layers Collection of
+ * {@link ol.layer.Base layers} that are part of this group.
+ * @observable
+ * @api stable
+ */
+ol.layer.Group.prototype.setLayers = function(layers) {
+ this.set(ol.layer.GroupProperty.LAYERS, layers);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.layer.Group.prototype.getLayersArray = function(opt_array) {
+ var array = opt_array !== undefined ? opt_array : [];
+ this.getLayers().forEach(function(layer) {
+ layer.getLayersArray(array);
+ });
+ return array;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) {
+ var states = opt_states !== undefined ? opt_states : [];
+
+ var pos = states.length;
+
+ this.getLayers().forEach(function(layer) {
+ layer.getLayerStatesArray(states);
+ });
+
+ var ownLayerState = this.getLayerState();
+ var i, ii, layerState;
+ for (i = pos, ii = states.length; i < ii; i++) {
+ layerState = states[i];
+ layerState.opacity *= ownLayerState.opacity;
+ layerState.visible = layerState.visible && ownLayerState.visible;
+ layerState.maxResolution = Math.min(
+ layerState.maxResolution, ownLayerState.maxResolution);
+ layerState.minResolution = Math.max(
+ layerState.minResolution, ownLayerState.minResolution);
+ if (ownLayerState.extent !== undefined) {
+ if (layerState.extent !== undefined) {
+ layerState.extent = ol.extent.getIntersection(
+ layerState.extent, ownLayerState.extent);
+ } else {
+ layerState.extent = ownLayerState.extent;
+ }
+ }
+ }
+
+ return states;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.layer.Group.prototype.getSourceState = function() {
+ return ol.source.State.READY;
+};
+
+goog.provide('ol.proj.EPSG3857');
+
+goog.require('goog.asserts');
+goog.require('ol.math');
+goog.require('ol.proj');
+goog.require('ol.proj.Projection');
+goog.require('ol.proj.Units');
+
+
+/**
+ * @classdesc
+ * Projection object for web/spherical Mercator (EPSG:3857).
+ *
+ * @constructor
+ * @extends {ol.proj.Projection}
+ * @param {string} code Code.
+ * @private
+ */
+ol.proj.EPSG3857_ = function(code) {
+ ol.proj.Projection.call(this, {
+ code: code,
+ units: ol.proj.Units.METERS,
+ extent: ol.proj.EPSG3857.EXTENT,
+ global: true,
+ worldExtent: ol.proj.EPSG3857.WORLD_EXTENT
+ });
+};
+ol.inherits(ol.proj.EPSG3857_, ol.proj.Projection);
+
+
+/**
+ * @inheritDoc
+ */
+ol.proj.EPSG3857_.prototype.getPointResolution = function(resolution, point) {
+ return resolution / ol.math.cosh(point[1] / ol.proj.EPSG3857.RADIUS);
+};
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.proj.EPSG3857.RADIUS = 6378137;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.proj.EPSG3857.HALF_SIZE = Math.PI * ol.proj.EPSG3857.RADIUS;
+
+
+/**
+ * @const
+ * @type {ol.Extent}
+ */
+ol.proj.EPSG3857.EXTENT = [
+ -ol.proj.EPSG3857.HALF_SIZE, -ol.proj.EPSG3857.HALF_SIZE,
+ ol.proj.EPSG3857.HALF_SIZE, ol.proj.EPSG3857.HALF_SIZE
+];
+
+
+/**
+ * @const
+ * @type {ol.Extent}
+ */
+ol.proj.EPSG3857.WORLD_EXTENT = [-180, -85, 180, 85];
+
+
+/**
+ * Lists several projection codes with the same meaning as EPSG:3857.
+ *
+ * @type {Array.<string>}
+ */
+ol.proj.EPSG3857.CODES = [
+ 'EPSG:3857',
+ 'EPSG:102100',
+ 'EPSG:102113',
+ 'EPSG:900913',
+ 'urn:ogc:def:crs:EPSG:6.18:3:3857',
+ 'urn:ogc:def:crs:EPSG::3857',
+ 'http://www.opengis.net/gml/srs/epsg.xml#3857'
+];
+
+
+/**
+ * Projections equal to EPSG:3857.
+ *
+ * @const
+ * @type {Array.<ol.proj.Projection>}
+ */
+ol.proj.EPSG3857.PROJECTIONS = ol.proj.EPSG3857.CODES.map(function(code) {
+ return new ol.proj.EPSG3857_(code);
+});
+
+
+/**
+ * Transformation from EPSG:4326 to EPSG:3857.
+ *
+ * @param {Array.<number>} input Input array of coordinate values.
+ * @param {Array.<number>=} opt_output Output array of coordinate values.
+ * @param {number=} opt_dimension Dimension (default is `2`).
+ * @return {Array.<number>} Output array of coordinate values.
+ */
+ol.proj.EPSG3857.fromEPSG4326 = function(input, opt_output, opt_dimension) {
+ var length = input.length,
+ dimension = opt_dimension > 1 ? opt_dimension : 2,
+ output = opt_output;
+ if (output === undefined) {
+ if (dimension > 2) {
+ // preserve values beyond second dimension
+ output = input.slice();
+ } else {
+ output = new Array(length);
+ }
+ }
+ goog.asserts.assert(output.length % dimension === 0,
+ 'modulus of output.length with dimension should be 0');
+ for (var i = 0; i < length; i += dimension) {
+ output[i] = ol.proj.EPSG3857.RADIUS * Math.PI * input[i] / 180;
+ output[i + 1] = ol.proj.EPSG3857.RADIUS *
+ Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360));
+ }
+ return output;
+};
+
+
+/**
+ * Transformation from EPSG:3857 to EPSG:4326.
+ *
+ * @param {Array.<number>} input Input array of coordinate values.
+ * @param {Array.<number>=} opt_output Output array of coordinate values.
+ * @param {number=} opt_dimension Dimension (default is `2`).
+ * @return {Array.<number>} Output array of coordinate values.
+ */
+ol.proj.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) {
+ var length = input.length,
+ dimension = opt_dimension > 1 ? opt_dimension : 2,
+ output = opt_output;
+ if (output === undefined) {
+ if (dimension > 2) {
+ // preserve values beyond second dimension
+ output = input.slice();
+ } else {
+ output = new Array(length);
+ }
+ }
+ goog.asserts.assert(output.length % dimension === 0,
+ 'modulus of output.length with dimension should be 0');
+ for (var i = 0; i < length; i += dimension) {
+ output[i] = 180 * input[i] / (ol.proj.EPSG3857.RADIUS * Math.PI);
+ output[i + 1] = 360 * Math.atan(
+ Math.exp(input[i + 1] / ol.proj.EPSG3857.RADIUS)) / Math.PI - 90;
+ }
+ return output;
+};
+
+goog.provide('ol.sphere.WGS84');
+
+goog.require('ol.Sphere');
+
+
+/**
+ * A sphere with radius equal to the semi-major axis of the WGS84 ellipsoid.
+ * @const
+ * @type {ol.Sphere}
+ */
+ol.sphere.WGS84 = new ol.Sphere(6378137);
+
+goog.provide('ol.proj.EPSG4326');
+
+goog.require('ol.proj');
+goog.require('ol.proj.Projection');
+goog.require('ol.proj.Units');
+goog.require('ol.sphere.WGS84');
+
+
+/**
+ * @classdesc
+ * Projection object for WGS84 geographic coordinates (EPSG:4326).
+ *
+ * Note that OpenLayers does not strictly comply with the EPSG definition.
+ * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x).
+ * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates.
+ *
+ * @constructor
+ * @extends {ol.proj.Projection}
+ * @param {string} code Code.
+ * @param {string=} opt_axisOrientation Axis orientation.
+ * @private
+ */
+ol.proj.EPSG4326_ = function(code, opt_axisOrientation) {
+ ol.proj.Projection.call(this, {
+ code: code,
+ units: ol.proj.Units.DEGREES,
+ extent: ol.proj.EPSG4326.EXTENT,
+ axisOrientation: opt_axisOrientation,
+ global: true,
+ metersPerUnit: ol.proj.EPSG4326.METERS_PER_UNIT,
+ worldExtent: ol.proj.EPSG4326.EXTENT
+ });
+};
+ol.inherits(ol.proj.EPSG4326_, ol.proj.Projection);
+
+
+/**
+ * @inheritDoc
+ */
+ol.proj.EPSG4326_.prototype.getPointResolution = function(resolution, point) {
+ return resolution;
+};
+
+
+/**
+ * Extent of the EPSG:4326 projection which is the whole world.
+ *
+ * @const
+ * @type {ol.Extent}
+ */
+ol.proj.EPSG4326.EXTENT = [-180, -90, 180, 90];
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.proj.EPSG4326.METERS_PER_UNIT = Math.PI * ol.sphere.WGS84.radius / 180;
+
+
+/**
+ * Projections equal to EPSG:4326.
+ *
+ * @const
+ * @type {Array.<ol.proj.Projection>}
+ */
+ol.proj.EPSG4326.PROJECTIONS = [
+ new ol.proj.EPSG4326_('CRS:84'),
+ new ol.proj.EPSG4326_('EPSG:4326', 'neu'),
+ new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG::4326', 'neu'),
+ new ol.proj.EPSG4326_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),
+ new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:1.3:CRS84'),
+ new ol.proj.EPSG4326_('urn:ogc:def:crs:OGC:2:84'),
+ new ol.proj.EPSG4326_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),
+ new ol.proj.EPSG4326_('urn:x-ogc:def:crs:EPSG:4326', 'neu')
+];
+
+goog.provide('ol.proj.common');
+
+goog.require('ol.proj');
+goog.require('ol.proj.EPSG3857');
+goog.require('ol.proj.EPSG4326');
+
+
+/**
+ * FIXME empty description for jsdoc
+ * @api
+ */
+ol.proj.common.add = function() {
+ // Add transformations that don't alter coordinates to convert within set of
+ // projections with equal meaning.
+ ol.proj.addEquivalentProjections(ol.proj.EPSG3857.PROJECTIONS);
+ ol.proj.addEquivalentProjections(ol.proj.EPSG4326.PROJECTIONS);
+ // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like
+ // coordinates and back.
+ ol.proj.addEquivalentTransforms(
+ ol.proj.EPSG4326.PROJECTIONS,
+ ol.proj.EPSG3857.PROJECTIONS,
+ ol.proj.EPSG3857.fromEPSG4326,
+ ol.proj.EPSG3857.toEPSG4326);
+};
+
+goog.provide('ol.layer.Image');
+
+goog.require('ol.layer.Layer');
+
+
+/**
+ * @classdesc
+ * Server-rendered images that are available for arbitrary extents and
+ * resolutions.
+ * Note that any property set in the options is set as a {@link ol.Object}
+ * property on the layer object; for example, setting `title: 'My Title'` in the
+ * options means that `title` is observable, and has get/set accessors.
+ *
+ * @constructor
+ * @extends {ol.layer.Layer}
+ * @fires ol.render.Event
+ * @param {olx.layer.ImageOptions=} opt_options Layer options.
+ * @api stable
+ */
+ol.layer.Image = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+ ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (options));
+};
+ol.inherits(ol.layer.Image, ol.layer.Layer);
+
+
+/**
+ * Return the associated {@link ol.source.Image source} of the image layer.
+ * @function
+ * @return {ol.source.Image} Source.
+ * @api stable
+ */
+ol.layer.Image.prototype.getSource;
+
+goog.provide('ol.layer.Tile');
+
+goog.require('ol');
+goog.require('ol.layer.Layer');
+goog.require('ol.object');
+
+
+/**
+ * @enum {string}
+ */
+ol.layer.TileProperty = {
+ PRELOAD: 'preload',
+ USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'
+};
+
+
+/**
+ * @classdesc
+ * For layer sources that provide pre-rendered, tiled images in grids that are
+ * organized by zoom levels for specific resolutions.
+ * Note that any property set in the options is set as a {@link ol.Object}
+ * property on the layer object; for example, setting `title: 'My Title'` in the
+ * options means that `title` is observable, and has get/set accessors.
+ *
+ * @constructor
+ * @extends {ol.layer.Layer}
+ * @fires ol.render.Event
+ * @param {olx.layer.TileOptions=} opt_options Tile layer options.
+ * @api stable
+ */
+ol.layer.Tile = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+
+ var baseOptions = ol.object.assign({}, options);
+
+ delete baseOptions.preload;
+ delete baseOptions.useInterimTilesOnError;
+ ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
+
+ this.setPreload(options.preload !== undefined ? options.preload : 0);
+ this.setUseInterimTilesOnError(options.useInterimTilesOnError !== undefined ?
+ options.useInterimTilesOnError : true);
+};
+ol.inherits(ol.layer.Tile, ol.layer.Layer);
+
+
+/**
+ * Return the level as number to which we will preload tiles up to.
+ * @return {number} The level to preload tiles up to.
+ * @observable
+ * @api
+ */
+ol.layer.Tile.prototype.getPreload = function() {
+ return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD));
+};
+
+
+/**
+ * Return the associated {@link ol.source.Tile tilesource} of the layer.
+ * @function
+ * @return {ol.source.Tile} Source.
+ * @api stable
+ */
+ol.layer.Tile.prototype.getSource;
+
+
+/**
+ * Set the level as number to which we will preload tiles up to.
+ * @param {number} preload The level to preload tiles up to.
+ * @observable
+ * @api
+ */
+ol.layer.Tile.prototype.setPreload = function(preload) {
+ this.set(ol.layer.TileProperty.PRELOAD, preload);
+};
+
+
+/**
+ * Whether we use interim tiles on error.
+ * @return {boolean} Use interim tiles on error.
+ * @observable
+ * @api
+ */
+ol.layer.Tile.prototype.getUseInterimTilesOnError = function() {
+ return /** @type {boolean} */ (
+ this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR));
+};
+
+
+/**
+ * Set whether we use interim tiles on error.
+ * @param {boolean} useInterimTilesOnError Use interim tiles on error.
+ * @observable
+ * @api
+ */
+ol.layer.Tile.prototype.setUseInterimTilesOnError = function(useInterimTilesOnError) {
+ this.set(
+ ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
+};
+
+goog.provide('ol.render.canvas');
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.canvas.defaultFont = '10px sans-serif';
+
+
+/**
+ * @const
+ * @type {ol.Color}
+ */
+ol.render.canvas.defaultFillStyle = [0, 0, 0, 1];
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.canvas.defaultLineCap = 'round';
+
+
+/**
+ * @const
+ * @type {Array.<number>}
+ */
+ol.render.canvas.defaultLineDash = [];
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.canvas.defaultLineJoin = 'round';
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.render.canvas.defaultMiterLimit = 10;
+
+
+/**
+ * @const
+ * @type {ol.Color}
+ */
+ol.render.canvas.defaultStrokeStyle = [0, 0, 0, 1];
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.canvas.defaultTextAlign = 'center';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.canvas.defaultTextBaseline = 'middle';
+
+
+/**
+ * @const
+ * @type {number}
+ */
+ol.render.canvas.defaultLineWidth = 1;
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {number} rotation Rotation.
+ * @param {number} offsetX X offset.
+ * @param {number} offsetY Y offset.
+ */
+ol.render.canvas.rotateAtOffset = function(context, rotation, offsetX, offsetY) {
+ if (rotation !== 0) {
+ context.translate(offsetX, offsetY);
+ context.rotate(rotation);
+ context.translate(-offsetX, -offsetY);
+ }
+};
+
+goog.provide('ol.style.Fill');
+
+goog.require('ol.color');
+
+
+/**
+ * @classdesc
+ * Set fill style for vector features.
+ *
+ * @constructor
+ * @param {olx.style.FillOptions=} opt_options Options.
+ * @api
+ */
+ol.style.Fill = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {ol.Color|ol.ColorLike}
+ */
+ this.color_ = options.color !== undefined ? options.color : null;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Get the fill color.
+ * @return {ol.Color|ol.ColorLike} Color.
+ * @api
+ */
+ol.style.Fill.prototype.getColor = function() {
+ return this.color_;
+};
+
+
+/**
+ * Set the color.
+ *
+ * @param {ol.Color|ol.ColorLike} color Color.
+ * @api
+ */
+ol.style.Fill.prototype.setColor = function(color) {
+ this.color_ = color;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * @return {string} The checksum.
+ */
+ol.style.Fill.prototype.getChecksum = function() {
+ if (this.checksum_ === undefined) {
+ if (
+ this.color_ instanceof CanvasPattern ||
+ this.color_ instanceof CanvasGradient
+ ) {
+ this.checksum_ = goog.getUid(this.color_).toString();
+ } else {
+ this.checksum_ = 'f' + (this.color_ ?
+ ol.color.asString(this.color_) : '-');
+ }
+ }
+
+ return this.checksum_;
+};
+
+// Copyright 2008 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Namespace with crypto related helper functions.
+ */
+
+goog.provide('goog.crypt');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+
+
+/**
+ * Turns a string into an array of bytes; a "byte" being a JS number in the
+ * range 0-255.
+ * @param {string} str String value to arrify.
+ * @return {!Array<number>} Array of numbers corresponding to the
+ * UCS character codes of each character in str.
+ */
+goog.crypt.stringToByteArray = function(str) {
+ var output = [], p = 0;
+ for (var i = 0; i < str.length; i++) {
+ var c = str.charCodeAt(i);
+ while (c > 0xff) {
+ output[p++] = c & 0xff;
+ c >>= 8;
+ }
+ output[p++] = c;
+ }
+ return output;
+};
+
+
+/**
+ * Turns an array of numbers into the string given by the concatenation of the
+ * characters to which the numbers correspond.
+ * @param {!Uint8Array|!Array<number>} bytes Array of numbers representing
+ * characters.
+ * @return {string} Stringification of the array.
+ */
+goog.crypt.byteArrayToString = function(bytes) {
+ var CHUNK_SIZE = 8192;
+
+ // Special-case the simple case for speed's sake.
+ if (bytes.length <= CHUNK_SIZE) {
+ return String.fromCharCode.apply(null, bytes);
+ }
+
+ // The remaining logic splits conversion by chunks since
+ // Function#apply() has a maximum parameter count.
+ // See discussion: http://goo.gl/LrWmZ9
+
+ var str = '';
+ for (var i = 0; i < bytes.length; i += CHUNK_SIZE) {
+ var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE);
+ str += String.fromCharCode.apply(null, chunk);
+ }
+ return str;
+};
+
+
+/**
+ * Turns an array of numbers into the hex string given by the concatenation of
+ * the hex values to which the numbers correspond.
+ * @param {Uint8Array|Array<number>} array Array of numbers representing
+ * characters.
+ * @return {string} Hex string.
+ */
+goog.crypt.byteArrayToHex = function(array) {
+ return goog.array
+ .map(
+ array,
+ function(numByte) {
+ var hexByte = numByte.toString(16);
+ return hexByte.length > 1 ? hexByte : '0' + hexByte;
+ })
+ .join('');
+};
+
+
+/**
+ * Converts a hex string into an integer array.
+ * @param {string} hexString Hex string of 16-bit integers (two characters
+ * per integer).
+ * @return {!Array<number>} Array of {0,255} integers for the given string.
+ */
+goog.crypt.hexToByteArray = function(hexString) {
+ goog.asserts.assert(
+ hexString.length % 2 == 0, 'Key string length must be multiple of 2');
+ var arr = [];
+ for (var i = 0; i < hexString.length; i += 2) {
+ arr.push(parseInt(hexString.substring(i, i + 2), 16));
+ }
+ return arr;
+};
+
+
+/**
+ * Converts a JS string to a UTF-8 "byte" array.
+ * @param {string} str 16-bit unicode string.
+ * @return {!Array<number>} UTF-8 byte array.
+ */
+goog.crypt.stringToUtf8ByteArray = function(str) {
+ // TODO(user): Use native implementations if/when available
+ var out = [], p = 0;
+ for (var i = 0; i < str.length; i++) {
+ var c = str.charCodeAt(i);
+ if (c < 128) {
+ out[p++] = c;
+ } else if (c < 2048) {
+ out[p++] = (c >> 6) | 192;
+ out[p++] = (c & 63) | 128;
+ } else if (
+ ((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
+ ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
+ // Surrogate Pair
+ c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
+ out[p++] = (c >> 18) | 240;
+ out[p++] = ((c >> 12) & 63) | 128;
+ out[p++] = ((c >> 6) & 63) | 128;
+ out[p++] = (c & 63) | 128;
+ } else {
+ out[p++] = (c >> 12) | 224;
+ out[p++] = ((c >> 6) & 63) | 128;
+ out[p++] = (c & 63) | 128;
+ }
+ }
+ return out;
+};
+
+
+/**
+ * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode.
+ * @param {Uint8Array|Array<number>} bytes UTF-8 byte array.
+ * @return {string} 16-bit Unicode string.
+ */
+goog.crypt.utf8ByteArrayToString = function(bytes) {
+ // TODO(user): Use native implementations if/when available
+ var out = [], pos = 0, c = 0;
+ while (pos < bytes.length) {
+ var c1 = bytes[pos++];
+ if (c1 < 128) {
+ out[c++] = String.fromCharCode(c1);
+ } else if (c1 > 191 && c1 < 224) {
+ var c2 = bytes[pos++];
+ out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
+ } else if (c1 > 239 && c1 < 365) {
+ // Surrogate Pair
+ var c2 = bytes[pos++];
+ var c3 = bytes[pos++];
+ var c4 = bytes[pos++];
+ var u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) -
+ 0x10000;
+ out[c++] = String.fromCharCode(0xD800 + (u >> 10));
+ out[c++] = String.fromCharCode(0xDC00 + (u & 1023));
+ } else {
+ var c2 = bytes[pos++];
+ var c3 = bytes[pos++];
+ out[c++] =
+ String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
+ }
+ }
+ return out.join('');
+};
+
+
+/**
+ * XOR two byte arrays.
+ * @param {!Uint8Array|!Int8Array|!Array<number>} bytes1 Byte array 1.
+ * @param {!Uint8Array|!Int8Array|!Array<number>} bytes2 Byte array 2.
+ * @return {!Array<number>} Resulting XOR of the two byte arrays.
+ */
+goog.crypt.xorByteArray = function(bytes1, bytes2) {
+ goog.asserts.assert(
+ bytes1.length == bytes2.length, 'XOR array lengths must match');
+
+ var result = [];
+ for (var i = 0; i < bytes1.length; i++) {
+ result.push(bytes1[i] ^ bytes2[i]);
+ }
+ return result;
+};
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Abstract cryptographic hash interface.
+ *
+ * See goog.crypt.Sha1 and goog.crypt.Md5 for sample implementations.
+ *
+ */
+
+goog.provide('goog.crypt.Hash');
+
+
+
+/**
+ * Create a cryptographic hash instance.
+ *
+ * @constructor
+ * @struct
+ */
+goog.crypt.Hash = function() {
+ /**
+ * The block size for the hasher.
+ * @type {number}
+ */
+ this.blockSize = -1;
+};
+
+
+/**
+ * Resets the internal accumulator.
+ */
+goog.crypt.Hash.prototype.reset = goog.abstractMethod;
+
+
+/**
+ * Adds a byte array (array with values in [0-255] range) or a string (might
+ * only contain 8-bit, i.e., Latin1 characters) to the internal accumulator.
+ *
+ * Many hash functions operate on blocks of data and implement optimizations
+ * when a full chunk of data is readily available. Hence it is often preferable
+ * to provide large chunks of data (a kilobyte or more) than to repeatedly
+ * call the update method with few tens of bytes. If this is not possible, or
+ * not feasible, it might be good to provide data in multiplies of hash block
+ * size (often 64 bytes). Please see the implementation and performance tests
+ * of your favourite hash.
+ *
+ * @param {Array<number>|Uint8Array|string} bytes Data used for the update.
+ * @param {number=} opt_length Number of bytes to use.
+ */
+goog.crypt.Hash.prototype.update = goog.abstractMethod;
+
+
+/**
+ * @return {!Array<number>} The finalized hash computed
+ * from the internal accumulator.
+ */
+goog.crypt.Hash.prototype.digest = goog.abstractMethod;
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview MD5 cryptographic hash.
+ * Implementation of http://tools.ietf.org/html/rfc1321 with common
+ * optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5).
+ *
+ * Usage:
+ * var md5 = new goog.crypt.Md5();
+ * md5.update(bytes);
+ * var hash = md5.digest();
+ *
+ * Performance:
+ * Chrome 23 ~680 Mbit/s
+ * Chrome 13 (in a VM) ~250 Mbit/s
+ * Firefox 6.0 (in a VM) ~100 Mbit/s
+ * IE9 (in a VM) ~27 Mbit/s
+ * Firefox 3.6 ~15 Mbit/s
+ * IE8 (in a VM) ~13 Mbit/s
+ *
+ */
+
+goog.provide('goog.crypt.Md5');
+
+goog.require('goog.crypt.Hash');
+
+
+
+/**
+ * MD5 cryptographic hash constructor.
+ * @constructor
+ * @extends {goog.crypt.Hash}
+ * @final
+ * @struct
+ */
+goog.crypt.Md5 = function() {
+ goog.crypt.Md5.base(this, 'constructor');
+
+ this.blockSize = 512 / 8;
+
+ /**
+ * Holds the current values of accumulated A-D variables (MD buffer).
+ * @type {!Array<number>}
+ * @private
+ */
+ this.chain_ = new Array(4);
+
+ /**
+ * A buffer holding the data until the whole block can be processed.
+ * @type {!Array<number>}
+ * @private
+ */
+ this.block_ = new Array(this.blockSize);
+
+ /**
+ * The length of yet-unprocessed data as collected in the block.
+ * @type {number}
+ * @private
+ */
+ this.blockLength_ = 0;
+
+ /**
+ * The total length of the message so far.
+ * @type {number}
+ * @private
+ */
+ this.totalLength_ = 0;
+
+ this.reset();
+};
+goog.inherits(goog.crypt.Md5, goog.crypt.Hash);
+
+
+/**
+ * Integer rotation constants used by the abbreviated implementation.
+ * They are hardcoded in the unrolled implementation, so it is left
+ * here commented out.
+ * @type {Array<number>}
+ * @private
+ *
+goog.crypt.Md5.S_ = [
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+];
+ */
+
+/**
+ * Sine function constants used by the abbreviated implementation.
+ * They are hardcoded in the unrolled implementation, so it is left
+ * here commented out.
+ * @type {Array<number>}
+ * @private
+ *
+goog.crypt.Md5.T_ = [
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+];
+ */
+
+
+/** @override */
+goog.crypt.Md5.prototype.reset = function() {
+ this.chain_[0] = 0x67452301;
+ this.chain_[1] = 0xefcdab89;
+ this.chain_[2] = 0x98badcfe;
+ this.chain_[3] = 0x10325476;
+
+ this.blockLength_ = 0;
+ this.totalLength_ = 0;
+};
+
+
+/**
+ * Internal compress helper function. It takes a block of data (64 bytes)
+ * and updates the accumulator.
+ * @param {Array<number>|Uint8Array|string} buf The block to compress.
+ * @param {number=} opt_offset Offset of the block in the buffer.
+ * @private
+ */
+goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) {
+ if (!opt_offset) {
+ opt_offset = 0;
+ }
+
+ // We allocate the array every time, but it's cheap in practice.
+ var X = new Array(16);
+
+ // Get 16 little endian words. It is not worth unrolling this for Chrome 11.
+ if (goog.isString(buf)) {
+ for (var i = 0; i < 16; ++i) {
+ X[i] = (buf.charCodeAt(opt_offset++)) |
+ (buf.charCodeAt(opt_offset++) << 8) |
+ (buf.charCodeAt(opt_offset++) << 16) |
+ (buf.charCodeAt(opt_offset++) << 24);
+ }
+ } else {
+ for (var i = 0; i < 16; ++i) {
+ X[i] = (buf[opt_offset++]) | (buf[opt_offset++] << 8) |
+ (buf[opt_offset++] << 16) | (buf[opt_offset++] << 24);
+ }
+ }
+
+ var A = this.chain_[0];
+ var B = this.chain_[1];
+ var C = this.chain_[2];
+ var D = this.chain_[3];
+ var sum = 0;
+
+ /*
+ * This is an abbreviated implementation, it is left here commented out for
+ * reference purposes. See below for an unrolled version in use.
+ *
+ var f, n, tmp;
+ for (var i = 0; i < 64; ++i) {
+
+ if (i < 16) {
+ f = (D ^ (B & (C ^ D)));
+ n = i;
+ } else if (i < 32) {
+ f = (C ^ (D & (B ^ C)));
+ n = (5 * i + 1) % 16;
+ } else if (i < 48) {
+ f = (B ^ C ^ D);
+ n = (3 * i + 5) % 16;
+ } else {
+ f = (C ^ (B | (~D)));
+ n = (7 * i) % 16;
+ }
+
+ tmp = D;
+ D = C;
+ C = B;
+ sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff;
+ B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) |
+ (sum >>> (32 - goog.crypt.Md5.S_[i]));
+ A = tmp;
+ }
+ */
+
+ /*
+ * This is an unrolled MD5 implementation, which gives ~30% speedup compared
+ * to the abbreviated implementation above, as measured on Chrome 11. It is
+ * important to keep 32-bit croppings to minimum and inline the integer
+ * rotation.
+ */
+ sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff;
+ A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+ sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff;
+ D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+ sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff;
+ C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+ sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff;
+ B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+ sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff;
+ A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+ sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff;
+ D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+ sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff;
+ C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+ sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff;
+ B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+ sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff;
+ A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+ sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff;
+ D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+ sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff;
+ C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+ sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff;
+ B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+ sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff;
+ A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+ sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff;
+ D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+ sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff;
+ C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+ sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff;
+ B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+ sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff;
+ A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+ sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff;
+ D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+ sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff;
+ C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+ sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff;
+ B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+ sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff;
+ A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+ sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff;
+ D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+ sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff;
+ C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+ sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff;
+ B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+ sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff;
+ A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+ sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff;
+ D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+ sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff;
+ C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+ sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff;
+ B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+ sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff;
+ A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+ sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff;
+ D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+ sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff;
+ C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+ sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff;
+ B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+ sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff;
+ A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+ sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff;
+ D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+ sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff;
+ C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+ sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff;
+ B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+ sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff;
+ A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+ sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff;
+ D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+ sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff;
+ C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+ sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff;
+ B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+ sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff;
+ A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+ sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff;
+ D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+ sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff;
+ C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+ sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff;
+ B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+ sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff;
+ A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+ sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff;
+ D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+ sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff;
+ C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+ sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff;
+ B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+ sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff;
+ A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+ sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff;
+ D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+ sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff;
+ C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+ sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff;
+ B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+ sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff;
+ A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+ sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff;
+ D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+ sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff;
+ C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+ sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff;
+ B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+ sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff;
+ A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+ sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff;
+ D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+ sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff;
+ C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+ sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff;
+ B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+ sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff;
+ A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+ sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff;
+ D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+ sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff;
+ C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+ sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff;
+ B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+
+ this.chain_[0] = (this.chain_[0] + A) & 0xffffffff;
+ this.chain_[1] = (this.chain_[1] + B) & 0xffffffff;
+ this.chain_[2] = (this.chain_[2] + C) & 0xffffffff;
+ this.chain_[3] = (this.chain_[3] + D) & 0xffffffff;
+};
+
+
+/** @override */
+goog.crypt.Md5.prototype.update = function(bytes, opt_length) {
+ if (!goog.isDef(opt_length)) {
+ opt_length = bytes.length;
+ }
+ var lengthMinusBlock = opt_length - this.blockSize;
+
+ // Copy some object properties to local variables in order to save on access
+ // time from inside the loop (~10% speedup was observed on Chrome 11).
+ var block = this.block_;
+ var blockLength = this.blockLength_;
+ var i = 0;
+
+ // The outer while loop should execute at most twice.
+ while (i < opt_length) {
+ // When we have no data in the block to top up, we can directly process the
+ // input buffer (assuming it contains sufficient data). This gives ~30%
+ // speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that
+ // the data is provided in large chunks (or in multiples of 64 bytes).
+ if (blockLength == 0) {
+ while (i <= lengthMinusBlock) {
+ this.compress_(bytes, i);
+ i += this.blockSize;
+ }
+ }
+
+ if (goog.isString(bytes)) {
+ while (i < opt_length) {
+ block[blockLength++] = bytes.charCodeAt(i++);
+ if (blockLength == this.blockSize) {
+ this.compress_(block);
+ blockLength = 0;
+ // Jump to the outer loop so we use the full-block optimization.
+ break;
+ }
+ }
+ } else {
+ while (i < opt_length) {
+ block[blockLength++] = bytes[i++];
+ if (blockLength == this.blockSize) {
+ this.compress_(block);
+ blockLength = 0;
+ // Jump to the outer loop so we use the full-block optimization.
+ break;
+ }
+ }
+ }
+ }
+
+ this.blockLength_ = blockLength;
+ this.totalLength_ += opt_length;
+};
+
+
+/** @override */
+goog.crypt.Md5.prototype.digest = function() {
+ // This must accommodate at least 1 padding byte (0x80), 8 bytes of
+ // total bitlength, and must end at a 64-byte boundary.
+ var pad = new Array(
+ (this.blockLength_ < 56 ? this.blockSize : this.blockSize * 2) -
+ this.blockLength_);
+
+ // Add padding: 0x80 0x00*
+ pad[0] = 0x80;
+ for (var i = 1; i < pad.length - 8; ++i) {
+ pad[i] = 0;
+ }
+ // Add the total number of bits, little endian 64-bit integer.
+ var totalBits = this.totalLength_ * 8;
+ for (var i = pad.length - 8; i < pad.length; ++i) {
+ pad[i] = totalBits & 0xff;
+ totalBits /= 0x100; // Don't use bit-shifting here!
+ }
+ this.update(pad);
+
+ var digest = new Array(16);
+ var n = 0;
+ for (var i = 0; i < 4; ++i) {
+ for (var j = 0; j < 32; j += 8) {
+ digest[n++] = (this.chain_[i] >>> j) & 0xff;
+ }
+ }
+ return digest;
+};
+
+goog.provide('ol.style.Stroke');
+
+goog.require('goog.crypt');
+goog.require('goog.crypt.Md5');
+goog.require('ol.color');
+
+
+/**
+ * @classdesc
+ * Set stroke style for vector features.
+ * Note that the defaults given are the Canvas defaults, which will be used if
+ * option is not defined. The `get` functions return whatever was entered in
+ * the options; they will not return the default.
+ *
+ * @constructor
+ * @param {olx.style.StrokeOptions=} opt_options Options.
+ * @api
+ */
+ol.style.Stroke = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {ol.Color|string}
+ */
+ this.color_ = options.color !== undefined ? options.color : null;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.lineCap_ = options.lineCap;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.lineJoin_ = options.lineJoin;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.miterLimit_ = options.miterLimit;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.width_ = options.width;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Get the stroke color.
+ * @return {ol.Color|string} Color.
+ * @api
+ */
+ol.style.Stroke.prototype.getColor = function() {
+ return this.color_;
+};
+
+
+/**
+ * Get the line cap type for the stroke.
+ * @return {string|undefined} Line cap.
+ * @api
+ */
+ol.style.Stroke.prototype.getLineCap = function() {
+ return this.lineCap_;
+};
+
+
+/**
+ * Get the line dash style for the stroke.
+ * @return {Array.<number>} Line dash.
+ * @api
+ */
+ol.style.Stroke.prototype.getLineDash = function() {
+ return this.lineDash_;
+};
+
+
+/**
+ * Get the line join type for the stroke.
+ * @return {string|undefined} Line join.
+ * @api
+ */
+ol.style.Stroke.prototype.getLineJoin = function() {
+ return this.lineJoin_;
+};
+
+
+/**
+ * Get the miter limit for the stroke.
+ * @return {number|undefined} Miter limit.
+ * @api
+ */
+ol.style.Stroke.prototype.getMiterLimit = function() {
+ return this.miterLimit_;
+};
+
+
+/**
+ * Get the stroke width.
+ * @return {number|undefined} Width.
+ * @api
+ */
+ol.style.Stroke.prototype.getWidth = function() {
+ return this.width_;
+};
+
+
+/**
+ * Set the color.
+ *
+ * @param {ol.Color|string} color Color.
+ * @api
+ */
+ol.style.Stroke.prototype.setColor = function(color) {
+ this.color_ = color;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Set the line cap.
+ *
+ * @param {string|undefined} lineCap Line cap.
+ * @api
+ */
+ol.style.Stroke.prototype.setLineCap = function(lineCap) {
+ this.lineCap_ = lineCap;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Set the line dash.
+ *
+ * Please note that Internet Explorer 10 and lower [do not support][mdn] the
+ * `setLineDash` method on the `CanvasRenderingContext2D` and therefore this
+ * property will have no visual effect in these browsers.
+ *
+ * [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility
+ *
+ * @param {Array.<number>} lineDash Line dash.
+ * @api
+ */
+ol.style.Stroke.prototype.setLineDash = function(lineDash) {
+ this.lineDash_ = lineDash;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Set the line join.
+ *
+ * @param {string|undefined} lineJoin Line join.
+ * @api
+ */
+ol.style.Stroke.prototype.setLineJoin = function(lineJoin) {
+ this.lineJoin_ = lineJoin;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Set the miter limit.
+ *
+ * @param {number|undefined} miterLimit Miter limit.
+ * @api
+ */
+ol.style.Stroke.prototype.setMiterLimit = function(miterLimit) {
+ this.miterLimit_ = miterLimit;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * Set the width.
+ *
+ * @param {number|undefined} width Width.
+ * @api
+ */
+ol.style.Stroke.prototype.setWidth = function(width) {
+ this.width_ = width;
+ this.checksum_ = undefined;
+};
+
+
+/**
+ * @return {string} The checksum.
+ */
+ol.style.Stroke.prototype.getChecksum = function() {
+ if (this.checksum_ === undefined) {
+ var raw = 's' +
+ (this.color_ ?
+ ol.color.asString(this.color_) : '-') + ',' +
+ (this.lineCap_ !== undefined ?
+ this.lineCap_.toString() : '-') + ',' +
+ (this.lineDash_ ?
+ this.lineDash_.toString() : '-') + ',' +
+ (this.lineJoin_ !== undefined ?
+ this.lineJoin_ : '-') + ',' +
+ (this.miterLimit_ !== undefined ?
+ this.miterLimit_.toString() : '-') + ',' +
+ (this.width_ !== undefined ?
+ this.width_.toString() : '-');
+
+ var md5 = new goog.crypt.Md5();
+ md5.update(raw);
+ this.checksum_ = goog.crypt.byteArrayToString(md5.digest());
+ }
+
+ return this.checksum_;
+};
+
+goog.provide('ol.style.Circle');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.color');
+goog.require('ol.colorlike');
+goog.require('ol.dom');
+goog.require('ol.has');
+goog.require('ol.render.canvas');
+goog.require('ol.style.Fill');
+goog.require('ol.style.Image');
+goog.require('ol.style.ImageState');
+goog.require('ol.style.Stroke');
+
+
+/**
+ * @classdesc
+ * Set circle style for vector features.
+ *
+ * @constructor
+ * @param {olx.style.CircleOptions=} opt_options Options.
+ * @extends {ol.style.Image}
+ * @api
+ */
+ol.style.Circle = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {Array.<string>}
+ */
+ this.checksums_ = null;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = null;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.hitDetectionCanvas_ = null;
+
+ /**
+ * @private
+ * @type {ol.style.Fill}
+ */
+ this.fill_ = options.fill !== undefined ? options.fill : null;
+
+ /**
+ * @private
+ * @type {ol.style.Stroke}
+ */
+ this.stroke_ = options.stroke !== undefined ? options.stroke : null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.radius_ = options.radius;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.origin_ = [0, 0];
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.anchor_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.size_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.imageSize_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.hitDetectionImageSize_ = null;
+
+ this.render_(options.atlasManager);
+
+ /**
+ * @type {boolean}
+ */
+ var snapToPixel = options.snapToPixel !== undefined ?
+ options.snapToPixel : true;
+
+ ol.style.Image.call(this, {
+ opacity: 1,
+ rotateWithView: false,
+ rotation: 0,
+ scale: 1,
+ snapToPixel: snapToPixel
+ });
+
+};
+ol.inherits(ol.style.Circle, ol.style.Image);
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getAnchor = function() {
+ return this.anchor_;
+};
+
+
+/**
+ * Get the fill style for the circle.
+ * @return {ol.style.Fill} Fill style.
+ * @api
+ */
+ol.style.Circle.prototype.getFill = function() {
+ return this.fill_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getHitDetectionImage = function(pixelRatio) {
+ return this.hitDetectionCanvas_;
+};
+
+
+/**
+ * Get the image used to render the circle.
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {HTMLCanvasElement} Canvas element.
+ * @api
+ */
+ol.style.Circle.prototype.getImage = function(pixelRatio) {
+ return this.canvas_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getImageState = function() {
+ return ol.style.ImageState.LOADED;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getImageSize = function() {
+ return this.imageSize_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getHitDetectionImageSize = function() {
+ return this.hitDetectionImageSize_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getOrigin = function() {
+ return this.origin_;
+};
+
+
+/**
+ * Get the circle radius.
+ * @return {number} Radius.
+ * @api
+ */
+ol.style.Circle.prototype.getRadius = function() {
+ return this.radius_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.getSize = function() {
+ return this.size_;
+};
+
+
+/**
+ * Get the stroke style for the circle.
+ * @return {ol.style.Stroke} Stroke style.
+ * @api
+ */
+ol.style.Circle.prototype.getStroke = function() {
+ return this.stroke_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.listenImageChange = ol.nullFunction;
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.load = ol.nullFunction;
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.Circle.prototype.unlistenImageChange = ol.nullFunction;
+
+
+/**
+ * @private
+ * @param {ol.style.AtlasManager|undefined} atlasManager An atlas manager.
+ */
+ol.style.Circle.prototype.render_ = function(atlasManager) {
+ var imageSize;
+ var lineDash = null;
+ var strokeStyle;
+ var strokeWidth = 0;
+
+ if (this.stroke_) {
+ strokeStyle = ol.color.asString(this.stroke_.getColor());
+ strokeWidth = this.stroke_.getWidth();
+ if (strokeWidth === undefined) {
+ strokeWidth = ol.render.canvas.defaultLineWidth;
+ }
+ lineDash = this.stroke_.getLineDash();
+ if (!ol.has.CANVAS_LINE_DASH) {
+ lineDash = null;
+ }
+ }
+
+
+ var size = 2 * (this.radius_ + strokeWidth) + 1;
+
+ /** @type {ol.CircleRenderOptions} */
+ var renderOptions = {
+ strokeStyle: strokeStyle,
+ strokeWidth: strokeWidth,
+ size: size,
+ lineDash: lineDash
+ };
+
+ if (atlasManager === undefined) {
+ // no atlas manager is used, create a new canvas
+ var context = ol.dom.createCanvasContext2D(size, size);
+ this.canvas_ = context.canvas;
+
+ // canvas.width and height are rounded to the closest integer
+ size = this.canvas_.width;
+ imageSize = size;
+
+ // draw the circle on the canvas
+ this.draw_(renderOptions, context, 0, 0);
+
+ this.createHitDetectionCanvas_(renderOptions);
+ } else {
+ // an atlas manager is used, add the symbol to an atlas
+ size = Math.round(size);
+
+ var hasCustomHitDetectionImage = !this.fill_;
+ var renderHitDetectionCallback;
+ if (hasCustomHitDetectionImage) {
+ // render the hit-detection image into a separate atlas image
+ renderHitDetectionCallback =
+ this.drawHitDetectionCanvas_.bind(this, renderOptions);
+ }
+
+ var id = this.getChecksum();
+ var info = atlasManager.add(
+ id, size, size, this.draw_.bind(this, renderOptions),
+ renderHitDetectionCallback);
+ goog.asserts.assert(info, 'circle radius is too large');
+
+ this.canvas_ = info.image;
+ this.origin_ = [info.offsetX, info.offsetY];
+ imageSize = info.image.width;
+
+ if (hasCustomHitDetectionImage) {
+ this.hitDetectionCanvas_ = info.hitImage;
+ this.hitDetectionImageSize_ =
+ [info.hitImage.width, info.hitImage.height];
+ } else {
+ this.hitDetectionCanvas_ = this.canvas_;
+ this.hitDetectionImageSize_ = [imageSize, imageSize];
+ }
+ }
+
+ this.anchor_ = [size / 2, size / 2];
+ this.size_ = [size, size];
+ this.imageSize_ = [imageSize, imageSize];
+};
+
+
+/**
+ * @private
+ * @param {ol.CircleRenderOptions} renderOptions Render options.
+ * @param {CanvasRenderingContext2D} context The rendering context.
+ * @param {number} x The origin for the symbol (x).
+ * @param {number} y The origin for the symbol (y).
+ */
+ol.style.Circle.prototype.draw_ = function(renderOptions, context, x, y) {
+ // reset transform
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // then move to (x, y)
+ context.translate(x, y);
+
+ context.beginPath();
+ context.arc(
+ renderOptions.size / 2, renderOptions.size / 2,
+ this.radius_, 0, 2 * Math.PI, true);
+
+ if (this.fill_) {
+ context.fillStyle = ol.colorlike.asColorLike(this.fill_.getColor());
+ context.fill();
+ }
+ if (this.stroke_) {
+ context.strokeStyle = renderOptions.strokeStyle;
+ context.lineWidth = renderOptions.strokeWidth;
+ if (renderOptions.lineDash) {
+ context.setLineDash(renderOptions.lineDash);
+ }
+ context.stroke();
+ }
+ context.closePath();
+};
+
+
+/**
+ * @private
+ * @param {ol.CircleRenderOptions} renderOptions Render options.
+ */
+ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) {
+ this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size];
+ if (this.fill_) {
+ this.hitDetectionCanvas_ = this.canvas_;
+ return;
+ }
+
+ // if no fill style is set, create an extra hit-detection image with a
+ // default fill style
+ var context = ol.dom.createCanvasContext2D(renderOptions.size, renderOptions.size);
+ this.hitDetectionCanvas_ = context.canvas;
+
+ this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);
+};
+
+
+/**
+ * @private
+ * @param {ol.CircleRenderOptions} renderOptions Render options.
+ * @param {CanvasRenderingContext2D} context The context.
+ * @param {number} x The origin for the symbol (x).
+ * @param {number} y The origin for the symbol (y).
+ */
+ol.style.Circle.prototype.drawHitDetectionCanvas_ = function(renderOptions, context, x, y) {
+ // reset transform
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // then move to (x, y)
+ context.translate(x, y);
+
+ context.beginPath();
+ context.arc(
+ renderOptions.size / 2, renderOptions.size / 2,
+ this.radius_, 0, 2 * Math.PI, true);
+
+ context.fillStyle = ol.color.asString(ol.render.canvas.defaultFillStyle);
+ context.fill();
+ if (this.stroke_) {
+ context.strokeStyle = renderOptions.strokeStyle;
+ context.lineWidth = renderOptions.strokeWidth;
+ if (renderOptions.lineDash) {
+ context.setLineDash(renderOptions.lineDash);
+ }
+ context.stroke();
+ }
+ context.closePath();
+};
+
+
+/**
+ * @return {string} The checksum.
+ */
+ol.style.Circle.prototype.getChecksum = function() {
+ var strokeChecksum = this.stroke_ ?
+ this.stroke_.getChecksum() : '-';
+ var fillChecksum = this.fill_ ?
+ this.fill_.getChecksum() : '-';
+
+ var recalculate = !this.checksums_ ||
+ (strokeChecksum != this.checksums_[1] ||
+ fillChecksum != this.checksums_[2] ||
+ this.radius_ != this.checksums_[3]);
+
+ if (recalculate) {
+ var checksum = 'c' + strokeChecksum + fillChecksum +
+ (this.radius_ !== undefined ? this.radius_.toString() : '-');
+ this.checksums_ = [checksum, strokeChecksum, fillChecksum, this.radius_];
+ }
+
+ return this.checksums_[0];
+};
+
+goog.provide('ol.style.Style');
+goog.provide('ol.style.defaultGeometryFunction');
+
+goog.require('goog.asserts');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.style.Circle');
+goog.require('ol.style.Fill');
+goog.require('ol.style.Image');
+goog.require('ol.style.Stroke');
+
+
+/**
+ * @classdesc
+ * Container for vector feature rendering styles. Any changes made to the style
+ * or its children through `set*()` methods will not take effect until the
+ * feature or layer that uses the style is re-rendered.
+ *
+ * @constructor
+ * @struct
+ * @param {olx.style.StyleOptions=} opt_options Style options.
+ * @api
+ */
+ol.style.Style = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {string|ol.geom.Geometry|ol.StyleGeometryFunction}
+ */
+ this.geometry_ = null;
+
+ /**
+ * @private
+ * @type {!ol.StyleGeometryFunction}
+ */
+ this.geometryFunction_ = ol.style.defaultGeometryFunction;
+
+ if (options.geometry !== undefined) {
+ this.setGeometry(options.geometry);
+ }
+
+ /**
+ * @private
+ * @type {ol.style.Fill}
+ */
+ this.fill_ = options.fill !== undefined ? options.fill : null;
+
+ /**
+ * @private
+ * @type {ol.style.Image}
+ */
+ this.image_ = options.image !== undefined ? options.image : null;
+
+ /**
+ * @private
+ * @type {ol.style.Stroke}
+ */
+ this.stroke_ = options.stroke !== undefined ? options.stroke : null;
+
+ /**
+ * @private
+ * @type {ol.style.Text}
+ */
+ this.text_ = options.text !== undefined ? options.text : null;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.zIndex_ = options.zIndex;
+
+};
+
+
+/**
+ * Get the geometry to be rendered.
+ * @return {string|ol.geom.Geometry|ol.StyleGeometryFunction}
+ * Feature property or geometry or function that returns the geometry that will
+ * be rendered with this style.
+ * @api
+ */
+ol.style.Style.prototype.getGeometry = function() {
+ return this.geometry_;
+};
+
+
+/**
+ * Get the function used to generate a geometry for rendering.
+ * @return {!ol.StyleGeometryFunction} Function that is called with a feature
+ * and returns the geometry to render instead of the feature's geometry.
+ * @api
+ */
+ol.style.Style.prototype.getGeometryFunction = function() {
+ return this.geometryFunction_;
+};
+
+
+/**
+ * Get the fill style.
+ * @return {ol.style.Fill} Fill style.
+ * @api
+ */
+ol.style.Style.prototype.getFill = function() {
+ return this.fill_;
+};
+
+
+/**
+ * Get the image style.
+ * @return {ol.style.Image} Image style.
+ * @api
+ */
+ol.style.Style.prototype.getImage = function() {
+ return this.image_;
+};
+
+
+/**
+ * Get the stroke style.
+ * @return {ol.style.Stroke} Stroke style.
+ * @api
+ */
+ol.style.Style.prototype.getStroke = function() {
+ return this.stroke_;
+};
+
+
+/**
+ * Get the text style.
+ * @return {ol.style.Text} Text style.
+ * @api
+ */
+ol.style.Style.prototype.getText = function() {
+ return this.text_;
+};
+
+
+/**
+ * Get the z-index for the style.
+ * @return {number|undefined} ZIndex.
+ * @api
+ */
+ol.style.Style.prototype.getZIndex = function() {
+ return this.zIndex_;
+};
+
+
+/**
+ * Set a geometry that is rendered instead of the feature's geometry.
+ *
+ * @param {string|ol.geom.Geometry|ol.StyleGeometryFunction} geometry
+ * Feature property or geometry or function returning a geometry to render
+ * for this style.
+ * @api
+ */
+ol.style.Style.prototype.setGeometry = function(geometry) {
+ if (typeof geometry === 'function') {
+ this.geometryFunction_ = geometry;
+ } else if (typeof geometry === 'string') {
+ this.geometryFunction_ = function(feature) {
+ var result = feature.get(geometry);
+ if (result) {
+ goog.asserts.assertInstanceof(result, ol.geom.Geometry,
+ 'feature geometry must be an ol.geom.Geometry instance');
+ }
+ return result;
+ };
+ } else if (!geometry) {
+ this.geometryFunction_ = ol.style.defaultGeometryFunction;
+ } else if (geometry !== undefined) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Geometry,
+ 'geometry must be an ol.geom.Geometry instance');
+ this.geometryFunction_ = function() {
+ return geometry;
+ };
+ }
+ this.geometry_ = geometry;
+};
+
+
+/**
+ * Set the z-index.
+ *
+ * @param {number|undefined} zIndex ZIndex.
+ * @api
+ */
+ol.style.Style.prototype.setZIndex = function(zIndex) {
+ this.zIndex_ = zIndex;
+};
+
+
+/**
+ * Convert the provided object into a style function. Functions passed through
+ * unchanged. Arrays of ol.style.Style or single style objects wrapped in a
+ * new style function.
+ * @param {ol.StyleFunction|Array.<ol.style.Style>|ol.style.Style} obj
+ * A style function, a single style, or an array of styles.
+ * @return {ol.StyleFunction} A style function.
+ */
+ol.style.createStyleFunction = function(obj) {
+ var styleFunction;
+
+ if (typeof obj === 'function') {
+ styleFunction = obj;
+ } else {
+ /**
+ * @type {Array.<ol.style.Style>}
+ */
+ var styles;
+ if (Array.isArray(obj)) {
+ styles = obj;
+ } else {
+ goog.asserts.assertInstanceof(obj, ol.style.Style,
+ 'obj geometry must be an ol.style.Style instance');
+ styles = [obj];
+ }
+ styleFunction = function() {
+ return styles;
+ };
+ }
+ return styleFunction;
+};
+
+
+/**
+ * @type {Array.<ol.style.Style>}
+ * @private
+ */
+ol.style.defaultStyle_ = null;
+
+
+/**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {number} resolution Resolution.
+ * @return {Array.<ol.style.Style>} Style.
+ */
+ol.style.defaultStyleFunction = function(feature, resolution) {
+ // We don't use an immediately-invoked function
+ // and a closure so we don't get an error at script evaluation time in
+ // browsers that do not support Canvas. (ol.style.Circle does
+ // canvas.getContext('2d') at construction time, which will cause an.error
+ // in such browsers.)
+ if (!ol.style.defaultStyle_) {
+ var fill = new ol.style.Fill({
+ color: 'rgba(255,255,255,0.4)'
+ });
+ var stroke = new ol.style.Stroke({
+ color: '#3399CC',
+ width: 1.25
+ });
+ ol.style.defaultStyle_ = [
+ new ol.style.Style({
+ image: new ol.style.Circle({
+ fill: fill,
+ stroke: stroke,
+ radius: 5
+ }),
+ fill: fill,
+ stroke: stroke
+ })
+ ];
+ }
+ return ol.style.defaultStyle_;
+};
+
+
+/**
+ * Default styles for editing features.
+ * @return {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} Styles
+ */
+ol.style.createDefaultEditingStyles = function() {
+ /** @type {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} */
+ var styles = {};
+ var white = [255, 255, 255, 1];
+ var blue = [0, 153, 255, 1];
+ var width = 3;
+ styles[ol.geom.GeometryType.POLYGON] = [
+ new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: [255, 255, 255, 0.5]
+ })
+ })
+ ];
+ styles[ol.geom.GeometryType.MULTI_POLYGON] =
+ styles[ol.geom.GeometryType.POLYGON];
+
+ styles[ol.geom.GeometryType.LINE_STRING] = [
+ new ol.style.Style({
+ stroke: new ol.style.Stroke({
+ color: white,
+ width: width + 2
+ })
+ }),
+ new ol.style.Style({
+ stroke: new ol.style.Stroke({
+ color: blue,
+ width: width
+ })
+ })
+ ];
+ styles[ol.geom.GeometryType.MULTI_LINE_STRING] =
+ styles[ol.geom.GeometryType.LINE_STRING];
+
+ styles[ol.geom.GeometryType.CIRCLE] =
+ styles[ol.geom.GeometryType.POLYGON].concat(
+ styles[ol.geom.GeometryType.LINE_STRING]
+ );
+
+
+ styles[ol.geom.GeometryType.POINT] = [
+ new ol.style.Style({
+ image: new ol.style.Circle({
+ radius: width * 2,
+ fill: new ol.style.Fill({
+ color: blue
+ }),
+ stroke: new ol.style.Stroke({
+ color: white,
+ width: width / 2
+ })
+ }),
+ zIndex: Infinity
+ })
+ ];
+ styles[ol.geom.GeometryType.MULTI_POINT] =
+ styles[ol.geom.GeometryType.POINT];
+
+ styles[ol.geom.GeometryType.GEOMETRY_COLLECTION] =
+ styles[ol.geom.GeometryType.POLYGON].concat(
+ styles[ol.geom.GeometryType.LINE_STRING],
+ styles[ol.geom.GeometryType.POINT]
+ );
+
+ return styles;
+};
+
+
+/**
+ * Function that is called with a feature and returns its default geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry
+ * for.
+ * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render.
+ */
+ol.style.defaultGeometryFunction = function(feature) {
+ goog.asserts.assert(feature, 'feature must not be null');
+ return feature.getGeometry();
+};
+
+goog.provide('ol.layer.Vector');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.layer.Layer');
+goog.require('ol.object');
+goog.require('ol.style.Style');
+
+
+/**
+ * @enum {string}
+ */
+ol.layer.VectorProperty = {
+ RENDER_ORDER: 'renderOrder'
+};
+
+
+/**
+ * @classdesc
+ * Vector data that is rendered client-side.
+ * Note that any property set in the options is set as a {@link ol.Object}
+ * property on the layer object; for example, setting `title: 'My Title'` in the
+ * options means that `title` is observable, and has get/set accessors.
+ *
+ * @constructor
+ * @extends {ol.layer.Layer}
+ * @fires ol.render.Event
+ * @param {olx.layer.VectorOptions=} opt_options Options.
+ * @api stable
+ */
+ol.layer.Vector = function(opt_options) {
+
+ var options = opt_options ?
+ opt_options : /** @type {olx.layer.VectorOptions} */ ({});
+
+ goog.asserts.assert(
+ options.renderOrder === undefined || !options.renderOrder ||
+ typeof options.renderOrder === 'function',
+ 'renderOrder must be a comparator function');
+
+ var baseOptions = ol.object.assign({}, options);
+
+ delete baseOptions.style;
+ delete baseOptions.renderBuffer;
+ delete baseOptions.updateWhileAnimating;
+ delete baseOptions.updateWhileInteracting;
+ ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.renderBuffer_ = options.renderBuffer !== undefined ?
+ options.renderBuffer : 100;
+
+ /**
+ * User provided style.
+ * @type {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
+ * @private
+ */
+ this.style_ = null;
+
+ /**
+ * Style function for use within the library.
+ * @type {ol.StyleFunction|undefined}
+ * @private
+ */
+ this.styleFunction_ = undefined;
+
+ this.setStyle(options.style);
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.updateWhileAnimating_ = options.updateWhileAnimating !== undefined ?
+ options.updateWhileAnimating : false;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.updateWhileInteracting_ = options.updateWhileInteracting !== undefined ?
+ options.updateWhileInteracting : false;
+
+};
+ol.inherits(ol.layer.Vector, ol.layer.Layer);
+
+
+/**
+ * @return {number|undefined} Render buffer.
+ */
+ol.layer.Vector.prototype.getRenderBuffer = function() {
+ return this.renderBuffer_;
+};
+
+
+/**
+ * @return {function(ol.Feature, ol.Feature): number|null|undefined} Render
+ * order.
+ */
+ol.layer.Vector.prototype.getRenderOrder = function() {
+ return /** @type {function(ol.Feature, ol.Feature):number|null|undefined} */ (
+ this.get(ol.layer.VectorProperty.RENDER_ORDER));
+};
+
+
+/**
+ * Return the associated {@link ol.source.Vector vectorsource} of the layer.
+ * @function
+ * @return {ol.source.Vector} Source.
+ * @api stable
+ */
+ol.layer.Vector.prototype.getSource;
+
+
+/**
+ * Get the style for features. This returns whatever was passed to the `style`
+ * option at construction or to the `setStyle` method.
+ * @return {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
+ * Layer style.
+ * @api stable
+ */
+ol.layer.Vector.prototype.getStyle = function() {
+ return this.style_;
+};
+
+
+/**
+ * Get the style function.
+ * @return {ol.StyleFunction|undefined} Layer style function.
+ * @api stable
+ */
+ol.layer.Vector.prototype.getStyleFunction = function() {
+ return this.styleFunction_;
+};
+
+
+/**
+ * @return {boolean} Whether the rendered layer should be updated while
+ * animating.
+ */
+ol.layer.Vector.prototype.getUpdateWhileAnimating = function() {
+ return this.updateWhileAnimating_;
+};
+
+
+/**
+ * @return {boolean} Whether the rendered layer should be updated while
+ * interacting.
+ */
+ol.layer.Vector.prototype.getUpdateWhileInteracting = function() {
+ return this.updateWhileInteracting_;
+};
+
+
+/**
+ * @param {function(ol.Feature, ol.Feature):number|null|undefined} renderOrder
+ * Render order.
+ */
+ol.layer.Vector.prototype.setRenderOrder = function(renderOrder) {
+ goog.asserts.assert(
+ renderOrder === undefined || !renderOrder ||
+ typeof renderOrder === 'function',
+ 'renderOrder must be a comparator function');
+ this.set(ol.layer.VectorProperty.RENDER_ORDER, renderOrder);
+};
+
+
+/**
+ * Set the style for features. This can be a single style object, an array
+ * of styles, or a function that takes a feature and resolution and returns
+ * an array of styles. If it is `undefined` the default style is used. If
+ * it is `null` the layer has no style (a `null` style), so only features
+ * that have their own styles will be rendered in the layer. See
+ * {@link ol.style} for information on the default style.
+ * @param {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|null|undefined}
+ * style Layer style.
+ * @api stable
+ */
+ol.layer.Vector.prototype.setStyle = function(style) {
+ this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction;
+ this.styleFunction_ = style === null ?
+ undefined : ol.style.createStyleFunction(this.style_);
+ this.changed();
+};
+
+goog.provide('ol.layer.VectorTile');
+
+goog.require('goog.asserts');
+goog.require('ol.layer.Vector');
+goog.require('ol.object');
+
+
+/**
+ * @enum {string}
+ */
+ol.layer.VectorTileProperty = {
+ PRELOAD: 'preload',
+ USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'
+};
+
+
+/**
+ * @enum {string}
+ * Render mode for vector tiles:
+ * * `'image'`: Vector tiles are rendered as images. Great performance, but
+ * point symbols and texts are always rotated with the view and pixels are
+ * scaled during zoom animations.
+ * * `'hybrid'`: Polygon and line elements are rendered as images, so pixels
+ * are scaled during zoom animations. Point symbols and texts are accurately
+ * rendered as vectors and can stay upright on rotated views.
+ * * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering
+ * even during animations, but slower performance than the other options.
+ * @api
+ */
+ol.layer.VectorTileRenderType = {
+ IMAGE: 'image',
+ HYBRID: 'hybrid',
+ VECTOR: 'vector'
+};
+
+
+/**
+ * @classdesc
+ * Layer for vector tile data that is rendered client-side.
+ * Note that any property set in the options is set as a {@link ol.Object}
+ * property on the layer object; for example, setting `title: 'My Title'` in the
+ * options means that `title` is observable, and has get/set accessors.
+ *
+ * @constructor
+ * @extends {ol.layer.Vector}
+ * @param {olx.layer.VectorTileOptions=} opt_options Options.
+ * @api
+ */
+ol.layer.VectorTile = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+
+ var baseOptions = ol.object.assign({}, options);
+
+ delete baseOptions.preload;
+ delete baseOptions.useInterimTilesOnError;
+ ol.layer.Vector.call(this, /** @type {olx.layer.VectorOptions} */ (baseOptions));
+
+ this.setPreload(options.preload ? options.preload : 0);
+ this.setUseInterimTilesOnError(options.useInterimTilesOnError ?
+ options.useInterimTilesOnError : true);
+
+ goog.asserts.assert(options.renderMode == undefined ||
+ options.renderMode == ol.layer.VectorTileRenderType.IMAGE ||
+ options.renderMode == ol.layer.VectorTileRenderType.HYBRID ||
+ options.renderMode == ol.layer.VectorTileRenderType.VECTOR,
+ 'renderMode needs to be \'image\', \'hybrid\' or \'vector\'');
+
+ /**
+ * @private
+ * @type {ol.layer.VectorTileRenderType|string}
+ */
+ this.renderMode_ = options.renderMode || ol.layer.VectorTileRenderType.HYBRID;
+
+};
+ol.inherits(ol.layer.VectorTile, ol.layer.Vector);
+
+
+/**
+ * Return the level as number to which we will preload tiles up to.
+ * @return {number} The level to preload tiles up to.
+ * @observable
+ * @api
+ */
+ol.layer.VectorTile.prototype.getPreload = function() {
+ return /** @type {number} */ (this.get(ol.layer.VectorTileProperty.PRELOAD));
+};
+
+
+/**
+ * @return {ol.layer.VectorTileRenderType|string} The render mode.
+ */
+ol.layer.VectorTile.prototype.getRenderMode = function() {
+ return this.renderMode_;
+};
+
+
+/**
+ * Whether we use interim tiles on error.
+ * @return {boolean} Use interim tiles on error.
+ * @observable
+ * @api
+ */
+ol.layer.VectorTile.prototype.getUseInterimTilesOnError = function() {
+ return /** @type {boolean} */ (
+ this.get(ol.layer.VectorTileProperty.USE_INTERIM_TILES_ON_ERROR));
+};
+
+
+/**
+ * Set the level as number to which we will preload tiles up to.
+ * @param {number} preload The level to preload tiles up to.
+ * @observable
+ * @api
+ */
+ol.layer.VectorTile.prototype.setPreload = function(preload) {
+ this.set(ol.layer.TileProperty.PRELOAD, preload);
+};
+
+
+/**
+ * Set whether we use interim tiles on error.
+ * @param {boolean} useInterimTilesOnError Use interim tiles on error.
+ * @observable
+ * @api
+ */
+ol.layer.VectorTile.prototype.setUseInterimTilesOnError = function(useInterimTilesOnError) {
+ this.set(
+ ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
+};
+
+// FIXME test, especially polygons with holes and multipolygons
+// FIXME need to handle large thick features (where pixel size matters)
+// FIXME add offset and end to ol.geom.flat.transform.transform2D?
+
+goog.provide('ol.render.canvas.Immediate');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.array');
+goog.require('ol.color');
+goog.require('ol.colorlike');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.flat.transform');
+goog.require('ol.has');
+goog.require('ol.render.VectorContext');
+goog.require('ol.render.canvas');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @classdesc
+ * A concrete subclass of {@link ol.render.VectorContext} that implements
+ * direct rendering of features and geometries to an HTML5 Canvas context.
+ * Instances of this class are created internally by the library and
+ * provided to application code as vectorContext member of the
+ * {@link ol.render.Event} object associated with postcompose, precompose and
+ * render events emitted by layers and maps.
+ *
+ * @constructor
+ * @extends {ol.render.VectorContext}
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.Extent} extent Extent.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {number} viewRotation View rotation.
+ * @struct
+ */
+ol.render.canvas.Immediate = function(context, pixelRatio, extent, transform, viewRotation) {
+ ol.render.VectorContext.call(this);
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = context;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.pixelRatio_ = pixelRatio;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.extent_ = extent;
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.transform_ = transform;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.viewRotation_ = viewRotation;
+
+ /**
+ * @private
+ * @type {?ol.CanvasFillState}
+ */
+ this.contextFillState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasStrokeState}
+ */
+ this.contextStrokeState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasTextState}
+ */
+ this.contextTextState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasFillState}
+ */
+ this.fillState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasStrokeState}
+ */
+ this.strokeState_ = null;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement|HTMLVideoElement|Image}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageAnchorX_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageAnchorY_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageHeight_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageOpacity_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageOriginX_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageOriginY_ = 0;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.imageRotateWithView_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageRotation_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageScale_ = 0;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.imageSnapToPixel_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.imageWidth_ = 0;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.text_ = '';
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textOffsetX_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textOffsetY_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textRotation_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textScale_ = 0;
+
+ /**
+ * @private
+ * @type {?ol.CanvasFillState}
+ */
+ this.textFillState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasStrokeState}
+ */
+ this.textStrokeState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasTextState}
+ */
+ this.textState_ = null;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.pixelCoordinates_ = [];
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.tmpLocalTransform_ = goog.vec.Mat4.createNumber();
+
+};
+ol.inherits(ol.render.canvas.Immediate, ol.render.VectorContext);
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @private
+ */
+ol.render.canvas.Immediate.prototype.drawImages_ = function(flatCoordinates, offset, end, stride) {
+ if (!this.image_) {
+ return;
+ }
+ goog.asserts.assert(offset === 0, 'offset should be 0');
+ goog.asserts.assert(end == flatCoordinates.length,
+ 'end should be equal to the length of flatCoordinates');
+ var pixelCoordinates = ol.geom.flat.transform.transform2D(
+ flatCoordinates, offset, end, 2, this.transform_,
+ this.pixelCoordinates_);
+ var context = this.context_;
+ var localTransform = this.tmpLocalTransform_;
+ var alpha = context.globalAlpha;
+ if (this.imageOpacity_ != 1) {
+ context.globalAlpha = alpha * this.imageOpacity_;
+ }
+ var rotation = this.imageRotation_;
+ if (this.imageRotateWithView_) {
+ rotation += this.viewRotation_;
+ }
+ var i, ii;
+ for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {
+ var x = pixelCoordinates[i] - this.imageAnchorX_;
+ var y = pixelCoordinates[i + 1] - this.imageAnchorY_;
+ if (this.imageSnapToPixel_) {
+ x = Math.round(x);
+ y = Math.round(y);
+ }
+ if (rotation !== 0 || this.imageScale_ != 1) {
+ var centerX = x + this.imageAnchorX_;
+ var centerY = y + this.imageAnchorY_;
+ ol.vec.Mat4.makeTransform2D(localTransform,
+ centerX, centerY, this.imageScale_, this.imageScale_,
+ rotation, -centerX, -centerY);
+ context.setTransform(
+ goog.vec.Mat4.getElement(localTransform, 0, 0),
+ goog.vec.Mat4.getElement(localTransform, 1, 0),
+ goog.vec.Mat4.getElement(localTransform, 0, 1),
+ goog.vec.Mat4.getElement(localTransform, 1, 1),
+ goog.vec.Mat4.getElement(localTransform, 0, 3),
+ goog.vec.Mat4.getElement(localTransform, 1, 3));
+ }
+ context.drawImage(this.image_, this.imageOriginX_, this.imageOriginY_,
+ this.imageWidth_, this.imageHeight_, x, y,
+ this.imageWidth_, this.imageHeight_);
+ }
+ if (rotation !== 0 || this.imageScale_ != 1) {
+ context.setTransform(1, 0, 0, 1, 0, 0);
+ }
+ if (this.imageOpacity_ != 1) {
+ context.globalAlpha = alpha;
+ }
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @private
+ */
+ol.render.canvas.Immediate.prototype.drawText_ = function(flatCoordinates, offset, end, stride) {
+ if (!this.textState_ || this.text_ === '') {
+ return;
+ }
+ if (this.textFillState_) {
+ this.setContextFillState_(this.textFillState_);
+ }
+ if (this.textStrokeState_) {
+ this.setContextStrokeState_(this.textStrokeState_);
+ }
+ this.setContextTextState_(this.textState_);
+ goog.asserts.assert(offset === 0, 'offset should be 0');
+ goog.asserts.assert(end == flatCoordinates.length,
+ 'end should be equal to the length of flatCoordinates');
+ var pixelCoordinates = ol.geom.flat.transform.transform2D(
+ flatCoordinates, offset, end, stride, this.transform_,
+ this.pixelCoordinates_);
+ var context = this.context_;
+ for (; offset < end; offset += stride) {
+ var x = pixelCoordinates[offset] + this.textOffsetX_;
+ var y = pixelCoordinates[offset + 1] + this.textOffsetY_;
+ if (this.textRotation_ !== 0 || this.textScale_ != 1) {
+ var localTransform = ol.vec.Mat4.makeTransform2D(this.tmpLocalTransform_,
+ x, y, this.textScale_, this.textScale_, this.textRotation_, -x, -y);
+ context.setTransform(
+ goog.vec.Mat4.getElement(localTransform, 0, 0),
+ goog.vec.Mat4.getElement(localTransform, 1, 0),
+ goog.vec.Mat4.getElement(localTransform, 0, 1),
+ goog.vec.Mat4.getElement(localTransform, 1, 1),
+ goog.vec.Mat4.getElement(localTransform, 0, 3),
+ goog.vec.Mat4.getElement(localTransform, 1, 3));
+ }
+ if (this.textStrokeState_) {
+ context.strokeText(this.text_, x, y);
+ }
+ if (this.textFillState_) {
+ context.fillText(this.text_, x, y);
+ }
+ }
+ if (this.textRotation_ !== 0 || this.textScale_ != 1) {
+ context.setTransform(1, 0, 0, 1, 0, 0);
+ }
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {boolean} close Close.
+ * @private
+ * @return {number} end End.
+ */
+ol.render.canvas.Immediate.prototype.moveToLineTo_ = function(flatCoordinates, offset, end, stride, close) {
+ var context = this.context_;
+ var pixelCoordinates = ol.geom.flat.transform.transform2D(
+ flatCoordinates, offset, end, stride, this.transform_,
+ this.pixelCoordinates_);
+ context.moveTo(pixelCoordinates[0], pixelCoordinates[1]);
+ var length = pixelCoordinates.length;
+ if (close) {
+ length -= 2;
+ }
+ for (var i = 2; i < length; i += 2) {
+ context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]);
+ }
+ if (close) {
+ context.closePath();
+ }
+ return end;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @private
+ * @return {number} End.
+ */
+ol.render.canvas.Immediate.prototype.drawRings_ = function(flatCoordinates, offset, ends, stride) {
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ offset = this.moveToLineTo_(
+ flatCoordinates, offset, ends[i], stride, true);
+ }
+ return offset;
+};
+
+
+/**
+ * Render a circle geometry into the canvas. Rendering is immediate and uses
+ * the current fill and stroke styles.
+ *
+ * @param {ol.geom.Circle} geometry Circle geometry.
+ * @api
+ */
+ol.render.canvas.Immediate.prototype.drawCircle = function(geometry) {
+ if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
+ return;
+ }
+ if (this.fillState_ || this.strokeState_) {
+ if (this.fillState_) {
+ this.setContextFillState_(this.fillState_);
+ }
+ if (this.strokeState_) {
+ this.setContextStrokeState_(this.strokeState_);
+ }
+ var pixelCoordinates = ol.geom.transformSimpleGeometry2D(
+ geometry, this.transform_, this.pixelCoordinates_);
+ var dx = pixelCoordinates[2] - pixelCoordinates[0];
+ var dy = pixelCoordinates[3] - pixelCoordinates[1];
+ var radius = Math.sqrt(dx * dx + dy * dy);
+ var context = this.context_;
+ context.beginPath();
+ context.arc(
+ pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI);
+ if (this.fillState_) {
+ context.fill();
+ }
+ if (this.strokeState_) {
+ context.stroke();
+ }
+ }
+ if (this.text_ !== '') {
+ this.drawText_(geometry.getCenter(), 0, 2, 2);
+ }
+};
+
+
+/**
+ * Set the rendering style. Note that since this is an immediate rendering API,
+ * any `zIndex` on the provided style will be ignored.
+ *
+ * @param {ol.style.Style} style The rendering style.
+ * @api
+ */
+ol.render.canvas.Immediate.prototype.setStyle = function(style) {
+ this.setFillStrokeStyle(style.getFill(), style.getStroke());
+ this.setImageStyle(style.getImage());
+ this.setTextStyle(style.getText());
+};
+
+
+/**
+ * Render a geometry into the canvas. Call
+ * {@link ol.render.canvas.Immediate#setStyle} first to set the rendering style.
+ *
+ * @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.
+ * @api
+ */
+ol.render.canvas.Immediate.prototype.drawGeometry = function(geometry) {
+ var type = geometry.getType();
+ switch (type) {
+ case ol.geom.GeometryType.POINT:
+ this.drawPoint(/** @type {ol.geom.Point} */ (geometry));
+ break;
+ case ol.geom.GeometryType.LINE_STRING:
+ this.drawLineString(/** @type {ol.geom.LineString} */ (geometry));
+ break;
+ case ol.geom.GeometryType.POLYGON:
+ this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry));
+ break;
+ case ol.geom.GeometryType.MULTI_POINT:
+ this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry));
+ break;
+ case ol.geom.GeometryType.MULTI_LINE_STRING:
+ this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry));
+ break;
+ case ol.geom.GeometryType.MULTI_POLYGON:
+ this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry));
+ break;
+ case ol.geom.GeometryType.GEOMETRY_COLLECTION:
+ this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry));
+ break;
+ case ol.geom.GeometryType.CIRCLE:
+ this.drawCircle(/** @type {ol.geom.Circle} */ (geometry));
+ break;
+ default:
+ goog.asserts.fail('Unsupported geometry type: ' + type);
+ }
+};
+
+
+/**
+ * Render a feature into the canvas. Note that any `zIndex` on the provided
+ * style will be ignored - features are rendered immediately in the order that
+ * this method is called. If you need `zIndex` support, you should be using an
+ * {@link ol.layer.Vector} instead.
+ *
+ * @param {ol.Feature} feature Feature.
+ * @param {ol.style.Style} style Style.
+ * @api
+ */
+ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) {
+ var geometry = style.getGeometryFunction()(feature);
+ if (!geometry ||
+ !ol.extent.intersects(this.extent_, geometry.getExtent())) {
+ return;
+ }
+ this.setStyle(style);
+ goog.asserts.assert(geometry, 'geometry must be truthy');
+ this.drawGeometry(geometry);
+};
+
+
+/**
+ * Render a GeometryCollection to the canvas. Rendering is immediate and
+ * uses the current styles appropriate for each geometry in the collection.
+ *
+ * @param {ol.geom.GeometryCollection} geometry Geometry collection.
+ */
+ol.render.canvas.Immediate.prototype.drawGeometryCollection = function(geometry) {
+ var geometries = geometry.getGeometriesArray();
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ this.drawGeometry(geometries[i]);
+ }
+};
+
+
+/**
+ * Render a Point geometry into the canvas. Rendering is immediate and uses
+ * the current style.
+ *
+ * @param {ol.geom.Point|ol.render.Feature} geometry Point geometry.
+ */
+ol.render.canvas.Immediate.prototype.drawPoint = function(geometry) {
+ var flatCoordinates = geometry.getFlatCoordinates();
+ var stride = geometry.getStride();
+ if (this.image_) {
+ this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);
+ }
+ if (this.text_ !== '') {
+ this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);
+ }
+};
+
+
+/**
+ * Render a MultiPoint geometry into the canvas. Rendering is immediate and
+ * uses the current style.
+ *
+ * @param {ol.geom.MultiPoint|ol.render.Feature} geometry MultiPoint geometry.
+ */
+ol.render.canvas.Immediate.prototype.drawMultiPoint = function(geometry) {
+ var flatCoordinates = geometry.getFlatCoordinates();
+ var stride = geometry.getStride();
+ if (this.image_) {
+ this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);
+ }
+ if (this.text_ !== '') {
+ this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);
+ }
+};
+
+
+/**
+ * Render a LineString into the canvas. Rendering is immediate and uses
+ * the current style.
+ *
+ * @param {ol.geom.LineString|ol.render.Feature} geometry LineString geometry.
+ */
+ol.render.canvas.Immediate.prototype.drawLineString = function(geometry) {
+ if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
+ return;
+ }
+ if (this.strokeState_) {
+ this.setContextStrokeState_(this.strokeState_);
+ var context = this.context_;
+ var flatCoordinates = geometry.getFlatCoordinates();
+ context.beginPath();
+ this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length,
+ geometry.getStride(), false);
+ context.stroke();
+ }
+ if (this.text_ !== '') {
+ var flatMidpoint = geometry.getFlatMidpoint();
+ this.drawText_(flatMidpoint, 0, 2, 2);
+ }
+};
+
+
+/**
+ * Render a MultiLineString geometry into the canvas. Rendering is immediate
+ * and uses the current style.
+ *
+ * @param {ol.geom.MultiLineString|ol.render.Feature} geometry MultiLineString
+ * geometry.
+ */
+ol.render.canvas.Immediate.prototype.drawMultiLineString = function(geometry) {
+ var geometryExtent = geometry.getExtent();
+ if (!ol.extent.intersects(this.extent_, geometryExtent)) {
+ return;
+ }
+ if (this.strokeState_) {
+ this.setContextStrokeState_(this.strokeState_);
+ var context = this.context_;
+ var flatCoordinates = geometry.getFlatCoordinates();
+ var offset = 0;
+ var ends = geometry.getEnds();
+ var stride = geometry.getStride();
+ context.beginPath();
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ offset = this.moveToLineTo_(
+ flatCoordinates, offset, ends[i], stride, false);
+ }
+ context.stroke();
+ }
+ if (this.text_ !== '') {
+ var flatMidpoints = geometry.getFlatMidpoints();
+ this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2);
+ }
+};
+
+
+/**
+ * Render a Polygon geometry into the canvas. Rendering is immediate and uses
+ * the current style.
+ *
+ * @param {ol.geom.Polygon|ol.render.Feature} geometry Polygon geometry.
+ */
+ol.render.canvas.Immediate.prototype.drawPolygon = function(geometry) {
+ if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
+ return;
+ }
+ if (this.strokeState_ || this.fillState_) {
+ if (this.fillState_) {
+ this.setContextFillState_(this.fillState_);
+ }
+ if (this.strokeState_) {
+ this.setContextStrokeState_(this.strokeState_);
+ }
+ var context = this.context_;
+ context.beginPath();
+ this.drawRings_(geometry.getOrientedFlatCoordinates(),
+ 0, geometry.getEnds(), geometry.getStride());
+ if (this.fillState_) {
+ context.fill();
+ }
+ if (this.strokeState_) {
+ context.stroke();
+ }
+ }
+ if (this.text_ !== '') {
+ var flatInteriorPoint = geometry.getFlatInteriorPoint();
+ this.drawText_(flatInteriorPoint, 0, 2, 2);
+ }
+};
+
+
+/**
+ * Render MultiPolygon geometry into the canvas. Rendering is immediate and
+ * uses the current style.
+ * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.
+ */
+ol.render.canvas.Immediate.prototype.drawMultiPolygon = function(geometry) {
+ if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
+ return;
+ }
+ if (this.strokeState_ || this.fillState_) {
+ if (this.fillState_) {
+ this.setContextFillState_(this.fillState_);
+ }
+ if (this.strokeState_) {
+ this.setContextStrokeState_(this.strokeState_);
+ }
+ var context = this.context_;
+ var flatCoordinates = geometry.getOrientedFlatCoordinates();
+ var offset = 0;
+ var endss = geometry.getEndss();
+ var stride = geometry.getStride();
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ context.beginPath();
+ offset = this.drawRings_(flatCoordinates, offset, ends, stride);
+ if (this.fillState_) {
+ context.fill();
+ }
+ if (this.strokeState_) {
+ context.stroke();
+ }
+ }
+ }
+ if (this.text_ !== '') {
+ var flatInteriorPoints = geometry.getFlatInteriorPoints();
+ this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2);
+ }
+};
+
+
+/**
+ * @param {ol.CanvasFillState} fillState Fill state.
+ * @private
+ */
+ol.render.canvas.Immediate.prototype.setContextFillState_ = function(fillState) {
+ var context = this.context_;
+ var contextFillState = this.contextFillState_;
+ if (!contextFillState) {
+ context.fillStyle = fillState.fillStyle;
+ this.contextFillState_ = {
+ fillStyle: fillState.fillStyle
+ };
+ } else {
+ if (contextFillState.fillStyle != fillState.fillStyle) {
+ contextFillState.fillStyle = context.fillStyle = fillState.fillStyle;
+ }
+ }
+};
+
+
+/**
+ * @param {ol.CanvasStrokeState} strokeState Stroke state.
+ * @private
+ */
+ol.render.canvas.Immediate.prototype.setContextStrokeState_ = function(strokeState) {
+ var context = this.context_;
+ var contextStrokeState = this.contextStrokeState_;
+ if (!contextStrokeState) {
+ context.lineCap = strokeState.lineCap;
+ if (ol.has.CANVAS_LINE_DASH) {
+ context.setLineDash(strokeState.lineDash);
+ }
+ context.lineJoin = strokeState.lineJoin;
+ context.lineWidth = strokeState.lineWidth;
+ context.miterLimit = strokeState.miterLimit;
+ context.strokeStyle = strokeState.strokeStyle;
+ this.contextStrokeState_ = {
+ lineCap: strokeState.lineCap,
+ lineDash: strokeState.lineDash,
+ lineJoin: strokeState.lineJoin,
+ lineWidth: strokeState.lineWidth,
+ miterLimit: strokeState.miterLimit,
+ strokeStyle: strokeState.strokeStyle
+ };
+ } else {
+ if (contextStrokeState.lineCap != strokeState.lineCap) {
+ contextStrokeState.lineCap = context.lineCap = strokeState.lineCap;
+ }
+ if (ol.has.CANVAS_LINE_DASH) {
+ if (!ol.array.equals(
+ contextStrokeState.lineDash, strokeState.lineDash)) {
+ context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash);
+ }
+ }
+ if (contextStrokeState.lineJoin != strokeState.lineJoin) {
+ contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin;
+ }
+ if (contextStrokeState.lineWidth != strokeState.lineWidth) {
+ contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth;
+ }
+ if (contextStrokeState.miterLimit != strokeState.miterLimit) {
+ contextStrokeState.miterLimit = context.miterLimit =
+ strokeState.miterLimit;
+ }
+ if (contextStrokeState.strokeStyle != strokeState.strokeStyle) {
+ contextStrokeState.strokeStyle = context.strokeStyle =
+ strokeState.strokeStyle;
+ }
+ }
+};
+
+
+/**
+ * @param {ol.CanvasTextState} textState Text state.
+ * @private
+ */
+ol.render.canvas.Immediate.prototype.setContextTextState_ = function(textState) {
+ var context = this.context_;
+ var contextTextState = this.contextTextState_;
+ if (!contextTextState) {
+ context.font = textState.font;
+ context.textAlign = textState.textAlign;
+ context.textBaseline = textState.textBaseline;
+ this.contextTextState_ = {
+ font: textState.font,
+ textAlign: textState.textAlign,
+ textBaseline: textState.textBaseline
+ };
+ } else {
+ if (contextTextState.font != textState.font) {
+ contextTextState.font = context.font = textState.font;
+ }
+ if (contextTextState.textAlign != textState.textAlign) {
+ contextTextState.textAlign = context.textAlign = textState.textAlign;
+ }
+ if (contextTextState.textBaseline != textState.textBaseline) {
+ contextTextState.textBaseline = context.textBaseline =
+ textState.textBaseline;
+ }
+ }
+};
+
+
+/**
+ * Set the fill and stroke style for subsequent draw operations. To clear
+ * either fill or stroke styles, pass null for the appropriate parameter.
+ *
+ * @param {ol.style.Fill} fillStyle Fill style.
+ * @param {ol.style.Stroke} strokeStyle Stroke style.
+ */
+ol.render.canvas.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
+ if (!fillStyle) {
+ this.fillState_ = null;
+ } else {
+ var fillStyleColor = fillStyle.getColor();
+ this.fillState_ = {
+ fillStyle: ol.colorlike.asColorLike(fillStyleColor ?
+ fillStyleColor : ol.render.canvas.defaultFillStyle)
+ };
+ }
+ if (!strokeStyle) {
+ this.strokeState_ = null;
+ } else {
+ var strokeStyleColor = strokeStyle.getColor();
+ var strokeStyleLineCap = strokeStyle.getLineCap();
+ var strokeStyleLineDash = strokeStyle.getLineDash();
+ var strokeStyleLineJoin = strokeStyle.getLineJoin();
+ var strokeStyleWidth = strokeStyle.getWidth();
+ var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
+ this.strokeState_ = {
+ lineCap: strokeStyleLineCap !== undefined ?
+ strokeStyleLineCap : ol.render.canvas.defaultLineCap,
+ lineDash: strokeStyleLineDash ?
+ strokeStyleLineDash : ol.render.canvas.defaultLineDash,
+ lineJoin: strokeStyleLineJoin !== undefined ?
+ strokeStyleLineJoin : ol.render.canvas.defaultLineJoin,
+ lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ?
+ strokeStyleWidth : ol.render.canvas.defaultLineWidth),
+ miterLimit: strokeStyleMiterLimit !== undefined ?
+ strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit,
+ strokeStyle: ol.color.asString(strokeStyleColor ?
+ strokeStyleColor : ol.render.canvas.defaultStrokeStyle)
+ };
+ }
+};
+
+
+/**
+ * Set the image style for subsequent draw operations. Pass null to remove
+ * the image style.
+ *
+ * @param {ol.style.Image} imageStyle Image style.
+ */
+ol.render.canvas.Immediate.prototype.setImageStyle = function(imageStyle) {
+ if (!imageStyle) {
+ this.image_ = null;
+ } else {
+ var imageAnchor = imageStyle.getAnchor();
+ // FIXME pixel ratio
+ var imageImage = imageStyle.getImage(1);
+ var imageOrigin = imageStyle.getOrigin();
+ var imageSize = imageStyle.getSize();
+ goog.asserts.assert(imageAnchor, 'imageAnchor must be truthy');
+ goog.asserts.assert(imageImage, 'imageImage must be truthy');
+ goog.asserts.assert(imageOrigin, 'imageOrigin must be truthy');
+ goog.asserts.assert(imageSize, 'imageSize must be truthy');
+ this.imageAnchorX_ = imageAnchor[0];
+ this.imageAnchorY_ = imageAnchor[1];
+ this.imageHeight_ = imageSize[1];
+ this.image_ = imageImage;
+ this.imageOpacity_ = imageStyle.getOpacity();
+ this.imageOriginX_ = imageOrigin[0];
+ this.imageOriginY_ = imageOrigin[1];
+ this.imageRotateWithView_ = imageStyle.getRotateWithView();
+ this.imageRotation_ = imageStyle.getRotation();
+ this.imageScale_ = imageStyle.getScale();
+ this.imageSnapToPixel_ = imageStyle.getSnapToPixel();
+ this.imageWidth_ = imageSize[0];
+ }
+};
+
+
+/**
+ * Set the text style for subsequent draw operations. Pass null to
+ * remove the text style.
+ *
+ * @param {ol.style.Text} textStyle Text style.
+ */
+ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) {
+ if (!textStyle) {
+ this.text_ = '';
+ } else {
+ var textFillStyle = textStyle.getFill();
+ if (!textFillStyle) {
+ this.textFillState_ = null;
+ } else {
+ var textFillStyleColor = textFillStyle.getColor();
+ this.textFillState_ = {
+ fillStyle: ol.colorlike.asColorLike(textFillStyleColor ?
+ textFillStyleColor : ol.render.canvas.defaultFillStyle)
+ };
+ }
+ var textStrokeStyle = textStyle.getStroke();
+ if (!textStrokeStyle) {
+ this.textStrokeState_ = null;
+ } else {
+ var textStrokeStyleColor = textStrokeStyle.getColor();
+ var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
+ var textStrokeStyleLineDash = textStrokeStyle.getLineDash();
+ var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();
+ var textStrokeStyleWidth = textStrokeStyle.getWidth();
+ var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
+ this.textStrokeState_ = {
+ lineCap: textStrokeStyleLineCap !== undefined ?
+ textStrokeStyleLineCap : ol.render.canvas.defaultLineCap,
+ lineDash: textStrokeStyleLineDash ?
+ textStrokeStyleLineDash : ol.render.canvas.defaultLineDash,
+ lineJoin: textStrokeStyleLineJoin !== undefined ?
+ textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin,
+ lineWidth: textStrokeStyleWidth !== undefined ?
+ textStrokeStyleWidth : ol.render.canvas.defaultLineWidth,
+ miterLimit: textStrokeStyleMiterLimit !== undefined ?
+ textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit,
+ strokeStyle: ol.color.asString(textStrokeStyleColor ?
+ textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle)
+ };
+ }
+ var textFont = textStyle.getFont();
+ var textOffsetX = textStyle.getOffsetX();
+ var textOffsetY = textStyle.getOffsetY();
+ var textRotation = textStyle.getRotation();
+ var textScale = textStyle.getScale();
+ var textText = textStyle.getText();
+ var textTextAlign = textStyle.getTextAlign();
+ var textTextBaseline = textStyle.getTextBaseline();
+ this.textState_ = {
+ font: textFont !== undefined ?
+ textFont : ol.render.canvas.defaultFont,
+ textAlign: textTextAlign !== undefined ?
+ textTextAlign : ol.render.canvas.defaultTextAlign,
+ textBaseline: textTextBaseline !== undefined ?
+ textTextBaseline : ol.render.canvas.defaultTextBaseline
+ };
+ this.text_ = textText !== undefined ? textText : '';
+ this.textOffsetX_ =
+ textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0;
+ this.textOffsetY_ =
+ textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0;
+ this.textRotation_ = textRotation !== undefined ? textRotation : 0;
+ this.textScale_ = this.pixelRatio_ * (textScale !== undefined ?
+ textScale : 1);
+ }
+};
+
+goog.provide('ol.renderer.canvas.Layer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.extent');
+goog.require('ol.layer.Layer');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.canvas');
+goog.require('ol.render.canvas.Immediate');
+goog.require('ol.renderer.Layer');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.Layer}
+ * @param {ol.layer.Layer} layer Layer.
+ */
+ol.renderer.canvas.Layer = function(layer) {
+
+ ol.renderer.Layer.call(this, layer);
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumber();
+
+};
+ol.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer);
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @param {CanvasRenderingContext2D} context Context.
+ */
+ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerState, context) {
+
+ this.dispatchPreComposeEvent(context, frameState);
+
+ var image = this.getImage();
+ if (image) {
+
+ // clipped rendering if layer extent is set
+ var extent = layerState.extent;
+ var clipped = extent !== undefined;
+ if (clipped) {
+ goog.asserts.assert(extent !== undefined,
+ 'layerState extent is defined');
+ var pixelRatio = frameState.pixelRatio;
+ var width = frameState.size[0] * pixelRatio;
+ var height = frameState.size[1] * pixelRatio;
+ var rotation = frameState.viewState.rotation;
+ var topLeft = ol.extent.getTopLeft(extent);
+ var topRight = ol.extent.getTopRight(extent);
+ var bottomRight = ol.extent.getBottomRight(extent);
+ var bottomLeft = ol.extent.getBottomLeft(extent);
+
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ topLeft, topLeft);
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ topRight, topRight);
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ bottomRight, bottomRight);
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ bottomLeft, bottomLeft);
+
+ context.save();
+ ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
+ context.beginPath();
+ context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio);
+ context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio);
+ context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio);
+ context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio);
+ context.clip();
+ ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
+ }
+
+ var imageTransform = this.getImageTransform();
+ // for performance reasons, context.save / context.restore is not used
+ // to save and restore the transformation matrix and the opacity.
+ // see http://jsperf.com/context-save-restore-versus-variable
+ var alpha = context.globalAlpha;
+ context.globalAlpha = layerState.opacity;
+
+ // for performance reasons, context.setTransform is only used
+ // when the view is rotated. see http://jsperf.com/canvas-transform
+ var dx = goog.vec.Mat4.getElement(imageTransform, 0, 3);
+ var dy = goog.vec.Mat4.getElement(imageTransform, 1, 3);
+ var dw = image.width * goog.vec.Mat4.getElement(imageTransform, 0, 0);
+ var dh = image.height * goog.vec.Mat4.getElement(imageTransform, 1, 1);
+ context.drawImage(image, 0, 0, +image.width, +image.height,
+ Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
+ context.globalAlpha = alpha;
+
+ if (clipped) {
+ context.restore();
+ }
+ }
+
+ this.dispatchPostComposeEvent(context, frameState);
+
+};
+
+
+/**
+ * @param {ol.render.EventType} type Event type.
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {goog.vec.Mat4.Number=} opt_transform Transform.
+ * @private
+ */
+ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState, opt_transform) {
+ var layer = this.getLayer();
+ if (layer.hasListener(type)) {
+ var width = frameState.size[0] * frameState.pixelRatio;
+ var height = frameState.size[1] * frameState.pixelRatio;
+ var rotation = frameState.viewState.rotation;
+ ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
+ var transform = opt_transform !== undefined ?
+ opt_transform : this.getTransform(frameState, 0);
+ var render = new ol.render.canvas.Immediate(
+ context, frameState.pixelRatio, frameState.extent, transform,
+ frameState.viewState.rotation);
+ var composeEvent = new ol.render.Event(type, layer, render, frameState,
+ context, null);
+ layer.dispatchEvent(composeEvent);
+ ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
+ }
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {goog.vec.Mat4.Number=} opt_transform Transform.
+ * @protected
+ */
+ol.renderer.canvas.Layer.prototype.dispatchPostComposeEvent = function(context, frameState, opt_transform) {
+ this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, context,
+ frameState, opt_transform);
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {goog.vec.Mat4.Number=} opt_transform Transform.
+ * @protected
+ */
+ol.renderer.canvas.Layer.prototype.dispatchPreComposeEvent = function(context, frameState, opt_transform) {
+ this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, context,
+ frameState, opt_transform);
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {goog.vec.Mat4.Number=} opt_transform Transform.
+ * @protected
+ */
+ol.renderer.canvas.Layer.prototype.dispatchRenderEvent = function(context, frameState, opt_transform) {
+ this.dispatchComposeEvent_(ol.render.EventType.RENDER, context,
+ frameState, opt_transform);
+};
+
+
+/**
+ * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas.
+ */
+ol.renderer.canvas.Layer.prototype.getImage = goog.abstractMethod;
+
+
+/**
+ * @return {!goog.vec.Mat4.Number} Image transform.
+ */
+ol.renderer.canvas.Layer.prototype.getImageTransform = goog.abstractMethod;
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {number} offsetX Offset on the x-axis in view coordinates.
+ * @protected
+ * @return {!goog.vec.Mat4.Number} Transform.
+ */
+ol.renderer.canvas.Layer.prototype.getTransform = function(frameState, offsetX) {
+ var viewState = frameState.viewState;
+ var pixelRatio = frameState.pixelRatio;
+ return ol.vec.Mat4.makeTransform2D(this.transform_,
+ pixelRatio * frameState.size[0] / 2,
+ pixelRatio * frameState.size[1] / 2,
+ pixelRatio / viewState.resolution,
+ -pixelRatio / viewState.resolution,
+ -viewState.rotation,
+ -viewState.center[0] + offsetX,
+ -viewState.center[1]);
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @return {boolean} whether composeFrame should be called.
+ */
+ol.renderer.canvas.Layer.prototype.prepareFrame = goog.abstractMethod;
+
+
+/**
+ * @param {ol.Pixel} pixelOnMap Pixel.
+ * @param {goog.vec.Mat4.Number} imageTransformInv The transformation matrix
+ * to convert from a map pixel to a canvas pixel.
+ * @return {ol.Pixel} The pixel.
+ * @protected
+ */
+ol.renderer.canvas.Layer.prototype.getPixelOnCanvas = function(pixelOnMap, imageTransformInv) {
+ var pixelOnCanvas = [0, 0];
+ ol.vec.Mat4.multVec2(imageTransformInv, pixelOnMap, pixelOnCanvas);
+ return pixelOnCanvas;
+};
+
+goog.provide('ol.render.IReplayGroup');
+
+goog.require('ol.render.VectorContext');
+
+
+/**
+ * @enum {string}
+ */
+ol.render.ReplayType = {
+ IMAGE: 'Image',
+ LINE_STRING: 'LineString',
+ POLYGON: 'Polygon',
+ TEXT: 'Text'
+};
+
+
+/**
+ * @const
+ * @type {Array.<ol.render.ReplayType>}
+ */
+ol.render.REPLAY_ORDER = [
+ ol.render.ReplayType.POLYGON,
+ ol.render.ReplayType.LINE_STRING,
+ ol.render.ReplayType.IMAGE,
+ ol.render.ReplayType.TEXT
+];
+
+
+/**
+ * @interface
+ */
+ol.render.IReplayGroup = function() {
+};
+
+
+/* eslint-disable valid-jsdoc */
+// TODO: enable valid-jsdoc for @interface methods when this issue is resolved
+// https://github.com/eslint/eslint/issues/4887
+
+
+/**
+ * @param {number|undefined} zIndex Z index.
+ * @param {ol.render.ReplayType} replayType Replay type.
+ * @return {ol.render.VectorContext} Replay.
+ */
+ol.render.IReplayGroup.prototype.getReplay = function(zIndex, replayType) {
+};
+
+
+/**
+ * @return {boolean} Is empty.
+ */
+ol.render.IReplayGroup.prototype.isEmpty = function() {
+};
+
+// FIXME add option to apply snapToPixel to all coordinates?
+// FIXME can eliminate empty set styles and strokes (when all geoms skipped)
+
+goog.provide('ol.render.canvas.ImageReplay');
+goog.provide('ol.render.canvas.LineStringReplay');
+goog.provide('ol.render.canvas.PolygonReplay');
+goog.provide('ol.render.canvas.Replay');
+goog.provide('ol.render.canvas.ReplayGroup');
+goog.provide('ol.render.canvas.TextReplay');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.color');
+goog.require('ol.colorlike');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.extent.Relationship');
+goog.require('ol.geom.flat.simplify');
+goog.require('ol.geom.flat.transform');
+goog.require('ol.has');
+goog.require('ol.object');
+goog.require('ol.render.IReplayGroup');
+goog.require('ol.render.VectorContext');
+goog.require('ol.render.canvas');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @enum {number}
+ */
+ol.render.canvas.Instruction = {
+ BEGIN_GEOMETRY: 0,
+ BEGIN_PATH: 1,
+ CIRCLE: 2,
+ CLOSE_PATH: 3,
+ DRAW_IMAGE: 4,
+ DRAW_TEXT: 5,
+ END_GEOMETRY: 6,
+ FILL: 7,
+ MOVE_TO_LINE_TO: 8,
+ SET_FILL_STYLE: 9,
+ SET_STROKE_STYLE: 10,
+ SET_TEXT_STYLE: 11,
+ STROKE: 12
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.render.VectorContext}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Maximum extent.
+ * @param {number} resolution Resolution.
+ * @protected
+ * @struct
+ */
+ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) {
+ ol.render.VectorContext.call(this);
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.tolerance = tolerance;
+
+ /**
+ * @protected
+ * @const
+ * @type {ol.Extent}
+ */
+ this.maxExtent = maxExtent;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.bufferedMaxExtent_ = null;
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.maxLineWidth = 0;
+
+ /**
+ * @protected
+ * @const
+ * @type {number}
+ */
+ this.resolution = resolution;
+
+ /**
+ * @private
+ * @type {Array.<*>}
+ */
+ this.beginGeometryInstruction1_ = null;
+
+ /**
+ * @private
+ * @type {Array.<*>}
+ */
+ this.beginGeometryInstruction2_ = null;
+
+ /**
+ * @protected
+ * @type {Array.<*>}
+ */
+ this.instructions = [];
+
+ /**
+ * @protected
+ * @type {Array.<number>}
+ */
+ this.coordinates = [];
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.renderedTransform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @protected
+ * @type {Array.<*>}
+ */
+ this.hitDetectionInstructions = [];
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.pixelCoordinates_ = [];
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.tmpLocalTransform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.tmpLocalTransformInv_ = goog.vec.Mat4.createNumber();
+};
+ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {boolean} close Close.
+ * @protected
+ * @return {number} My end.
+ */
+ol.render.canvas.Replay.prototype.appendFlatCoordinates = function(flatCoordinates, offset, end, stride, close) {
+
+ var myEnd = this.coordinates.length;
+ var extent = this.getBufferedMaxExtent();
+ var lastCoord = [flatCoordinates[offset], flatCoordinates[offset + 1]];
+ var nextCoord = [NaN, NaN];
+ var skipped = true;
+
+ var i, lastRel, nextRel;
+ for (i = offset + stride; i < end; i += stride) {
+ nextCoord[0] = flatCoordinates[i];
+ nextCoord[1] = flatCoordinates[i + 1];
+ nextRel = ol.extent.coordinateRelationship(extent, nextCoord);
+ if (nextRel !== lastRel) {
+ if (skipped) {
+ this.coordinates[myEnd++] = lastCoord[0];
+ this.coordinates[myEnd++] = lastCoord[1];
+ }
+ this.coordinates[myEnd++] = nextCoord[0];
+ this.coordinates[myEnd++] = nextCoord[1];
+ skipped = false;
+ } else if (nextRel === ol.extent.Relationship.INTERSECTING) {
+ this.coordinates[myEnd++] = nextCoord[0];
+ this.coordinates[myEnd++] = nextCoord[1];
+ skipped = false;
+ } else {
+ skipped = true;
+ }
+ lastCoord[0] = nextCoord[0];
+ lastCoord[1] = nextCoord[1];
+ lastRel = nextRel;
+ }
+
+ // handle case where there is only one point to append
+ if (i === offset + stride) {
+ this.coordinates[myEnd++] = lastCoord[0];
+ this.coordinates[myEnd++] = lastCoord[1];
+ }
+
+ if (close) {
+ this.coordinates[myEnd++] = flatCoordinates[offset];
+ this.coordinates[myEnd++] = flatCoordinates[offset + 1];
+ }
+ return myEnd;
+};
+
+
+/**
+ * @protected
+ * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) {
+ this.beginGeometryInstruction1_ =
+ [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0];
+ this.instructions.push(this.beginGeometryInstruction1_);
+ this.beginGeometryInstruction2_ =
+ [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0];
+ this.hitDetectionInstructions.push(this.beginGeometryInstruction2_);
+};
+
+
+/**
+ * @private
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {number} viewRotation View rotation.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {Array.<*>} instructions Instructions array.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined}
+ * featureCallback Feature callback.
+ * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
+ * extent.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.canvas.Replay.prototype.replay_ = function(
+ context, pixelRatio, transform, viewRotation, skippedFeaturesHash,
+ instructions, featureCallback, opt_hitExtent) {
+ /** @type {Array.<number>} */
+ var pixelCoordinates;
+ if (ol.vec.Mat4.equals2D(transform, this.renderedTransform_)) {
+ pixelCoordinates = this.pixelCoordinates_;
+ } else {
+ pixelCoordinates = ol.geom.flat.transform.transform2D(
+ this.coordinates, 0, this.coordinates.length, 2,
+ transform, this.pixelCoordinates_);
+ goog.vec.Mat4.setFromArray(this.renderedTransform_, transform);
+ goog.asserts.assert(pixelCoordinates === this.pixelCoordinates_,
+ 'pixelCoordinates should be the same as this.pixelCoordinates_');
+ }
+ var skipFeatures = !ol.object.isEmpty(skippedFeaturesHash);
+ var i = 0; // instruction index
+ var ii = instructions.length; // end of instructions
+ var d = 0; // data index
+ var dd; // end of per-instruction data
+ var localTransform = this.tmpLocalTransform_;
+ var localTransformInv = this.tmpLocalTransformInv_;
+ var prevX, prevY, roundX, roundY;
+ while (i < ii) {
+ var instruction = instructions[i];
+ var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);
+ var feature, fill, stroke, text, x, y;
+ switch (type) {
+ case ol.render.canvas.Instruction.BEGIN_GEOMETRY:
+ feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]);
+ if ((skipFeatures &&
+ skippedFeaturesHash[goog.getUid(feature).toString()]) ||
+ !feature.getGeometry()) {
+ i = /** @type {number} */ (instruction[2]);
+ } else if (opt_hitExtent !== undefined && !ol.extent.intersects(
+ opt_hitExtent, feature.getGeometry().getExtent())) {
+ i = /** @type {number} */ (instruction[2]);
+ } else {
+ ++i;
+ }
+ break;
+ case ol.render.canvas.Instruction.BEGIN_PATH:
+ context.beginPath();
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.CIRCLE:
+ goog.asserts.assert(goog.isNumber(instruction[1]),
+ 'second instruction should be a number');
+ d = /** @type {number} */ (instruction[1]);
+ var x1 = pixelCoordinates[d];
+ var y1 = pixelCoordinates[d + 1];
+ var x2 = pixelCoordinates[d + 2];
+ var y2 = pixelCoordinates[d + 3];
+ var dx = x2 - x1;
+ var dy = y2 - y1;
+ var r = Math.sqrt(dx * dx + dy * dy);
+ context.arc(x1, y1, r, 0, 2 * Math.PI, true);
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.CLOSE_PATH:
+ context.closePath();
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.DRAW_IMAGE:
+ goog.asserts.assert(goog.isNumber(instruction[1]),
+ 'second instruction should be a number');
+ d = /** @type {number} */ (instruction[1]);
+ goog.asserts.assert(goog.isNumber(instruction[2]),
+ 'third instruction should be a number');
+ dd = /** @type {number} */ (instruction[2]);
+ var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */
+ (instruction[3]);
+ // Remaining arguments in DRAW_IMAGE are in alphabetical order
+ var anchorX = /** @type {number} */ (instruction[4]) * pixelRatio;
+ var anchorY = /** @type {number} */ (instruction[5]) * pixelRatio;
+ var height = /** @type {number} */ (instruction[6]);
+ var opacity = /** @type {number} */ (instruction[7]);
+ var originX = /** @type {number} */ (instruction[8]);
+ var originY = /** @type {number} */ (instruction[9]);
+ var rotateWithView = /** @type {boolean} */ (instruction[10]);
+ var rotation = /** @type {number} */ (instruction[11]);
+ var scale = /** @type {number} */ (instruction[12]);
+ var snapToPixel = /** @type {boolean} */ (instruction[13]);
+ var width = /** @type {number} */ (instruction[14]);
+ if (rotateWithView) {
+ rotation += viewRotation;
+ }
+ for (; d < dd; d += 2) {
+ x = pixelCoordinates[d] - anchorX;
+ y = pixelCoordinates[d + 1] - anchorY;
+ if (snapToPixel) {
+ x = Math.round(x);
+ y = Math.round(y);
+ }
+ if (scale != 1 || rotation !== 0) {
+ var centerX = x + anchorX;
+ var centerY = y + anchorY;
+ ol.vec.Mat4.makeTransform2D(
+ localTransform, centerX, centerY, scale, scale,
+ rotation, -centerX, -centerY);
+ context.transform(
+ goog.vec.Mat4.getElement(localTransform, 0, 0),
+ goog.vec.Mat4.getElement(localTransform, 1, 0),
+ goog.vec.Mat4.getElement(localTransform, 0, 1),
+ goog.vec.Mat4.getElement(localTransform, 1, 1),
+ goog.vec.Mat4.getElement(localTransform, 0, 3),
+ goog.vec.Mat4.getElement(localTransform, 1, 3));
+ }
+ var alpha = context.globalAlpha;
+ if (opacity != 1) {
+ context.globalAlpha = alpha * opacity;
+ }
+
+ var w = (width + originX > image.width) ? image.width - originX : width;
+ var h = (height + originY > image.height) ? image.height - originY : height;
+
+ context.drawImage(image, originX, originY, w, h,
+ x, y, w * pixelRatio, h * pixelRatio);
+
+ if (opacity != 1) {
+ context.globalAlpha = alpha;
+ }
+ if (scale != 1 || rotation !== 0) {
+ goog.vec.Mat4.invert(localTransform, localTransformInv);
+ context.transform(
+ goog.vec.Mat4.getElement(localTransformInv, 0, 0),
+ goog.vec.Mat4.getElement(localTransformInv, 1, 0),
+ goog.vec.Mat4.getElement(localTransformInv, 0, 1),
+ goog.vec.Mat4.getElement(localTransformInv, 1, 1),
+ goog.vec.Mat4.getElement(localTransformInv, 0, 3),
+ goog.vec.Mat4.getElement(localTransformInv, 1, 3));
+ }
+ }
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.DRAW_TEXT:
+ goog.asserts.assert(goog.isNumber(instruction[1]),
+ '2nd instruction should be a number');
+ d = /** @type {number} */ (instruction[1]);
+ goog.asserts.assert(goog.isNumber(instruction[2]),
+ '3rd instruction should be a number');
+ dd = /** @type {number} */ (instruction[2]);
+ goog.asserts.assert(typeof instruction[3] === 'string',
+ '4th instruction should be a string');
+ text = /** @type {string} */ (instruction[3]);
+ goog.asserts.assert(goog.isNumber(instruction[4]),
+ '5th instruction should be a number');
+ var offsetX = /** @type {number} */ (instruction[4]) * pixelRatio;
+ goog.asserts.assert(goog.isNumber(instruction[5]),
+ '6th instruction should be a number');
+ var offsetY = /** @type {number} */ (instruction[5]) * pixelRatio;
+ goog.asserts.assert(goog.isNumber(instruction[6]),
+ '7th instruction should be a number');
+ rotation = /** @type {number} */ (instruction[6]);
+ goog.asserts.assert(goog.isNumber(instruction[7]),
+ '8th instruction should be a number');
+ scale = /** @type {number} */ (instruction[7]) * pixelRatio;
+ goog.asserts.assert(typeof instruction[8] === 'boolean',
+ '9th instruction should be a boolean');
+ fill = /** @type {boolean} */ (instruction[8]);
+ goog.asserts.assert(typeof instruction[9] === 'boolean',
+ '10th instruction should be a boolean');
+ stroke = /** @type {boolean} */ (instruction[9]);
+ for (; d < dd; d += 2) {
+ x = pixelCoordinates[d] + offsetX;
+ y = pixelCoordinates[d + 1] + offsetY;
+ if (scale != 1 || rotation !== 0) {
+ ol.vec.Mat4.makeTransform2D(
+ localTransform, x, y, scale, scale, rotation, -x, -y);
+ context.transform(
+ goog.vec.Mat4.getElement(localTransform, 0, 0),
+ goog.vec.Mat4.getElement(localTransform, 1, 0),
+ goog.vec.Mat4.getElement(localTransform, 0, 1),
+ goog.vec.Mat4.getElement(localTransform, 1, 1),
+ goog.vec.Mat4.getElement(localTransform, 0, 3),
+ goog.vec.Mat4.getElement(localTransform, 1, 3));
+ }
+
+ // Support multiple lines separated by \n
+ var lines = text.split('\n');
+ var numLines = lines.length;
+ var fontSize, lineY;
+ if (numLines > 1) {
+ // Estimate line height using width of capital M, and add padding
+ fontSize = Math.round(context.measureText('M').width * 1.5);
+ lineY = y - (((numLines - 1) / 2) * fontSize);
+ } else {
+ // No need to calculate line height/offset for a single line
+ fontSize = 0;
+ lineY = y;
+ }
+
+ for (var lineIndex = 0; lineIndex < numLines; lineIndex++) {
+ var line = lines[lineIndex];
+ if (stroke) {
+ context.strokeText(line, x, lineY);
+ }
+ if (fill) {
+ context.fillText(line, x, lineY);
+ }
+
+ // Move next line down by fontSize px
+ lineY = lineY + fontSize;
+ }
+
+ if (scale != 1 || rotation !== 0) {
+ goog.vec.Mat4.invert(localTransform, localTransformInv);
+ context.transform(
+ goog.vec.Mat4.getElement(localTransformInv, 0, 0),
+ goog.vec.Mat4.getElement(localTransformInv, 1, 0),
+ goog.vec.Mat4.getElement(localTransformInv, 0, 1),
+ goog.vec.Mat4.getElement(localTransformInv, 1, 1),
+ goog.vec.Mat4.getElement(localTransformInv, 0, 3),
+ goog.vec.Mat4.getElement(localTransformInv, 1, 3));
+ }
+ }
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.END_GEOMETRY:
+ if (featureCallback !== undefined) {
+ feature =
+ /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]);
+ var result = featureCallback(feature);
+ if (result) {
+ return result;
+ }
+ }
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.FILL:
+ context.fill();
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.MOVE_TO_LINE_TO:
+ goog.asserts.assert(goog.isNumber(instruction[1]),
+ '2nd instruction should be a number');
+ d = /** @type {number} */ (instruction[1]);
+ goog.asserts.assert(goog.isNumber(instruction[2]),
+ '3rd instruction should be a number');
+ dd = /** @type {number} */ (instruction[2]);
+ x = pixelCoordinates[d];
+ y = pixelCoordinates[d + 1];
+ roundX = (x + 0.5) | 0;
+ roundY = (y + 0.5) | 0;
+ if (roundX !== prevX || roundY !== prevY) {
+ context.moveTo(x, y);
+ prevX = roundX;
+ prevY = roundY;
+ }
+ for (d += 2; d < dd; d += 2) {
+ x = pixelCoordinates[d];
+ y = pixelCoordinates[d + 1];
+ roundX = (x + 0.5) | 0;
+ roundY = (y + 0.5) | 0;
+ if (d == dd - 2 || roundX !== prevX || roundY !== prevY) {
+ context.lineTo(x, y);
+ prevX = roundX;
+ prevY = roundY;
+ }
+ }
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.SET_FILL_STYLE:
+ goog.asserts.assert(
+ ol.colorlike.isColorLike(instruction[1]),
+ '2nd instruction should be a string, ' +
+ 'CanvasPattern, or CanvasGradient');
+ context.fillStyle = /** @type {ol.ColorLike} */ (instruction[1]);
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.SET_STROKE_STYLE:
+ goog.asserts.assert(typeof instruction[1] === 'string',
+ '2nd instruction should be a string');
+ goog.asserts.assert(goog.isNumber(instruction[2]),
+ '3rd instruction should be a number');
+ goog.asserts.assert(typeof instruction[3] === 'string',
+ '4rd instruction should be a string');
+ goog.asserts.assert(typeof instruction[4] === 'string',
+ '5th instruction should be a string');
+ goog.asserts.assert(goog.isNumber(instruction[5]),
+ '6th instruction should be a number');
+ goog.asserts.assert(instruction[6],
+ '7th instruction should not be null');
+ var usePixelRatio = instruction[7] !== undefined ?
+ instruction[7] : true;
+ var lineWidth = /** @type {number} */ (instruction[2]);
+ context.strokeStyle = /** @type {string} */ (instruction[1]);
+ context.lineWidth = usePixelRatio ? lineWidth * pixelRatio : lineWidth;
+ context.lineCap = /** @type {string} */ (instruction[3]);
+ context.lineJoin = /** @type {string} */ (instruction[4]);
+ context.miterLimit = /** @type {number} */ (instruction[5]);
+ if (ol.has.CANVAS_LINE_DASH) {
+ context.setLineDash(/** @type {Array.<number>} */ (instruction[6]));
+ }
+ prevX = NaN;
+ prevY = NaN;
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.SET_TEXT_STYLE:
+ goog.asserts.assert(typeof instruction[1] === 'string',
+ '2nd instruction should be a string');
+ goog.asserts.assert(typeof instruction[2] === 'string',
+ '3rd instruction should be a string');
+ goog.asserts.assert(typeof instruction[3] === 'string',
+ '4th instruction should be a string');
+ context.font = /** @type {string} */ (instruction[1]);
+ context.textAlign = /** @type {string} */ (instruction[2]);
+ context.textBaseline = /** @type {string} */ (instruction[3]);
+ ++i;
+ break;
+ case ol.render.canvas.Instruction.STROKE:
+ context.stroke();
+ ++i;
+ break;
+ default:
+ goog.asserts.fail('Unknown canvas render instruction');
+ ++i; // consume the instruction anyway, to avoid an infinite loop
+ break;
+ }
+ }
+ // assert that all instructions were consumed
+ goog.asserts.assert(i == instructions.length,
+ 'all instructions should be consumed');
+ return undefined;
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {number} viewRotation View rotation.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ */
+ol.render.canvas.Replay.prototype.replay = function(
+ context, pixelRatio, transform, viewRotation, skippedFeaturesHash) {
+ var instructions = this.instructions;
+ this.replay_(context, pixelRatio, transform, viewRotation,
+ skippedFeaturesHash, instructions, undefined);
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {number} viewRotation View rotation.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback
+ * Feature callback.
+ * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
+ * extent.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.canvas.Replay.prototype.replayHitDetection = function(
+ context, transform, viewRotation, skippedFeaturesHash,
+ opt_featureCallback, opt_hitExtent) {
+ var instructions = this.hitDetectionInstructions;
+ return this.replay_(context, 1, transform, viewRotation,
+ skippedFeaturesHash, instructions, opt_featureCallback, opt_hitExtent);
+};
+
+
+/**
+ * @private
+ */
+ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions_ = function() {
+ var hitDetectionInstructions = this.hitDetectionInstructions;
+ // step 1 - reverse array
+ hitDetectionInstructions.reverse();
+ // step 2 - reverse instructions within geometry blocks
+ var i;
+ var n = hitDetectionInstructions.length;
+ var instruction;
+ var type;
+ var begin = -1;
+ for (i = 0; i < n; ++i) {
+ instruction = hitDetectionInstructions[i];
+ type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);
+ if (type == ol.render.canvas.Instruction.END_GEOMETRY) {
+ goog.asserts.assert(begin == -1, 'begin should be -1');
+ begin = i;
+ } else if (type == ol.render.canvas.Instruction.BEGIN_GEOMETRY) {
+ instruction[2] = i;
+ goog.asserts.assert(begin >= 0,
+ 'begin should be larger than or equal to 0');
+ ol.array.reverseSubArray(this.hitDetectionInstructions, begin, i);
+ begin = -1;
+ }
+ }
+};
+
+
+/**
+ * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ */
+ol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) {
+ goog.asserts.assert(this.beginGeometryInstruction1_,
+ 'this.beginGeometryInstruction1_ should not be null');
+ this.beginGeometryInstruction1_[2] = this.instructions.length;
+ this.beginGeometryInstruction1_ = null;
+ goog.asserts.assert(this.beginGeometryInstruction2_,
+ 'this.beginGeometryInstruction2_ should not be null');
+ this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length;
+ this.beginGeometryInstruction2_ = null;
+ var endGeometryInstruction =
+ [ol.render.canvas.Instruction.END_GEOMETRY, feature];
+ this.instructions.push(endGeometryInstruction);
+ this.hitDetectionInstructions.push(endGeometryInstruction);
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.render.canvas.Replay.prototype.finish = ol.nullFunction;
+
+
+/**
+ * Get the buffered rendering extent. Rendering will be clipped to the extent
+ * provided to the constructor. To account for symbolizers that may intersect
+ * this extent, we calculate a buffered extent (e.g. based on stroke width).
+ * @return {ol.Extent} The buffered rendering extent.
+ * @protected
+ */
+ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() {
+ return this.maxExtent;
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.render.canvas.Replay}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Maximum extent.
+ * @param {number} resolution Resolution.
+ * @protected
+ * @struct
+ */
+ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution) {
+ ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement|HTMLVideoElement|Image}
+ */
+ this.hitDetectionImage_ = null;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement|HTMLVideoElement|Image}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.anchorX_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.anchorY_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.height_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.opacity_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.originX_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.originY_ = undefined;
+
+ /**
+ * @private
+ * @type {boolean|undefined}
+ */
+ this.rotateWithView_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.rotation_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.scale_ = undefined;
+
+ /**
+ * @private
+ * @type {boolean|undefined}
+ */
+ this.snapToPixel_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.width_ = undefined;
+
+};
+ol.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay);
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @private
+ * @return {number} My end.
+ */
+ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {
+ return this.appendFlatCoordinates(
+ flatCoordinates, offset, end, stride, false);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) {
+ if (!this.image_) {
+ return;
+ }
+ goog.asserts.assert(this.anchorX_ !== undefined,
+ 'this.anchorX_ should be defined');
+ goog.asserts.assert(this.anchorY_ !== undefined,
+ 'this.anchorY_ should be defined');
+ goog.asserts.assert(this.height_ !== undefined,
+ 'this.height_ should be defined');
+ goog.asserts.assert(this.opacity_ !== undefined,
+ 'this.opacity_ should be defined');
+ goog.asserts.assert(this.originX_ !== undefined,
+ 'this.originX_ should be defined');
+ goog.asserts.assert(this.originY_ !== undefined,
+ 'this.originY_ should be defined');
+ goog.asserts.assert(this.rotateWithView_ !== undefined,
+ 'this.rotateWithView_ should be defined');
+ goog.asserts.assert(this.rotation_ !== undefined,
+ 'this.rotation_ should be defined');
+ goog.asserts.assert(this.scale_ !== undefined,
+ 'this.scale_ should be defined');
+ goog.asserts.assert(this.width_ !== undefined,
+ 'this.width_ should be defined');
+ this.beginGeometry(pointGeometry, feature);
+ var flatCoordinates = pointGeometry.getFlatCoordinates();
+ var stride = pointGeometry.getStride();
+ var myBegin = this.coordinates.length;
+ var myEnd = this.drawCoordinates_(
+ flatCoordinates, 0, flatCoordinates.length, stride);
+ this.instructions.push([
+ ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
+ // Remaining arguments to DRAW_IMAGE are in alphabetical order
+ this.anchorX_, this.anchorY_, this.height_, this.opacity_,
+ this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
+ this.scale_, this.snapToPixel_, this.width_
+ ]);
+ this.hitDetectionInstructions.push([
+ ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
+ this.hitDetectionImage_,
+ // Remaining arguments to DRAW_IMAGE are in alphabetical order
+ this.anchorX_, this.anchorY_, this.height_, this.opacity_,
+ this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
+ this.scale_, this.snapToPixel_, this.width_
+ ]);
+ this.endGeometry(pointGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) {
+ if (!this.image_) {
+ return;
+ }
+ goog.asserts.assert(this.anchorX_ !== undefined,
+ 'this.anchorX_ should be defined');
+ goog.asserts.assert(this.anchorY_ !== undefined,
+ 'this.anchorY_ should be defined');
+ goog.asserts.assert(this.height_ !== undefined,
+ 'this.height_ should be defined');
+ goog.asserts.assert(this.opacity_ !== undefined,
+ 'this.opacity_ should be defined');
+ goog.asserts.assert(this.originX_ !== undefined,
+ 'this.originX_ should be defined');
+ goog.asserts.assert(this.originY_ !== undefined,
+ 'this.originY_ should be defined');
+ goog.asserts.assert(this.rotateWithView_ !== undefined,
+ 'this.rotateWithView_ should be defined');
+ goog.asserts.assert(this.rotation_ !== undefined,
+ 'this.rotation_ should be defined');
+ goog.asserts.assert(this.scale_ !== undefined,
+ 'this.scale_ should be defined');
+ goog.asserts.assert(this.width_ !== undefined,
+ 'this.width_ should be defined');
+ this.beginGeometry(multiPointGeometry, feature);
+ var flatCoordinates = multiPointGeometry.getFlatCoordinates();
+ var stride = multiPointGeometry.getStride();
+ var myBegin = this.coordinates.length;
+ var myEnd = this.drawCoordinates_(
+ flatCoordinates, 0, flatCoordinates.length, stride);
+ this.instructions.push([
+ ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
+ // Remaining arguments to DRAW_IMAGE are in alphabetical order
+ this.anchorX_, this.anchorY_, this.height_, this.opacity_,
+ this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
+ this.scale_, this.snapToPixel_, this.width_
+ ]);
+ this.hitDetectionInstructions.push([
+ ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
+ this.hitDetectionImage_,
+ // Remaining arguments to DRAW_IMAGE are in alphabetical order
+ this.anchorX_, this.anchorY_, this.height_, this.opacity_,
+ this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
+ this.scale_, this.snapToPixel_, this.width_
+ ]);
+ this.endGeometry(multiPointGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.ImageReplay.prototype.finish = function() {
+ this.reverseHitDetectionInstructions_();
+ // FIXME this doesn't really protect us against further calls to draw*Geometry
+ this.anchorX_ = undefined;
+ this.anchorY_ = undefined;
+ this.hitDetectionImage_ = null;
+ this.image_ = null;
+ this.height_ = undefined;
+ this.scale_ = undefined;
+ this.opacity_ = undefined;
+ this.originX_ = undefined;
+ this.originY_ = undefined;
+ this.rotateWithView_ = undefined;
+ this.rotation_ = undefined;
+ this.snapToPixel_ = undefined;
+ this.width_ = undefined;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {
+ goog.asserts.assert(imageStyle, 'imageStyle should not be null');
+ var anchor = imageStyle.getAnchor();
+ goog.asserts.assert(anchor, 'anchor should not be null');
+ var size = imageStyle.getSize();
+ goog.asserts.assert(size, 'size should not be null');
+ var hitDetectionImage = imageStyle.getHitDetectionImage(1);
+ goog.asserts.assert(hitDetectionImage,
+ 'hitDetectionImage should not be null');
+ var image = imageStyle.getImage(1);
+ goog.asserts.assert(image, 'image should not be null');
+ var origin = imageStyle.getOrigin();
+ goog.asserts.assert(origin, 'origin should not be null');
+ this.anchorX_ = anchor[0];
+ this.anchorY_ = anchor[1];
+ this.hitDetectionImage_ = hitDetectionImage;
+ this.image_ = image;
+ this.height_ = size[1];
+ this.opacity_ = imageStyle.getOpacity();
+ this.originX_ = origin[0];
+ this.originY_ = origin[1];
+ this.rotateWithView_ = imageStyle.getRotateWithView();
+ this.rotation_ = imageStyle.getRotation();
+ this.scale_ = imageStyle.getScale();
+ this.snapToPixel_ = imageStyle.getSnapToPixel();
+ this.width_ = size[0];
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.render.canvas.Replay}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Maximum extent.
+ * @param {number} resolution Resolution.
+ * @protected
+ * @struct
+ */
+ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution) {
+
+ ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
+
+ /**
+ * @private
+ * @type {{currentStrokeStyle: (string|undefined),
+ * currentLineCap: (string|undefined),
+ * currentLineDash: Array.<number>,
+ * currentLineJoin: (string|undefined),
+ * currentLineWidth: (number|undefined),
+ * currentMiterLimit: (number|undefined),
+ * lastStroke: number,
+ * strokeStyle: (string|undefined),
+ * lineCap: (string|undefined),
+ * lineDash: Array.<number>,
+ * lineJoin: (string|undefined),
+ * lineWidth: (number|undefined),
+ * miterLimit: (number|undefined)}|null}
+ */
+ this.state_ = {
+ currentStrokeStyle: undefined,
+ currentLineCap: undefined,
+ currentLineDash: null,
+ currentLineJoin: undefined,
+ currentLineWidth: undefined,
+ currentMiterLimit: undefined,
+ lastStroke: 0,
+ strokeStyle: undefined,
+ lineCap: undefined,
+ lineDash: null,
+ lineJoin: undefined,
+ lineWidth: undefined,
+ miterLimit: undefined
+ };
+
+};
+ol.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay);
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @private
+ * @return {number} end.
+ */
+ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flatCoordinates, offset, end, stride) {
+ var myBegin = this.coordinates.length;
+ var myEnd = this.appendFlatCoordinates(
+ flatCoordinates, offset, end, stride, false);
+ var moveToLineToInstruction =
+ [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];
+ this.instructions.push(moveToLineToInstruction);
+ this.hitDetectionInstructions.push(moveToLineToInstruction);
+ return end;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() {
+ if (!this.bufferedMaxExtent_) {
+ this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
+ if (this.maxLineWidth > 0) {
+ var width = this.resolution * (this.maxLineWidth + 1) / 2;
+ ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
+ }
+ }
+ return this.bufferedMaxExtent_;
+};
+
+
+/**
+ * @private
+ */
+ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() {
+ var state = this.state_;
+ var strokeStyle = state.strokeStyle;
+ var lineCap = state.lineCap;
+ var lineDash = state.lineDash;
+ var lineJoin = state.lineJoin;
+ var lineWidth = state.lineWidth;
+ var miterLimit = state.miterLimit;
+ goog.asserts.assert(strokeStyle !== undefined,
+ 'strokeStyle should be defined');
+ goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined');
+ goog.asserts.assert(lineDash, 'lineDash should not be null');
+ goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined');
+ goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined');
+ goog.asserts.assert(miterLimit !== undefined, 'miterLimit should be defined');
+ if (state.currentStrokeStyle != strokeStyle ||
+ state.currentLineCap != lineCap ||
+ !ol.array.equals(state.currentLineDash, lineDash) ||
+ state.currentLineJoin != lineJoin ||
+ state.currentLineWidth != lineWidth ||
+ state.currentMiterLimit != miterLimit) {
+ if (state.lastStroke != this.coordinates.length) {
+ this.instructions.push(
+ [ol.render.canvas.Instruction.STROKE]);
+ state.lastStroke = this.coordinates.length;
+ }
+ this.instructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash],
+ [ol.render.canvas.Instruction.BEGIN_PATH]);
+ state.currentStrokeStyle = strokeStyle;
+ state.currentLineCap = lineCap;
+ state.currentLineDash = lineDash;
+ state.currentLineJoin = lineJoin;
+ state.currentLineWidth = lineWidth;
+ state.currentMiterLimit = miterLimit;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) {
+ var state = this.state_;
+ goog.asserts.assert(state, 'state should not be null');
+ var strokeStyle = state.strokeStyle;
+ var lineWidth = state.lineWidth;
+ if (strokeStyle === undefined || lineWidth === undefined) {
+ return;
+ }
+ this.setStrokeStyle_();
+ this.beginGeometry(lineStringGeometry, feature);
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
+ state.miterLimit, state.lineDash],
+ [ol.render.canvas.Instruction.BEGIN_PATH]);
+ var flatCoordinates = lineStringGeometry.getFlatCoordinates();
+ var stride = lineStringGeometry.getStride();
+ this.drawFlatCoordinates_(
+ flatCoordinates, 0, flatCoordinates.length, stride);
+ this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]);
+ this.endGeometry(lineStringGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {
+ var state = this.state_;
+ goog.asserts.assert(state, 'state should not be null');
+ var strokeStyle = state.strokeStyle;
+ var lineWidth = state.lineWidth;
+ if (strokeStyle === undefined || lineWidth === undefined) {
+ return;
+ }
+ this.setStrokeStyle_();
+ this.beginGeometry(multiLineStringGeometry, feature);
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
+ state.miterLimit, state.lineDash],
+ [ol.render.canvas.Instruction.BEGIN_PATH]);
+ var ends = multiLineStringGeometry.getEnds();
+ var flatCoordinates = multiLineStringGeometry.getFlatCoordinates();
+ var stride = multiLineStringGeometry.getStride();
+ var offset = 0;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ offset = this.drawFlatCoordinates_(
+ flatCoordinates, offset, ends[i], stride);
+ }
+ this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]);
+ this.endGeometry(multiLineStringGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.LineStringReplay.prototype.finish = function() {
+ var state = this.state_;
+ goog.asserts.assert(state, 'state should not be null');
+ if (state.lastStroke != this.coordinates.length) {
+ this.instructions.push([ol.render.canvas.Instruction.STROKE]);
+ }
+ this.reverseHitDetectionInstructions_();
+ this.state_ = null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
+ goog.asserts.assert(this.state_, 'this.state_ should not be null');
+ goog.asserts.assert(!fillStyle, 'fillStyle should be null');
+ goog.asserts.assert(strokeStyle, 'strokeStyle should not be null');
+ var strokeStyleColor = strokeStyle.getColor();
+ this.state_.strokeStyle = ol.color.asString(strokeStyleColor ?
+ strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
+ var strokeStyleLineCap = strokeStyle.getLineCap();
+ this.state_.lineCap = strokeStyleLineCap !== undefined ?
+ strokeStyleLineCap : ol.render.canvas.defaultLineCap;
+ var strokeStyleLineDash = strokeStyle.getLineDash();
+ this.state_.lineDash = strokeStyleLineDash ?
+ strokeStyleLineDash : ol.render.canvas.defaultLineDash;
+ var strokeStyleLineJoin = strokeStyle.getLineJoin();
+ this.state_.lineJoin = strokeStyleLineJoin !== undefined ?
+ strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
+ var strokeStyleWidth = strokeStyle.getWidth();
+ this.state_.lineWidth = strokeStyleWidth !== undefined ?
+ strokeStyleWidth : ol.render.canvas.defaultLineWidth;
+ var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
+ this.state_.miterLimit = strokeStyleMiterLimit !== undefined ?
+ strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
+
+ if (this.state_.lineWidth > this.maxLineWidth) {
+ this.maxLineWidth = this.state_.lineWidth;
+ // invalidate the buffered max extent cache
+ this.bufferedMaxExtent_ = null;
+ }
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.render.canvas.Replay}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Maximum extent.
+ * @param {number} resolution Resolution.
+ * @protected
+ * @struct
+ */
+ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) {
+
+ ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
+
+ /**
+ * @private
+ * @type {{currentFillStyle: (ol.ColorLike|undefined),
+ * currentStrokeStyle: (string|undefined),
+ * currentLineCap: (string|undefined),
+ * currentLineDash: Array.<number>,
+ * currentLineJoin: (string|undefined),
+ * currentLineWidth: (number|undefined),
+ * currentMiterLimit: (number|undefined),
+ * fillStyle: (ol.ColorLike|undefined),
+ * strokeStyle: (string|undefined),
+ * lineCap: (string|undefined),
+ * lineDash: Array.<number>,
+ * lineJoin: (string|undefined),
+ * lineWidth: (number|undefined),
+ * miterLimit: (number|undefined)}|null}
+ */
+ this.state_ = {
+ currentFillStyle: undefined,
+ currentStrokeStyle: undefined,
+ currentLineCap: undefined,
+ currentLineDash: null,
+ currentLineJoin: undefined,
+ currentLineWidth: undefined,
+ currentMiterLimit: undefined,
+ fillStyle: undefined,
+ strokeStyle: undefined,
+ lineCap: undefined,
+ lineDash: null,
+ lineJoin: undefined,
+ lineWidth: undefined,
+ miterLimit: undefined
+ };
+
+};
+ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay);
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @private
+ * @return {number} End.
+ */
+ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) {
+ var state = this.state_;
+ var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];
+ this.instructions.push(beginPathInstruction);
+ this.hitDetectionInstructions.push(beginPathInstruction);
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ var myBegin = this.coordinates.length;
+ var myEnd = this.appendFlatCoordinates(
+ flatCoordinates, offset, end, stride, true);
+ var moveToLineToInstruction =
+ [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];
+ var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH];
+ this.instructions.push(moveToLineToInstruction, closePathInstruction);
+ this.hitDetectionInstructions.push(moveToLineToInstruction,
+ closePathInstruction);
+ offset = end;
+ }
+ // FIXME is it quicker to fill and stroke each polygon individually,
+ // FIXME or all polygons together?
+ var fillInstruction = [ol.render.canvas.Instruction.FILL];
+ this.hitDetectionInstructions.push(fillInstruction);
+ if (state.fillStyle !== undefined) {
+ this.instructions.push(fillInstruction);
+ }
+ if (state.strokeStyle !== undefined) {
+ goog.asserts.assert(state.lineWidth !== undefined,
+ 'state.lineWidth should be defined');
+ var strokeInstruction = [ol.render.canvas.Instruction.STROKE];
+ this.instructions.push(strokeInstruction);
+ this.hitDetectionInstructions.push(strokeInstruction);
+ }
+ return offset;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) {
+ var state = this.state_;
+ goog.asserts.assert(state, 'state should not be null');
+ var fillStyle = state.fillStyle;
+ var strokeStyle = state.strokeStyle;
+ if (fillStyle === undefined && strokeStyle === undefined) {
+ return;
+ }
+ if (strokeStyle !== undefined) {
+ goog.asserts.assert(state.lineWidth !== undefined,
+ 'state.lineWidth should be defined');
+ }
+ this.setFillStrokeStyles_();
+ this.beginGeometry(circleGeometry, feature);
+ // always fill the circle for hit detection
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_FILL_STYLE,
+ ol.color.asString(ol.render.canvas.defaultFillStyle)]);
+ if (state.strokeStyle !== undefined) {
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
+ state.miterLimit, state.lineDash]);
+ }
+ var flatCoordinates = circleGeometry.getFlatCoordinates();
+ var stride = circleGeometry.getStride();
+ var myBegin = this.coordinates.length;
+ this.appendFlatCoordinates(
+ flatCoordinates, 0, flatCoordinates.length, stride, false);
+ var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];
+ var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin];
+ this.instructions.push(beginPathInstruction, circleInstruction);
+ this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction);
+ var fillInstruction = [ol.render.canvas.Instruction.FILL];
+ this.hitDetectionInstructions.push(fillInstruction);
+ if (state.fillStyle !== undefined) {
+ this.instructions.push(fillInstruction);
+ }
+ if (state.strokeStyle !== undefined) {
+ goog.asserts.assert(state.lineWidth !== undefined,
+ 'state.lineWidth should be defined');
+ var strokeInstruction = [ol.render.canvas.Instruction.STROKE];
+ this.instructions.push(strokeInstruction);
+ this.hitDetectionInstructions.push(strokeInstruction);
+ }
+ this.endGeometry(circleGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {
+ var state = this.state_;
+ goog.asserts.assert(state, 'state should not be null');
+ var fillStyle = state.fillStyle;
+ var strokeStyle = state.strokeStyle;
+ if (fillStyle === undefined && strokeStyle === undefined) {
+ return;
+ }
+ if (strokeStyle !== undefined) {
+ goog.asserts.assert(state.lineWidth !== undefined,
+ 'state.lineWidth should be defined');
+ }
+ this.setFillStrokeStyles_();
+ this.beginGeometry(polygonGeometry, feature);
+ // always fill the polygon for hit detection
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_FILL_STYLE,
+ ol.color.asString(ol.render.canvas.defaultFillStyle)]);
+ if (state.strokeStyle !== undefined) {
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
+ state.miterLimit, state.lineDash]);
+ }
+ var ends = polygonGeometry.getEnds();
+ var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates();
+ var stride = polygonGeometry.getStride();
+ this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride);
+ this.endGeometry(polygonGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {
+ var state = this.state_;
+ goog.asserts.assert(state, 'state should not be null');
+ var fillStyle = state.fillStyle;
+ var strokeStyle = state.strokeStyle;
+ if (fillStyle === undefined && strokeStyle === undefined) {
+ return;
+ }
+ if (strokeStyle !== undefined) {
+ goog.asserts.assert(state.lineWidth !== undefined,
+ 'state.lineWidth should be defined');
+ }
+ this.setFillStrokeStyles_();
+ this.beginGeometry(multiPolygonGeometry, feature);
+ // always fill the multi-polygon for hit detection
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_FILL_STYLE,
+ ol.color.asString(ol.render.canvas.defaultFillStyle)]);
+ if (state.strokeStyle !== undefined) {
+ this.hitDetectionInstructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
+ state.miterLimit, state.lineDash]);
+ }
+ var endss = multiPolygonGeometry.getEndss();
+ var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates();
+ var stride = multiPolygonGeometry.getStride();
+ var offset = 0;
+ var i, ii;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ offset = this.drawFlatCoordinatess_(
+ flatCoordinates, offset, endss[i], stride);
+ }
+ this.endGeometry(multiPolygonGeometry, feature);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.PolygonReplay.prototype.finish = function() {
+ goog.asserts.assert(this.state_, 'this.state_ should not be null');
+ this.reverseHitDetectionInstructions_();
+ this.state_ = null;
+ // We want to preserve topology when drawing polygons. Polygons are
+ // simplified using quantization and point elimination. However, we might
+ // have received a mix of quantized and non-quantized geometries, so ensure
+ // that all are quantized by quantizing all coordinates in the batch.
+ var tolerance = this.tolerance;
+ if (tolerance !== 0) {
+ var coordinates = this.coordinates;
+ var i, ii;
+ for (i = 0, ii = coordinates.length; i < ii; ++i) {
+ coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance);
+ }
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() {
+ if (!this.bufferedMaxExtent_) {
+ this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
+ if (this.maxLineWidth > 0) {
+ var width = this.resolution * (this.maxLineWidth + 1) / 2;
+ ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
+ }
+ }
+ return this.bufferedMaxExtent_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
+ goog.asserts.assert(this.state_, 'this.state_ should not be null');
+ goog.asserts.assert(fillStyle || strokeStyle,
+ 'fillStyle or strokeStyle should not be null');
+ var state = this.state_;
+ if (fillStyle) {
+ var fillStyleColor = fillStyle.getColor();
+ state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
+ fillStyleColor : ol.render.canvas.defaultFillStyle);
+ } else {
+ state.fillStyle = undefined;
+ }
+ if (strokeStyle) {
+ var strokeStyleColor = strokeStyle.getColor();
+ state.strokeStyle = ol.color.asString(strokeStyleColor ?
+ strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
+ var strokeStyleLineCap = strokeStyle.getLineCap();
+ state.lineCap = strokeStyleLineCap !== undefined ?
+ strokeStyleLineCap : ol.render.canvas.defaultLineCap;
+ var strokeStyleLineDash = strokeStyle.getLineDash();
+ state.lineDash = strokeStyleLineDash ?
+ strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
+ var strokeStyleLineJoin = strokeStyle.getLineJoin();
+ state.lineJoin = strokeStyleLineJoin !== undefined ?
+ strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
+ var strokeStyleWidth = strokeStyle.getWidth();
+ state.lineWidth = strokeStyleWidth !== undefined ?
+ strokeStyleWidth : ol.render.canvas.defaultLineWidth;
+ var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
+ state.miterLimit = strokeStyleMiterLimit !== undefined ?
+ strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
+
+ if (state.lineWidth > this.maxLineWidth) {
+ this.maxLineWidth = state.lineWidth;
+ // invalidate the buffered max extent cache
+ this.bufferedMaxExtent_ = null;
+ }
+ } else {
+ state.strokeStyle = undefined;
+ state.lineCap = undefined;
+ state.lineDash = null;
+ state.lineJoin = undefined;
+ state.lineWidth = undefined;
+ state.miterLimit = undefined;
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() {
+ var state = this.state_;
+ var fillStyle = state.fillStyle;
+ var strokeStyle = state.strokeStyle;
+ var lineCap = state.lineCap;
+ var lineDash = state.lineDash;
+ var lineJoin = state.lineJoin;
+ var lineWidth = state.lineWidth;
+ var miterLimit = state.miterLimit;
+ if (fillStyle !== undefined && state.currentFillStyle != fillStyle) {
+ this.instructions.push(
+ [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle]);
+ state.currentFillStyle = state.fillStyle;
+ }
+ if (strokeStyle !== undefined) {
+ goog.asserts.assert(lineCap !== undefined, 'lineCap should be defined');
+ goog.asserts.assert(lineDash, 'lineDash should not be null');
+ goog.asserts.assert(lineJoin !== undefined, 'lineJoin should be defined');
+ goog.asserts.assert(lineWidth !== undefined, 'lineWidth should be defined');
+ goog.asserts.assert(miterLimit !== undefined,
+ 'miterLimit should be defined');
+ if (state.currentStrokeStyle != strokeStyle ||
+ state.currentLineCap != lineCap ||
+ state.currentLineDash != lineDash ||
+ state.currentLineJoin != lineJoin ||
+ state.currentLineWidth != lineWidth ||
+ state.currentMiterLimit != miterLimit) {
+ this.instructions.push(
+ [ol.render.canvas.Instruction.SET_STROKE_STYLE,
+ strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash]);
+ state.currentStrokeStyle = strokeStyle;
+ state.currentLineCap = lineCap;
+ state.currentLineDash = lineDash;
+ state.currentLineJoin = lineJoin;
+ state.currentLineWidth = lineWidth;
+ state.currentMiterLimit = miterLimit;
+ }
+ }
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.render.canvas.Replay}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Maximum extent.
+ * @param {number} resolution Resolution.
+ * @protected
+ * @struct
+ */
+ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution) {
+
+ ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
+
+ /**
+ * @private
+ * @type {?ol.CanvasFillState}
+ */
+ this.replayFillState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasStrokeState}
+ */
+ this.replayStrokeState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasTextState}
+ */
+ this.replayTextState_ = null;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.text_ = '';
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textOffsetX_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textOffsetY_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textRotation_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textScale_ = 0;
+
+ /**
+ * @private
+ * @type {?ol.CanvasFillState}
+ */
+ this.textFillState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasStrokeState}
+ */
+ this.textStrokeState_ = null;
+
+ /**
+ * @private
+ * @type {?ol.CanvasTextState}
+ */
+ this.textState_ = null;
+
+};
+ol.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay);
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {
+ if (this.text_ === '' || !this.textState_ ||
+ (!this.textFillState_ && !this.textStrokeState_)) {
+ return;
+ }
+ if (this.textFillState_) {
+ this.setReplayFillState_(this.textFillState_);
+ }
+ if (this.textStrokeState_) {
+ this.setReplayStrokeState_(this.textStrokeState_);
+ }
+ this.setReplayTextState_(this.textState_);
+ this.beginGeometry(geometry, feature);
+ var myBegin = this.coordinates.length;
+ var myEnd =
+ this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false);
+ var fill = !!this.textFillState_;
+ var stroke = !!this.textStrokeState_;
+ var drawTextInstruction = [
+ ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_,
+ this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_,
+ fill, stroke];
+ this.instructions.push(drawTextInstruction);
+ this.hitDetectionInstructions.push(drawTextInstruction);
+ this.endGeometry(geometry, feature);
+};
+
+
+/**
+ * @param {ol.CanvasFillState} fillState Fill state.
+ * @private
+ */
+ol.render.canvas.TextReplay.prototype.setReplayFillState_ = function(fillState) {
+ var replayFillState = this.replayFillState_;
+ if (replayFillState &&
+ replayFillState.fillStyle == fillState.fillStyle) {
+ return;
+ }
+ var setFillStyleInstruction =
+ [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle];
+ this.instructions.push(setFillStyleInstruction);
+ this.hitDetectionInstructions.push(setFillStyleInstruction);
+ if (!replayFillState) {
+ this.replayFillState_ = {
+ fillStyle: fillState.fillStyle
+ };
+ } else {
+ replayFillState.fillStyle = fillState.fillStyle;
+ }
+};
+
+
+/**
+ * @param {ol.CanvasStrokeState} strokeState Stroke state.
+ * @private
+ */
+ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = function(strokeState) {
+ var replayStrokeState = this.replayStrokeState_;
+ if (replayStrokeState &&
+ replayStrokeState.lineCap == strokeState.lineCap &&
+ replayStrokeState.lineDash == strokeState.lineDash &&
+ replayStrokeState.lineJoin == strokeState.lineJoin &&
+ replayStrokeState.lineWidth == strokeState.lineWidth &&
+ replayStrokeState.miterLimit == strokeState.miterLimit &&
+ replayStrokeState.strokeStyle == strokeState.strokeStyle) {
+ return;
+ }
+ var setStrokeStyleInstruction = [
+ ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle,
+ strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin,
+ strokeState.miterLimit, strokeState.lineDash, false
+ ];
+ this.instructions.push(setStrokeStyleInstruction);
+ this.hitDetectionInstructions.push(setStrokeStyleInstruction);
+ if (!replayStrokeState) {
+ this.replayStrokeState_ = {
+ lineCap: strokeState.lineCap,
+ lineDash: strokeState.lineDash,
+ lineJoin: strokeState.lineJoin,
+ lineWidth: strokeState.lineWidth,
+ miterLimit: strokeState.miterLimit,
+ strokeStyle: strokeState.strokeStyle
+ };
+ } else {
+ replayStrokeState.lineCap = strokeState.lineCap;
+ replayStrokeState.lineDash = strokeState.lineDash;
+ replayStrokeState.lineJoin = strokeState.lineJoin;
+ replayStrokeState.lineWidth = strokeState.lineWidth;
+ replayStrokeState.miterLimit = strokeState.miterLimit;
+ replayStrokeState.strokeStyle = strokeState.strokeStyle;
+ }
+};
+
+
+/**
+ * @param {ol.CanvasTextState} textState Text state.
+ * @private
+ */
+ol.render.canvas.TextReplay.prototype.setReplayTextState_ = function(textState) {
+ var replayTextState = this.replayTextState_;
+ if (replayTextState &&
+ replayTextState.font == textState.font &&
+ replayTextState.textAlign == textState.textAlign &&
+ replayTextState.textBaseline == textState.textBaseline) {
+ return;
+ }
+ var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE,
+ textState.font, textState.textAlign, textState.textBaseline];
+ this.instructions.push(setTextStyleInstruction);
+ this.hitDetectionInstructions.push(setTextStyleInstruction);
+ if (!replayTextState) {
+ this.replayTextState_ = {
+ font: textState.font,
+ textAlign: textState.textAlign,
+ textBaseline: textState.textBaseline
+ };
+ } else {
+ replayTextState.font = textState.font;
+ replayTextState.textAlign = textState.textAlign;
+ replayTextState.textBaseline = textState.textBaseline;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
+ if (!textStyle) {
+ this.text_ = '';
+ } else {
+ var textFillStyle = textStyle.getFill();
+ if (!textFillStyle) {
+ this.textFillState_ = null;
+ } else {
+ var textFillStyleColor = textFillStyle.getColor();
+ var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ?
+ textFillStyleColor : ol.render.canvas.defaultFillStyle);
+ if (!this.textFillState_) {
+ this.textFillState_ = {
+ fillStyle: fillStyle
+ };
+ } else {
+ var textFillState = this.textFillState_;
+ textFillState.fillStyle = fillStyle;
+ }
+ }
+ var textStrokeStyle = textStyle.getStroke();
+ if (!textStrokeStyle) {
+ this.textStrokeState_ = null;
+ } else {
+ var textStrokeStyleColor = textStrokeStyle.getColor();
+ var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
+ var textStrokeStyleLineDash = textStrokeStyle.getLineDash();
+ var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();
+ var textStrokeStyleWidth = textStrokeStyle.getWidth();
+ var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
+ var lineCap = textStrokeStyleLineCap !== undefined ?
+ textStrokeStyleLineCap : ol.render.canvas.defaultLineCap;
+ var lineDash = textStrokeStyleLineDash ?
+ textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
+ var lineJoin = textStrokeStyleLineJoin !== undefined ?
+ textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
+ var lineWidth = textStrokeStyleWidth !== undefined ?
+ textStrokeStyleWidth : ol.render.canvas.defaultLineWidth;
+ var miterLimit = textStrokeStyleMiterLimit !== undefined ?
+ textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
+ var strokeStyle = ol.color.asString(textStrokeStyleColor ?
+ textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle);
+ if (!this.textStrokeState_) {
+ this.textStrokeState_ = {
+ lineCap: lineCap,
+ lineDash: lineDash,
+ lineJoin: lineJoin,
+ lineWidth: lineWidth,
+ miterLimit: miterLimit,
+ strokeStyle: strokeStyle
+ };
+ } else {
+ var textStrokeState = this.textStrokeState_;
+ textStrokeState.lineCap = lineCap;
+ textStrokeState.lineDash = lineDash;
+ textStrokeState.lineJoin = lineJoin;
+ textStrokeState.lineWidth = lineWidth;
+ textStrokeState.miterLimit = miterLimit;
+ textStrokeState.strokeStyle = strokeStyle;
+ }
+ }
+ var textFont = textStyle.getFont();
+ var textOffsetX = textStyle.getOffsetX();
+ var textOffsetY = textStyle.getOffsetY();
+ var textRotation = textStyle.getRotation();
+ var textScale = textStyle.getScale();
+ var textText = textStyle.getText();
+ var textTextAlign = textStyle.getTextAlign();
+ var textTextBaseline = textStyle.getTextBaseline();
+ var font = textFont !== undefined ?
+ textFont : ol.render.canvas.defaultFont;
+ var textAlign = textTextAlign !== undefined ?
+ textTextAlign : ol.render.canvas.defaultTextAlign;
+ var textBaseline = textTextBaseline !== undefined ?
+ textTextBaseline : ol.render.canvas.defaultTextBaseline;
+ if (!this.textState_) {
+ this.textState_ = {
+ font: font,
+ textAlign: textAlign,
+ textBaseline: textBaseline
+ };
+ } else {
+ var textState = this.textState_;
+ textState.font = font;
+ textState.textAlign = textAlign;
+ textState.textBaseline = textBaseline;
+ }
+ this.text_ = textText !== undefined ? textText : '';
+ this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0;
+ this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0;
+ this.textRotation_ = textRotation !== undefined ? textRotation : 0;
+ this.textScale_ = textScale !== undefined ? textScale : 1;
+ }
+};
+
+
+/**
+ * @constructor
+ * @implements {ol.render.IReplayGroup}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Max extent.
+ * @param {number} resolution Resolution.
+ * @param {number=} opt_renderBuffer Optional rendering buffer.
+ * @struct
+ */
+ol.render.canvas.ReplayGroup = function(
+ tolerance, maxExtent, resolution, opt_renderBuffer) {
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.tolerance_ = tolerance;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.maxExtent_ = maxExtent;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.resolution_ = resolution;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.renderBuffer_ = opt_renderBuffer;
+
+ /**
+ * @private
+ * @type {!Object.<string,
+ * Object.<ol.render.ReplayType, ol.render.canvas.Replay>>}
+ */
+ this.replaysByZIndex_ = {};
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1);
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.hitDetectionTransform_ = goog.vec.Mat4.createNumber();
+
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.render.canvas.ReplayGroup.prototype.finish = function() {
+ var zKey;
+ for (zKey in this.replaysByZIndex_) {
+ var replays = this.replaysByZIndex_[zKey];
+ var replayKey;
+ for (replayKey in replays) {
+ replays[replayKey].finish();
+ }
+ }
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature
+ * callback.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
+ coordinate, resolution, rotation, skippedFeaturesHash, callback) {
+
+ var transform = this.hitDetectionTransform_;
+ ol.vec.Mat4.makeTransform2D(transform, 0.5, 0.5,
+ 1 / resolution, -1 / resolution, -rotation,
+ -coordinate[0], -coordinate[1]);
+
+ var context = this.hitDetectionContext_;
+ context.clearRect(0, 0, 1, 1);
+
+ /**
+ * @type {ol.Extent}
+ */
+ var hitExtent;
+ if (this.renderBuffer_ !== undefined) {
+ hitExtent = ol.extent.createEmpty();
+ ol.extent.extendCoordinate(hitExtent, coordinate);
+ ol.extent.buffer(hitExtent, resolution * this.renderBuffer_, hitExtent);
+ }
+
+ return this.replayHitDetection_(context, transform, rotation,
+ skippedFeaturesHash,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ var imageData = context.getImageData(0, 0, 1, 1).data;
+ if (imageData[3] > 0) {
+ var result = callback(feature);
+ if (result) {
+ return result;
+ }
+ context.clearRect(0, 0, 1, 1);
+ }
+ }, hitExtent);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
+ var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
+ var replays = this.replaysByZIndex_[zIndexKey];
+ if (replays === undefined) {
+ replays = {};
+ this.replaysByZIndex_[zIndexKey] = replays;
+ }
+ var replay = replays[replayType];
+ if (replay === undefined) {
+ var Constructor = ol.render.canvas.BATCH_CONSTRUCTORS_[replayType];
+ goog.asserts.assert(Constructor !== undefined,
+ replayType +
+ ' constructor missing from ol.render.canvas.BATCH_CONSTRUCTORS_');
+ replay = new Constructor(this.tolerance_, this.maxExtent_,
+ this.resolution_);
+ replays[replayType] = replay;
+ }
+ return replay;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.canvas.ReplayGroup.prototype.isEmpty = function() {
+ return ol.object.isEmpty(this.replaysByZIndex_);
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {number} viewRotation View rotation.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {Array.<ol.render.ReplayType>=} opt_replayTypes Ordered replay types
+ * to replay. Default is {@link ol.render.REPLAY_ORDER}
+ */
+ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio,
+ transform, viewRotation, skippedFeaturesHash, opt_replayTypes) {
+
+ /** @type {Array.<number>} */
+ var zs = Object.keys(this.replaysByZIndex_).map(Number);
+ zs.sort(ol.array.numberSafeCompareFunction);
+
+ // setup clipping so that the parts of over-simplified geometries are not
+ // visible outside the current extent when panning
+ var maxExtent = this.maxExtent_;
+ var minX = maxExtent[0];
+ var minY = maxExtent[1];
+ var maxX = maxExtent[2];
+ var maxY = maxExtent[3];
+ var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];
+ ol.geom.flat.transform.transform2D(
+ flatClipCoords, 0, 8, 2, transform, flatClipCoords);
+ context.save();
+ context.beginPath();
+ context.moveTo(flatClipCoords[0], flatClipCoords[1]);
+ context.lineTo(flatClipCoords[2], flatClipCoords[3]);
+ context.lineTo(flatClipCoords[4], flatClipCoords[5]);
+ context.lineTo(flatClipCoords[6], flatClipCoords[7]);
+ context.closePath();
+ context.clip();
+
+ var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.REPLAY_ORDER;
+ var i, ii, j, jj, replays, replay;
+ for (i = 0, ii = zs.length; i < ii; ++i) {
+ replays = this.replaysByZIndex_[zs[i].toString()];
+ for (j = 0, jj = replayTypes.length; j < jj; ++j) {
+ replay = replays[replayTypes[j]];
+ if (replay !== undefined) {
+ replay.replay(context, pixelRatio, transform, viewRotation,
+ skippedFeaturesHash);
+ }
+ }
+ }
+
+ context.restore();
+};
+
+
+/**
+ * @private
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @param {number} viewRotation View rotation.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback
+ * Feature callback.
+ * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
+ * extent.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
+ context, transform, viewRotation, skippedFeaturesHash,
+ featureCallback, opt_hitExtent) {
+ /** @type {Array.<number>} */
+ var zs = Object.keys(this.replaysByZIndex_).map(Number);
+ zs.sort(function(a, b) {
+ return b - a;
+ });
+
+ var i, ii, j, replays, replay, result;
+ for (i = 0, ii = zs.length; i < ii; ++i) {
+ replays = this.replaysByZIndex_[zs[i].toString()];
+ for (j = ol.render.REPLAY_ORDER.length - 1; j >= 0; --j) {
+ replay = replays[ol.render.REPLAY_ORDER[j]];
+ if (replay !== undefined) {
+ result = replay.replayHitDetection(context, transform, viewRotation,
+ skippedFeaturesHash, featureCallback, opt_hitExtent);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<ol.render.ReplayType,
+ * function(new: ol.render.canvas.Replay, number, ol.Extent,
+ * number)>}
+ */
+ol.render.canvas.BATCH_CONSTRUCTORS_ = {
+ 'Image': ol.render.canvas.ImageReplay,
+ 'LineString': ol.render.canvas.LineStringReplay,
+ 'Polygon': ol.render.canvas.PolygonReplay,
+ 'Text': ol.render.canvas.TextReplay
+};
+
+goog.provide('ol.render.Feature');
+
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryType');
+
+
+/**
+ * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like
+ * structure, optimized for rendering and styling. Geometry access through the
+ * API is limited to getting the type and extent of the geometry.
+ *
+ * @constructor
+ * @param {ol.geom.GeometryType} type Geometry type.
+ * @param {Array.<number>} flatCoordinates Flat coordinates. These always need
+ * to be right-handed for polygons.
+ * @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss.
+ * @param {Object.<string, *>} properties Properties.
+ */
+ol.render.Feature = function(type, flatCoordinates, ends, properties) {
+
+ /**
+ * @private
+ * @type {ol.Extent|undefined}
+ */
+ this.extent_;
+
+ goog.asserts.assert(type === ol.geom.GeometryType.POINT ||
+ type === ol.geom.GeometryType.MULTI_POINT ||
+ type === ol.geom.GeometryType.LINE_STRING ||
+ type === ol.geom.GeometryType.MULTI_LINE_STRING ||
+ type === ol.geom.GeometryType.POLYGON,
+ 'Need a Point, MultiPoint, LineString, MultiLineString or Polygon type');
+
+ /**
+ * @private
+ * @type {ol.geom.GeometryType}
+ */
+ this.type_ = type;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.flatCoordinates_ = flatCoordinates;
+
+ /**
+ * @private
+ * @type {Array.<number>|Array.<Array.<number>>}
+ */
+ this.ends_ = ends;
+
+ /**
+ * @private
+ * @type {Object.<string, *>}
+ */
+ this.properties_ = properties;
+
+};
+
+
+/**
+ * Get a feature property by its key.
+ * @param {string} key Key
+ * @return {*} Value for the requested key.
+ * @api
+ */
+ol.render.Feature.prototype.get = function(key) {
+ return this.properties_[key];
+};
+
+
+/**
+ * @return {Array.<number>|Array.<Array.<number>>} Ends or endss.
+ */
+ol.render.Feature.prototype.getEnds = function() {
+ return this.ends_;
+};
+
+
+/**
+ * Get the extent of this feature's geometry.
+ * @return {ol.Extent} Extent.
+ * @api
+ */
+ol.render.Feature.prototype.getExtent = function() {
+ if (!this.extent_) {
+ this.extent_ = this.type_ === ol.geom.GeometryType.POINT ?
+ ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) :
+ ol.extent.createOrUpdateFromFlatCoordinates(
+ this.flatCoordinates_, 0, this.flatCoordinates_.length, 2);
+
+ }
+ return this.extent_;
+};
+
+
+/**
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.render.Feature.prototype.getOrientedFlatCoordinates = function() {
+ return this.flatCoordinates_;
+};
+
+
+/**
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.render.Feature.prototype.getFlatCoordinates =
+ ol.render.Feature.prototype.getOrientedFlatCoordinates;
+
+
+/**
+ * Get the feature for working with its geometry.
+ * @return {ol.render.Feature} Feature.
+ * @api
+ */
+ol.render.Feature.prototype.getGeometry = function() {
+ return this;
+};
+
+
+/**
+ * Get the feature properties.
+ * @return {Object.<string, *>} Feature properties.
+ * @api
+ */
+ol.render.Feature.prototype.getProperties = function() {
+ return this.properties_;
+};
+
+
+/**
+ * Get the feature for working with its geometry.
+ * @return {ol.render.Feature} Feature.
+ */
+ol.render.Feature.prototype.getSimplifiedGeometry =
+ ol.render.Feature.prototype.getGeometry;
+
+
+/**
+ * @return {number} Stride.
+ */
+ol.render.Feature.prototype.getStride = function() {
+ return 2;
+};
+
+
+/**
+ * @return {undefined}
+ */
+ol.render.Feature.prototype.getStyleFunction = ol.nullFunction;
+
+
+/**
+ * Get the type of this feature's geometry.
+ * @return {ol.geom.GeometryType} Geometry type.
+ * @api
+ */
+ol.render.Feature.prototype.getType = function() {
+ return this.type_;
+};
+
+goog.provide('ol.renderer.vector');
+
+goog.require('goog.asserts');
+goog.require('ol.render.Feature');
+goog.require('ol.render.IReplayGroup');
+goog.require('ol.style.ImageState');
+goog.require('ol.style.Style');
+
+
+/**
+ * @param {ol.Feature|ol.render.Feature} feature1 Feature 1.
+ * @param {ol.Feature|ol.render.Feature} feature2 Feature 2.
+ * @return {number} Order.
+ */
+ol.renderer.vector.defaultOrder = function(feature1, feature2) {
+ return goog.getUid(feature1) - goog.getUid(feature2);
+};
+
+
+/**
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {number} Squared pixel tolerance.
+ */
+ol.renderer.vector.getSquaredTolerance = function(resolution, pixelRatio) {
+ var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);
+ return tolerance * tolerance;
+};
+
+
+/**
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @return {number} Pixel tolerance.
+ */
+ol.renderer.vector.getTolerance = function(resolution, pixelRatio) {
+ return ol.SIMPLIFY_TOLERANCE * resolution / pixelRatio;
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.Circle} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style, feature) {
+ var fillStyle = style.getFill();
+ var strokeStyle = style.getStroke();
+ if (fillStyle || strokeStyle) {
+ var polygonReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.POLYGON);
+ polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
+ polygonReplay.drawCircle(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {ol.style.Style} style Style.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {function(this: T, ol.events.Event)} listener Listener function.
+ * @param {T} thisArg Value to use as `this` when executing `listener`.
+ * @return {boolean} `true` if style is loading.
+ * @template T
+ */
+ol.renderer.vector.renderFeature = function(
+ replayGroup, feature, style, squaredTolerance, listener, thisArg) {
+ var loading = false;
+ var imageStyle, imageState;
+ imageStyle = style.getImage();
+ if (imageStyle) {
+ imageState = imageStyle.getImageState();
+ if (imageState == ol.style.ImageState.LOADED ||
+ imageState == ol.style.ImageState.ERROR) {
+ imageStyle.unlistenImageChange(listener, thisArg);
+ } else {
+ if (imageState == ol.style.ImageState.IDLE) {
+ imageStyle.load();
+ }
+ imageState = imageStyle.getImageState();
+ goog.asserts.assert(imageState == ol.style.ImageState.LOADING,
+ 'imageState should be LOADING');
+ imageStyle.listenImageChange(listener, thisArg);
+ loading = true;
+ }
+ }
+ ol.renderer.vector.renderFeature_(replayGroup, feature, style,
+ squaredTolerance);
+ return loading;
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {ol.style.Style} style Style.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @private
+ */
+ol.renderer.vector.renderFeature_ = function(
+ replayGroup, feature, style, squaredTolerance) {
+ var geometry = style.getGeometryFunction()(feature);
+ if (!geometry) {
+ return;
+ }
+ var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
+ var geometryRenderer =
+ ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()];
+ goog.asserts.assert(geometryRenderer !== undefined,
+ 'geometryRenderer should be defined');
+ geometryRenderer(replayGroup, simplifiedGeometry, style, feature);
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.GeometryCollection} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderGeometryCollectionGeometry_ = function(replayGroup, geometry, style, feature) {
+ var geometries = geometry.getGeometriesArray();
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ var geometryRenderer =
+ ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()];
+ goog.asserts.assert(geometryRenderer !== undefined,
+ 'geometryRenderer should be defined');
+ geometryRenderer(replayGroup, geometries[i], style, feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.LineString|ol.render.Feature} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, style, feature) {
+ var strokeStyle = style.getStroke();
+ if (strokeStyle) {
+ var lineStringReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.LINE_STRING);
+ lineStringReplay.setFillStrokeStyle(null, strokeStyle);
+ lineStringReplay.drawLineString(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.MultiLineString|ol.render.Feature} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geometry, style, feature) {
+ var strokeStyle = style.getStroke();
+ if (strokeStyle) {
+ var lineStringReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.LINE_STRING);
+ lineStringReplay.setFillStrokeStyle(null, strokeStyle);
+ lineStringReplay.drawMultiLineString(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ var flatMidpointCoordinates = geometry.getFlatMidpoints();
+ textReplay.drawText(flatMidpointCoordinates, 0,
+ flatMidpointCoordinates.length, 2, geometry, feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.MultiPolygon} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderMultiPolygonGeometry_ = function(replayGroup, geometry, style, feature) {
+ var fillStyle = style.getFill();
+ var strokeStyle = style.getStroke();
+ if (strokeStyle || fillStyle) {
+ var polygonReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.POLYGON);
+ polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
+ polygonReplay.drawMultiPolygon(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints();
+ textReplay.drawText(flatInteriorPointCoordinates, 0,
+ flatInteriorPointCoordinates.length, 2, geometry, feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.Point|ol.render.Feature} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style, feature) {
+ var imageStyle = style.getImage();
+ if (imageStyle) {
+ if (imageStyle.getImageState() != ol.style.ImageState.LOADED) {
+ return;
+ }
+ var imageReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.IMAGE);
+ imageReplay.setImageStyle(imageStyle);
+ imageReplay.drawPoint(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry,
+ feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.MultiPoint|ol.render.Feature} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, style, feature) {
+ var imageStyle = style.getImage();
+ if (imageStyle) {
+ if (imageStyle.getImageState() != ol.style.ImageState.LOADED) {
+ return;
+ }
+ var imageReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.IMAGE);
+ imageReplay.setImageStyle(imageStyle);
+ imageReplay.drawMultiPoint(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ var flatCoordinates = geometry.getFlatCoordinates();
+ textReplay.drawText(flatCoordinates, 0, flatCoordinates.length,
+ geometry.getStride(), geometry, feature);
+ }
+};
+
+
+/**
+ * @param {ol.render.IReplayGroup} replayGroup Replay group.
+ * @param {ol.geom.Polygon|ol.render.Feature} geometry Geometry.
+ * @param {ol.style.Style} style Style.
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @private
+ */
+ol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, style, feature) {
+ var fillStyle = style.getFill();
+ var strokeStyle = style.getStroke();
+ if (fillStyle || strokeStyle) {
+ var polygonReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.POLYGON);
+ polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
+ polygonReplay.drawPolygon(geometry, feature);
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ var textReplay = replayGroup.getReplay(
+ style.getZIndex(), ol.render.ReplayType.TEXT);
+ textReplay.setTextStyle(textStyle);
+ textReplay.drawText(
+ geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature);
+ }
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<ol.geom.GeometryType,
+ * function(ol.render.IReplayGroup, ol.geom.Geometry,
+ * ol.style.Style, Object)>}
+ */
+ol.renderer.vector.GEOMETRY_RENDERERS_ = {
+ 'Point': ol.renderer.vector.renderPointGeometry_,
+ 'LineString': ol.renderer.vector.renderLineStringGeometry_,
+ 'Polygon': ol.renderer.vector.renderPolygonGeometry_,
+ 'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_,
+ 'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_,
+ 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_,
+ 'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_,
+ 'Circle': ol.renderer.vector.renderCircleGeometry_
+};
+
+goog.provide('ol.ImageCanvas');
+
+goog.require('goog.asserts');
+goog.require('ol.ImageBase');
+goog.require('ol.ImageState');
+
+
+/**
+ * @constructor
+ * @extends {ol.ImageBase}
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {Array.<ol.Attribution>} attributions Attributions.
+ * @param {HTMLCanvasElement} canvas Canvas.
+ * @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to
+ * support asynchronous canvas drawing.
+ */
+ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,
+ canvas, opt_loader) {
+
+ /**
+ * Optional canvas loader function.
+ * @type {?ol.ImageCanvasLoader}
+ * @private
+ */
+ this.loader_ = opt_loader !== undefined ? opt_loader : null;
+
+ var state = opt_loader !== undefined ?
+ ol.ImageState.IDLE : ol.ImageState.LOADED;
+
+ ol.ImageBase.call(this, extent, resolution, pixelRatio, state, attributions);
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = canvas;
+
+ /**
+ * @private
+ * @type {Error}
+ */
+ this.error_ = null;
+
+};
+ol.inherits(ol.ImageCanvas, ol.ImageBase);
+
+
+/**
+ * Get any error associated with asynchronous rendering.
+ * @return {Error} Any error that occurred during rendering.
+ */
+ol.ImageCanvas.prototype.getError = function() {
+ return this.error_;
+};
+
+
+/**
+ * Handle async drawing complete.
+ * @param {Error} err Any error during drawing.
+ * @private
+ */
+ol.ImageCanvas.prototype.handleLoad_ = function(err) {
+ if (err) {
+ this.error_ = err;
+ this.state = ol.ImageState.ERROR;
+ } else {
+ this.state = ol.ImageState.LOADED;
+ }
+ this.changed();
+};
+
+
+/**
+ * Trigger drawing on canvas.
+ */
+ol.ImageCanvas.prototype.load = function() {
+ if (this.state == ol.ImageState.IDLE) {
+ goog.asserts.assert(this.loader_, 'this.loader_ must be set');
+ this.state = ol.ImageState.LOADING;
+ this.changed();
+ this.loader_(this.handleLoad_.bind(this));
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.ImageCanvas.prototype.getImage = function(opt_context) {
+ return this.canvas_;
+};
+
+goog.provide('ol.reproj');
+
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.math');
+goog.require('ol.proj');
+
+
+/**
+ * We need to employ more sophisticated solution
+ * if the web browser antialiases clipping edges on canvas.
+ *
+ * Currently only Chrome does not antialias the edges, but this is probably
+ * going to be "fixed" in the future: http://crbug.com/424291
+ *
+ * @type {boolean}
+ * @private
+ */
+ol.reproj.browserAntialiasesClip_ = (function(winNav, winChrome) {
+ // Adapted from http://stackoverflow.com/questions/4565112/javascript-how-to-find-out-if-the-user-browser-is-chrome
+ var isOpera = winNav.userAgent.indexOf('OPR') > -1;
+ var isIEedge = winNav.userAgent.indexOf('Edge') > -1;
+ return !(
+ !winNav.userAgent.match('CriOS') && // Not Chrome on iOS
+ winChrome !== null && winChrome !== undefined && // Has chrome in window
+ winNav.vendor === 'Google Inc.' && // Vendor is Google.
+ isOpera == false && // Not Opera
+ isIEedge == false // Not Edge
+ );
+})(ol.global.navigator, ol.global.chrome);
+
+
+/**
+ * Calculates ideal resolution to use from the source in order to achieve
+ * pixel mapping as close as possible to 1:1 during reprojection.
+ * The resolution is calculated regardless of what resolutions
+ * are actually available in the dataset (TileGrid, Image, ...).
+ *
+ * @param {ol.proj.Projection} sourceProj Source projection.
+ * @param {ol.proj.Projection} targetProj Target projection.
+ * @param {ol.Coordinate} targetCenter Target center.
+ * @param {number} targetResolution Target resolution.
+ * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0.
+ */
+ol.reproj.calculateSourceResolution = function(sourceProj, targetProj,
+ targetCenter, targetResolution) {
+
+ var sourceCenter = ol.proj.transform(targetCenter, targetProj, sourceProj);
+
+ // calculate the ideal resolution of the source data
+ var sourceResolution =
+ targetProj.getPointResolution(targetResolution, targetCenter);
+
+ var targetMetersPerUnit = targetProj.getMetersPerUnit();
+ if (targetMetersPerUnit !== undefined) {
+ sourceResolution *= targetMetersPerUnit;
+ }
+ var sourceMetersPerUnit = sourceProj.getMetersPerUnit();
+ if (sourceMetersPerUnit !== undefined) {
+ sourceResolution /= sourceMetersPerUnit;
+ }
+
+ // Based on the projection properties, the point resolution at the specified
+ // coordinates may be slightly different. We need to reverse-compensate this
+ // in order to achieve optimal results.
+
+ var compensationFactor =
+ sourceProj.getPointResolution(sourceResolution, sourceCenter) /
+ sourceResolution;
+
+ if (isFinite(compensationFactor) && compensationFactor > 0) {
+ sourceResolution /= compensationFactor;
+ }
+
+ return sourceResolution;
+};
+
+
+/**
+ * Enlarge the clipping triangle point by 1 pixel to ensure the edges overlap
+ * in order to mask gaps caused by antialiasing.
+ *
+ * @param {number} centroidX Centroid of the triangle (x coordinate in pixels).
+ * @param {number} centroidY Centroid of the triangle (y coordinate in pixels).
+ * @param {number} x X coordinate of the point (in pixels).
+ * @param {number} y Y coordinate of the point (in pixels).
+ * @return {ol.Coordinate} New point 1 px farther from the centroid.
+ * @private
+ */
+ol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) {
+ var dX = x - centroidX, dY = y - centroidY;
+ var distance = Math.sqrt(dX * dX + dY * dY);
+ return [Math.round(x + dX / distance), Math.round(y + dY / distance)];
+};
+
+
+/**
+ * Renders the source data into new canvas based on the triangulation.
+ *
+ * @param {number} width Width of the canvas.
+ * @param {number} height Height of the canvas.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} sourceResolution Source resolution.
+ * @param {ol.Extent} sourceExtent Extent of the data source.
+ * @param {number} targetResolution Target resolution.
+ * @param {ol.Extent} targetExtent Target extent.
+ * @param {ol.reproj.Triangulation} triangulation Calculated triangulation.
+ * @param {Array.<{extent: ol.Extent,
+ * image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources
+ * Array of sources.
+ * @param {number} gutter Gutter of the sources.
+ * @param {boolean=} opt_renderEdges Render reprojection edges.
+ * @return {HTMLCanvasElement} Canvas with reprojected data.
+ */
+ol.reproj.render = function(width, height, pixelRatio,
+ sourceResolution, sourceExtent, targetResolution, targetExtent,
+ triangulation, sources, gutter, opt_renderEdges) {
+
+ var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width),
+ Math.round(pixelRatio * height));
+
+ if (sources.length === 0) {
+ return context.canvas;
+ }
+
+ context.scale(pixelRatio, pixelRatio);
+
+ var sourceDataExtent = ol.extent.createEmpty();
+ sources.forEach(function(src, i, arr) {
+ ol.extent.extend(sourceDataExtent, src.extent);
+ });
+
+ var canvasWidthInUnits = ol.extent.getWidth(sourceDataExtent);
+ var canvasHeightInUnits = ol.extent.getHeight(sourceDataExtent);
+ var stitchContext = ol.dom.createCanvasContext2D(
+ Math.round(pixelRatio * canvasWidthInUnits / sourceResolution),
+ Math.round(pixelRatio * canvasHeightInUnits / sourceResolution));
+
+ var stitchScale = pixelRatio / sourceResolution;
+
+ sources.forEach(function(src, i, arr) {
+ var xPos = src.extent[0] - sourceDataExtent[0];
+ var yPos = -(src.extent[3] - sourceDataExtent[3]);
+ var srcWidth = ol.extent.getWidth(src.extent);
+ var srcHeight = ol.extent.getHeight(src.extent);
+
+ stitchContext.drawImage(
+ src.image,
+ gutter, gutter,
+ src.image.width - 2 * gutter, src.image.height - 2 * gutter,
+ xPos * stitchScale, yPos * stitchScale,
+ srcWidth * stitchScale, srcHeight * stitchScale);
+ });
+
+ var targetTopLeft = ol.extent.getTopLeft(targetExtent);
+
+ triangulation.getTriangles().forEach(function(triangle, i, arr) {
+ /* Calculate affine transform (src -> dst)
+ * Resulting matrix can be used to transform coordinate
+ * from `sourceProjection` to destination pixels.
+ *
+ * To optimize number of context calls and increase numerical stability,
+ * we also do the following operations:
+ * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1)
+ * here before solving the linear system so [ui, vi] are pixel coordinates.
+ *
+ * Src points: xi, yi
+ * Dst points: ui, vi
+ * Affine coefficients: aij
+ *
+ * | x0 y0 1 0 0 0 | |a00| |u0|
+ * | x1 y1 1 0 0 0 | |a01| |u1|
+ * | x2 y2 1 0 0 0 | x |a02| = |u2|
+ * | 0 0 0 x0 y0 1 | |a10| |v0|
+ * | 0 0 0 x1 y1 1 | |a11| |v1|
+ * | 0 0 0 x2 y2 1 | |a12| |v2|
+ */
+ var source = triangle.source, target = triangle.target;
+ var x0 = source[0][0], y0 = source[0][1],
+ x1 = source[1][0], y1 = source[1][1],
+ x2 = source[2][0], y2 = source[2][1];
+ var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution,
+ v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;
+ var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution,
+ v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;
+ var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution,
+ v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;
+
+ // Shift all the source points to improve numerical stability
+ // of all the subsequent calculations. The [x0, y0] is used here.
+ // This is also used to simplify the linear system.
+ var sourceNumericalShiftX = x0, sourceNumericalShiftY = y0;
+ x0 = 0;
+ y0 = 0;
+ x1 -= sourceNumericalShiftX;
+ y1 -= sourceNumericalShiftY;
+ x2 -= sourceNumericalShiftX;
+ y2 -= sourceNumericalShiftY;
+
+ var augmentedMatrix = [
+ [x1, y1, 0, 0, u1 - u0],
+ [x2, y2, 0, 0, u2 - u0],
+ [0, 0, x1, y1, v1 - v0],
+ [0, 0, x2, y2, v2 - v0]
+ ];
+ var affineCoefs = ol.math.solveLinearSystem(augmentedMatrix);
+ if (!affineCoefs) {
+ return;
+ }
+
+ context.save();
+ context.beginPath();
+ if (ol.reproj.browserAntialiasesClip_) {
+ var centroidX = (u0 + u1 + u2) / 3, centroidY = (v0 + v1 + v2) / 3;
+ var p0 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u0, v0);
+ var p1 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u1, v1);
+ var p2 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u2, v2);
+
+ context.moveTo(p0[0], p0[1]);
+ context.lineTo(p1[0], p1[1]);
+ context.lineTo(p2[0], p2[1]);
+ } else {
+ context.moveTo(u0, v0);
+ context.lineTo(u1, v1);
+ context.lineTo(u2, v2);
+ }
+ context.closePath();
+ context.clip();
+
+ context.transform(
+ affineCoefs[0], affineCoefs[2], affineCoefs[1], affineCoefs[3], u0, v0);
+
+ context.translate(sourceDataExtent[0] - sourceNumericalShiftX,
+ sourceDataExtent[3] - sourceNumericalShiftY);
+
+ context.scale(sourceResolution / pixelRatio,
+ -sourceResolution / pixelRatio);
+
+ context.drawImage(stitchContext.canvas, 0, 0);
+ context.restore();
+ });
+
+ if (opt_renderEdges) {
+ context.save();
+
+ context.strokeStyle = 'black';
+ context.lineWidth = 1;
+
+ triangulation.getTriangles().forEach(function(triangle, i, arr) {
+ var target = triangle.target;
+ var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution,
+ v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;
+ var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution,
+ v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;
+ var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution,
+ v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;
+
+ context.beginPath();
+ context.moveTo(u0, v0);
+ context.lineTo(u1, v1);
+ context.lineTo(u2, v2);
+ context.closePath();
+ context.stroke();
+ });
+
+ context.restore();
+ }
+ return context.canvas;
+};
+
+goog.provide('ol.reproj.Triangulation');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.math');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Class containing triangulation of the given target extent.
+ * Used for determining source data and the reprojection itself.
+ *
+ * @param {ol.proj.Projection} sourceProj Source projection.
+ * @param {ol.proj.Projection} targetProj Target projection.
+ * @param {ol.Extent} targetExtent Target extent to triangulate.
+ * @param {ol.Extent} maxSourceExtent Maximal source extent that can be used.
+ * @param {number} errorThreshold Acceptable error (in source units).
+ * @constructor
+ */
+ol.reproj.Triangulation = function(sourceProj, targetProj, targetExtent,
+ maxSourceExtent, errorThreshold) {
+
+ /**
+ * @type {ol.proj.Projection}
+ * @private
+ */
+ this.sourceProj_ = sourceProj;
+
+ /**
+ * @type {ol.proj.Projection}
+ * @private
+ */
+ this.targetProj_ = targetProj;
+
+ /** @type {!Object.<string, ol.Coordinate>} */
+ var transformInvCache = {};
+ var transformInv = ol.proj.getTransform(this.targetProj_, this.sourceProj_);
+
+ /**
+ * @param {ol.Coordinate} c A coordinate.
+ * @return {ol.Coordinate} Transformed coordinate.
+ * @private
+ */
+ this.transformInv_ = function(c) {
+ var key = c[0] + '/' + c[1];
+ if (!transformInvCache[key]) {
+ transformInvCache[key] = transformInv(c);
+ }
+ return transformInvCache[key];
+ };
+
+ /**
+ * @type {ol.Extent}
+ * @private
+ */
+ this.maxSourceExtent_ = maxSourceExtent;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.errorThresholdSquared_ = errorThreshold * errorThreshold;
+
+ /**
+ * @type {Array.<ol.ReprojTriangle>}
+ * @private
+ */
+ this.triangles_ = [];
+
+ /**
+ * Indicates that the triangulation crosses edge of the source projection.
+ * @type {boolean}
+ * @private
+ */
+ this.wrapsXInSource_ = false;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.canWrapXInSource_ = this.sourceProj_.canWrapX() &&
+ !!maxSourceExtent &&
+ !!this.sourceProj_.getExtent() &&
+ (ol.extent.getWidth(maxSourceExtent) ==
+ ol.extent.getWidth(this.sourceProj_.getExtent()));
+
+ /**
+ * @type {?number}
+ * @private
+ */
+ this.sourceWorldWidth_ = this.sourceProj_.getExtent() ?
+ ol.extent.getWidth(this.sourceProj_.getExtent()) : null;
+
+ /**
+ * @type {?number}
+ * @private
+ */
+ this.targetWorldWidth_ = this.targetProj_.getExtent() ?
+ ol.extent.getWidth(this.targetProj_.getExtent()) : null;
+
+ var destinationTopLeft = ol.extent.getTopLeft(targetExtent);
+ var destinationTopRight = ol.extent.getTopRight(targetExtent);
+ var destinationBottomRight = ol.extent.getBottomRight(targetExtent);
+ var destinationBottomLeft = ol.extent.getBottomLeft(targetExtent);
+ var sourceTopLeft = this.transformInv_(destinationTopLeft);
+ var sourceTopRight = this.transformInv_(destinationTopRight);
+ var sourceBottomRight = this.transformInv_(destinationBottomRight);
+ var sourceBottomLeft = this.transformInv_(destinationBottomLeft);
+
+ this.addQuad_(
+ destinationTopLeft, destinationTopRight,
+ destinationBottomRight, destinationBottomLeft,
+ sourceTopLeft, sourceTopRight, sourceBottomRight, sourceBottomLeft,
+ ol.RASTER_REPROJECTION_MAX_SUBDIVISION);
+
+ if (this.wrapsXInSource_) {
+ // Fix coordinates (ol.proj returns wrapped coordinates, "unwrap" here).
+ // This significantly simplifies the rest of the reprojection process.
+
+ goog.asserts.assert(this.sourceWorldWidth_ !== null);
+ var leftBound = Infinity;
+ this.triangles_.forEach(function(triangle, i, arr) {
+ leftBound = Math.min(leftBound,
+ triangle.source[0][0], triangle.source[1][0], triangle.source[2][0]);
+ });
+
+ // Shift triangles to be as close to `leftBound` as possible
+ // (if the distance is more than `worldWidth / 2` it can be closer.
+ this.triangles_.forEach(function(triangle) {
+ if (Math.max(triangle.source[0][0], triangle.source[1][0],
+ triangle.source[2][0]) - leftBound > this.sourceWorldWidth_ / 2) {
+ var newTriangle = [[triangle.source[0][0], triangle.source[0][1]],
+ [triangle.source[1][0], triangle.source[1][1]],
+ [triangle.source[2][0], triangle.source[2][1]]];
+ if ((newTriangle[0][0] - leftBound) > this.sourceWorldWidth_ / 2) {
+ newTriangle[0][0] -= this.sourceWorldWidth_;
+ }
+ if ((newTriangle[1][0] - leftBound) > this.sourceWorldWidth_ / 2) {
+ newTriangle[1][0] -= this.sourceWorldWidth_;
+ }
+ if ((newTriangle[2][0] - leftBound) > this.sourceWorldWidth_ / 2) {
+ newTriangle[2][0] -= this.sourceWorldWidth_;
+ }
+
+ // Rarely (if the extent contains both the dateline and prime meridian)
+ // the shift can in turn break some triangles.
+ // Detect this here and don't shift in such cases.
+ var minX = Math.min(
+ newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]);
+ var maxX = Math.max(
+ newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]);
+ if ((maxX - minX) < this.sourceWorldWidth_ / 2) {
+ triangle.source = newTriangle;
+ }
+ }
+ }, this);
+ }
+
+ transformInvCache = {};
+};
+
+
+/**
+ * Adds triangle to the triangulation.
+ * @param {ol.Coordinate} a The target a coordinate.
+ * @param {ol.Coordinate} b The target b coordinate.
+ * @param {ol.Coordinate} c The target c coordinate.
+ * @param {ol.Coordinate} aSrc The source a coordinate.
+ * @param {ol.Coordinate} bSrc The source b coordinate.
+ * @param {ol.Coordinate} cSrc The source c coordinate.
+ * @private
+ */
+ol.reproj.Triangulation.prototype.addTriangle_ = function(a, b, c,
+ aSrc, bSrc, cSrc) {
+ this.triangles_.push({
+ source: [aSrc, bSrc, cSrc],
+ target: [a, b, c]
+ });
+};
+
+
+/**
+ * Adds quad (points in clock-wise order) to the triangulation
+ * (and reprojects the vertices) if valid.
+ * Performs quad subdivision if needed to increase precision.
+ *
+ * @param {ol.Coordinate} a The target a coordinate.
+ * @param {ol.Coordinate} b The target b coordinate.
+ * @param {ol.Coordinate} c The target c coordinate.
+ * @param {ol.Coordinate} d The target d coordinate.
+ * @param {ol.Coordinate} aSrc The source a coordinate.
+ * @param {ol.Coordinate} bSrc The source b coordinate.
+ * @param {ol.Coordinate} cSrc The source c coordinate.
+ * @param {ol.Coordinate} dSrc The source d coordinate.
+ * @param {number} maxSubdivision Maximal allowed subdivision of the quad.
+ * @private
+ */
+ol.reproj.Triangulation.prototype.addQuad_ = function(a, b, c, d,
+ aSrc, bSrc, cSrc, dSrc, maxSubdivision) {
+
+ var sourceQuadExtent = ol.extent.boundingExtent([aSrc, bSrc, cSrc, dSrc]);
+ var sourceCoverageX = this.sourceWorldWidth_ ?
+ ol.extent.getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null;
+
+ // when the quad is wrapped in the source projection
+ // it covers most of the projection extent, but not fully
+ var wrapsX = this.sourceProj_.canWrapX() &&
+ sourceCoverageX > 0.5 && sourceCoverageX < 1;
+
+ var needsSubdivision = false;
+
+ if (maxSubdivision > 0) {
+ if (this.targetProj_.isGlobal() && this.targetWorldWidth_) {
+ var targetQuadExtent = ol.extent.boundingExtent([a, b, c, d]);
+ var targetCoverageX =
+ ol.extent.getWidth(targetQuadExtent) / this.targetWorldWidth_;
+ needsSubdivision |=
+ targetCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH;
+ }
+ if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) {
+ needsSubdivision |=
+ sourceCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH;
+ }
+ }
+
+ if (!needsSubdivision && this.maxSourceExtent_) {
+ if (!ol.extent.intersects(sourceQuadExtent, this.maxSourceExtent_)) {
+ // whole quad outside source projection extent -> ignore
+ return;
+ }
+ }
+
+ if (!needsSubdivision) {
+ if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) ||
+ !isFinite(bSrc[0]) || !isFinite(bSrc[1]) ||
+ !isFinite(cSrc[0]) || !isFinite(cSrc[1]) ||
+ !isFinite(dSrc[0]) || !isFinite(dSrc[1])) {
+ if (maxSubdivision > 0) {
+ needsSubdivision = true;
+ } else {
+ return;
+ }
+ }
+ }
+
+ if (maxSubdivision > 0) {
+ if (!needsSubdivision) {
+ var center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2];
+ var centerSrc = this.transformInv_(center);
+
+ var dx;
+ if (wrapsX) {
+ goog.asserts.assert(this.sourceWorldWidth_);
+ var centerSrcEstimX =
+ (ol.math.modulo(aSrc[0], this.sourceWorldWidth_) +
+ ol.math.modulo(cSrc[0], this.sourceWorldWidth_)) / 2;
+ dx = centerSrcEstimX -
+ ol.math.modulo(centerSrc[0], this.sourceWorldWidth_);
+ } else {
+ dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0];
+ }
+ var dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1];
+ var centerSrcErrorSquared = dx * dx + dy * dy;
+ needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_;
+ }
+ if (needsSubdivision) {
+ if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) {
+ // split horizontally (top & bottom)
+ var bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2];
+ var bcSrc = this.transformInv_(bc);
+ var da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2];
+ var daSrc = this.transformInv_(da);
+
+ this.addQuad_(
+ a, b, bc, da, aSrc, bSrc, bcSrc, daSrc, maxSubdivision - 1);
+ this.addQuad_(
+ da, bc, c, d, daSrc, bcSrc, cSrc, dSrc, maxSubdivision - 1);
+ } else {
+ // split vertically (left & right)
+ var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
+ var abSrc = this.transformInv_(ab);
+ var cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2];
+ var cdSrc = this.transformInv_(cd);
+
+ this.addQuad_(
+ a, ab, cd, d, aSrc, abSrc, cdSrc, dSrc, maxSubdivision - 1);
+ this.addQuad_(
+ ab, b, c, cd, abSrc, bSrc, cSrc, cdSrc, maxSubdivision - 1);
+ }
+ return;
+ }
+ }
+
+ if (wrapsX) {
+ if (!this.canWrapXInSource_) {
+ return;
+ }
+ this.wrapsXInSource_ = true;
+ }
+
+ this.addTriangle_(a, c, d, aSrc, cSrc, dSrc);
+ this.addTriangle_(a, b, c, aSrc, bSrc, cSrc);
+};
+
+
+/**
+ * Calculates extent of the 'source' coordinates from all the triangles.
+ *
+ * @return {ol.Extent} Calculated extent.
+ */
+ol.reproj.Triangulation.prototype.calculateSourceExtent = function() {
+ var extent = ol.extent.createEmpty();
+
+ this.triangles_.forEach(function(triangle, i, arr) {
+ var src = triangle.source;
+ ol.extent.extendCoordinate(extent, src[0]);
+ ol.extent.extendCoordinate(extent, src[1]);
+ ol.extent.extendCoordinate(extent, src[2]);
+ });
+
+ return extent;
+};
+
+
+/**
+ * @return {Array.<ol.ReprojTriangle>} Array of the calculated triangles.
+ */
+ol.reproj.Triangulation.prototype.getTriangles = function() {
+ return this.triangles_;
+};
+
+goog.provide('ol.reproj.Image');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.ImageBase');
+goog.require('ol.ImageState');
+goog.require('ol.extent');
+goog.require('ol.proj');
+goog.require('ol.reproj');
+goog.require('ol.reproj.Triangulation');
+
+
+/**
+ * @classdesc
+ * Class encapsulating single reprojected image.
+ * See {@link ol.source.Image}.
+ *
+ * @constructor
+ * @extends {ol.ImageBase}
+ * @param {ol.proj.Projection} sourceProj Source projection (of the data).
+ * @param {ol.proj.Projection} targetProj Target projection.
+ * @param {ol.Extent} targetExtent Target extent.
+ * @param {number} targetResolution Target resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.ReprojImageFunctionType} getImageFunction
+ * Function returning source images (extent, resolution, pixelRatio).
+ */
+ol.reproj.Image = function(sourceProj, targetProj,
+ targetExtent, targetResolution, pixelRatio, getImageFunction) {
+
+ /**
+ * @private
+ * @type {ol.proj.Projection}
+ */
+ this.targetProj_ = targetProj;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.maxSourceExtent_ = sourceProj.getExtent();
+ var maxTargetExtent = targetProj.getExtent();
+
+ var limitedTargetExtent = maxTargetExtent ?
+ ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent;
+
+ var targetCenter = ol.extent.getCenter(limitedTargetExtent);
+ var sourceResolution = ol.reproj.calculateSourceResolution(
+ sourceProj, targetProj, targetCenter, targetResolution);
+
+ var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD;
+
+ /**
+ * @private
+ * @type {!ol.reproj.Triangulation}
+ */
+ this.triangulation_ = new ol.reproj.Triangulation(
+ sourceProj, targetProj, limitedTargetExtent, this.maxSourceExtent_,
+ sourceResolution * errorThresholdInPixels);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.targetResolution_ = targetResolution;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.targetExtent_ = targetExtent;
+
+ var sourceExtent = this.triangulation_.calculateSourceExtent();
+
+ /**
+ * @private
+ * @type {ol.ImageBase}
+ */
+ this.sourceImage_ =
+ getImageFunction(sourceExtent, sourceResolution, pixelRatio);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.sourcePixelRatio_ =
+ this.sourceImage_ ? this.sourceImage_.getPixelRatio() : 1;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = null;
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.sourceListenerKey_ = null;
+
+
+ var state = ol.ImageState.LOADED;
+ var attributions = [];
+
+ if (this.sourceImage_) {
+ state = ol.ImageState.IDLE;
+ attributions = this.sourceImage_.getAttributions();
+ }
+
+ ol.ImageBase.call(this, targetExtent, targetResolution, this.sourcePixelRatio_,
+ state, attributions);
+};
+ol.inherits(ol.reproj.Image, ol.ImageBase);
+
+
+/**
+ * @inheritDoc
+ */
+ol.reproj.Image.prototype.disposeInternal = function() {
+ if (this.state == ol.ImageState.LOADING) {
+ this.unlistenSource_();
+ }
+ ol.ImageBase.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.reproj.Image.prototype.getImage = function(opt_context) {
+ return this.canvas_;
+};
+
+
+/**
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.reproj.Image.prototype.getProjection = function() {
+ return this.targetProj_;
+};
+
+
+/**
+ * @private
+ */
+ol.reproj.Image.prototype.reproject_ = function() {
+ var sourceState = this.sourceImage_.getState();
+ if (sourceState == ol.ImageState.LOADED) {
+ var width = ol.extent.getWidth(this.targetExtent_) / this.targetResolution_;
+ var height =
+ ol.extent.getHeight(this.targetExtent_) / this.targetResolution_;
+
+ this.canvas_ = ol.reproj.render(width, height, this.sourcePixelRatio_,
+ this.sourceImage_.getResolution(), this.maxSourceExtent_,
+ this.targetResolution_, this.targetExtent_, this.triangulation_, [{
+ extent: this.sourceImage_.getExtent(),
+ image: this.sourceImage_.getImage()
+ }], 0);
+ }
+ this.state = sourceState;
+ this.changed();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.reproj.Image.prototype.load = function() {
+ if (this.state == ol.ImageState.IDLE) {
+ this.state = ol.ImageState.LOADING;
+ this.changed();
+
+ var sourceState = this.sourceImage_.getState();
+ if (sourceState == ol.ImageState.LOADED ||
+ sourceState == ol.ImageState.ERROR) {
+ this.reproject_();
+ } else {
+ this.sourceListenerKey_ = ol.events.listen(this.sourceImage_,
+ ol.events.EventType.CHANGE, function(e) {
+ var sourceState = this.sourceImage_.getState();
+ if (sourceState == ol.ImageState.LOADED ||
+ sourceState == ol.ImageState.ERROR) {
+ this.unlistenSource_();
+ this.reproject_();
+ }
+ }, this);
+ this.sourceImage_.load();
+ }
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.reproj.Image.prototype.unlistenSource_ = function() {
+ goog.asserts.assert(this.sourceListenerKey_,
+ 'this.sourceListenerKey_ should not be null');
+ ol.events.unlistenByKey(this.sourceListenerKey_);
+ this.sourceListenerKey_ = null;
+};
+
+goog.provide('ol.source.Image');
+goog.provide('ol.source.ImageEvent');
+
+goog.require('goog.asserts');
+goog.require('ol.events.Event');
+goog.require('ol.ImageState');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.proj');
+goog.require('ol.reproj.Image');
+goog.require('ol.source.Source');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for sources providing a single image.
+ *
+ * @constructor
+ * @extends {ol.source.Source}
+ * @param {ol.SourceImageOptions} options Single image source options.
+ * @api
+ */
+ol.source.Image = function(options) {
+
+ ol.source.Source.call(this, {
+ attributions: options.attributions,
+ extent: options.extent,
+ logo: options.logo,
+ projection: options.projection,
+ state: options.state
+ });
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.resolutions_ = options.resolutions !== undefined ?
+ options.resolutions : null;
+ goog.asserts.assert(!this.resolutions_ ||
+ ol.array.isSorted(this.resolutions_,
+ function(a, b) {
+ return b - a;
+ }, true), 'resolutions must be null or sorted in descending order');
+
+
+ /**
+ * @private
+ * @type {ol.reproj.Image}
+ */
+ this.reprojectedImage_ = null;
+
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.reprojectedRevision_ = 0;
+
+};
+ol.inherits(ol.source.Image, ol.source.Source);
+
+
+/**
+ * @return {Array.<number>} Resolutions.
+ */
+ol.source.Image.prototype.getResolutions = function() {
+ return this.resolutions_;
+};
+
+
+/**
+ * @protected
+ * @param {number} resolution Resolution.
+ * @return {number} Resolution.
+ */
+ol.source.Image.prototype.findNearestResolution = function(resolution) {
+ if (this.resolutions_) {
+ var idx = ol.array.linearFindNearest(this.resolutions_, resolution, 0);
+ resolution = this.resolutions_[idx];
+ }
+ return resolution;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.ImageBase} Single image.
+ */
+ol.source.Image.prototype.getImage = function(extent, resolution, pixelRatio, projection) {
+ var sourceProjection = this.getProjection();
+ if (!ol.ENABLE_RASTER_REPROJECTION ||
+ !sourceProjection ||
+ !projection ||
+ ol.proj.equivalent(sourceProjection, projection)) {
+ if (sourceProjection) {
+ projection = sourceProjection;
+ }
+ return this.getImageInternal(extent, resolution, pixelRatio, projection);
+ } else {
+ if (this.reprojectedImage_) {
+ if (this.reprojectedRevision_ == this.getRevision() &&
+ ol.proj.equivalent(
+ this.reprojectedImage_.getProjection(), projection) &&
+ this.reprojectedImage_.getResolution() == resolution &&
+ this.reprojectedImage_.getPixelRatio() == pixelRatio &&
+ ol.extent.equals(this.reprojectedImage_.getExtent(), extent)) {
+ return this.reprojectedImage_;
+ }
+ this.reprojectedImage_.dispose();
+ this.reprojectedImage_ = null;
+ }
+
+ this.reprojectedImage_ = new ol.reproj.Image(
+ sourceProjection, projection, extent, resolution, pixelRatio,
+ function(extent, resolution, pixelRatio) {
+ return this.getImageInternal(extent, resolution,
+ pixelRatio, sourceProjection);
+ }.bind(this));
+ this.reprojectedRevision_ = this.getRevision();
+
+ return this.reprojectedImage_;
+ }
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {ol.ImageBase} Single image.
+ * @protected
+ */
+ol.source.Image.prototype.getImageInternal = goog.abstractMethod;
+
+
+/**
+ * Handle image change events.
+ * @param {ol.events.Event} event Event.
+ * @protected
+ */
+ol.source.Image.prototype.handleImageChange = function(event) {
+ var image = /** @type {ol.Image} */ (event.target);
+ switch (image.getState()) {
+ case ol.ImageState.LOADING:
+ this.dispatchEvent(
+ new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADSTART,
+ image));
+ break;
+ case ol.ImageState.LOADED:
+ this.dispatchEvent(
+ new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADEND,
+ image));
+ break;
+ case ol.ImageState.ERROR:
+ this.dispatchEvent(
+ new ol.source.ImageEvent(ol.source.ImageEventType.IMAGELOADERROR,
+ image));
+ break;
+ default:
+ // pass
+ }
+};
+
+
+/**
+ * Default image load function for image sources that use ol.Image image
+ * instances.
+ * @param {ol.Image} image Image.
+ * @param {string} src Source.
+ */
+ol.source.Image.defaultImageLoadFunction = function(image, src) {
+ image.getImage().src = src;
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.source.Image} instances are instances of this
+ * type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.source.ImageEvent}
+ * @param {string} type Type.
+ * @param {ol.Image} image The image.
+ */
+ol.source.ImageEvent = function(type, image) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The image related to the event.
+ * @type {ol.Image}
+ * @api
+ */
+ this.image = image;
+
+};
+ol.inherits(ol.source.ImageEvent, ol.events.Event);
+
+
+/**
+ * @enum {string}
+ */
+ol.source.ImageEventType = {
+
+ /**
+ * Triggered when an image starts loading.
+ * @event ol.source.ImageEvent#imageloadstart
+ * @api
+ */
+ IMAGELOADSTART: 'imageloadstart',
+
+ /**
+ * Triggered when an image finishes loading.
+ * @event ol.source.ImageEvent#imageloadend
+ * @api
+ */
+ IMAGELOADEND: 'imageloadend',
+
+ /**
+ * Triggered if image loading results in an error.
+ * @event ol.source.ImageEvent#imageloaderror
+ * @api
+ */
+ IMAGELOADERROR: 'imageloaderror'
+
+};
+
+goog.provide('ol.source.ImageCanvas');
+
+goog.require('ol.ImageCanvas');
+goog.require('ol.extent');
+goog.require('ol.source.Image');
+
+
+/**
+ * @classdesc
+ * Base class for image sources where a canvas element is the image.
+ *
+ * @constructor
+ * @extends {ol.source.Image}
+ * @param {olx.source.ImageCanvasOptions} options Constructor options.
+ * @api
+ */
+ol.source.ImageCanvas = function(options) {
+
+ ol.source.Image.call(this, {
+ attributions: options.attributions,
+ logo: options.logo,
+ projection: options.projection,
+ resolutions: options.resolutions,
+ state: options.state
+ });
+
+ /**
+ * @private
+ * @type {ol.CanvasFunctionType}
+ */
+ this.canvasFunction_ = options.canvasFunction;
+
+ /**
+ * @private
+ * @type {ol.ImageCanvas}
+ */
+ this.canvas_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.ratio_ = options.ratio !== undefined ?
+ options.ratio : 1.5;
+
+};
+ol.inherits(ol.source.ImageCanvas, ol.source.Image);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageCanvas.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
+ resolution = this.findNearestResolution(resolution);
+
+ var canvas = this.canvas_;
+ if (canvas &&
+ this.renderedRevision_ == this.getRevision() &&
+ canvas.getResolution() == resolution &&
+ canvas.getPixelRatio() == pixelRatio &&
+ ol.extent.containsExtent(canvas.getExtent(), extent)) {
+ return canvas;
+ }
+
+ extent = extent.slice();
+ ol.extent.scaleFromCenter(extent, this.ratio_);
+ var width = ol.extent.getWidth(extent) / resolution;
+ var height = ol.extent.getHeight(extent) / resolution;
+ var size = [width * pixelRatio, height * pixelRatio];
+
+ var canvasElement = this.canvasFunction_(
+ extent, resolution, pixelRatio, size, projection);
+ if (canvasElement) {
+ canvas = new ol.ImageCanvas(extent, resolution, pixelRatio,
+ this.getAttributions(), canvasElement);
+ }
+ this.canvas_ = canvas;
+ this.renderedRevision_ = this.getRevision();
+
+ return canvas;
+};
+
+goog.provide('ol.Feature');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.Object');
+goog.require('ol.geom.Geometry');
+goog.require('ol.style.Style');
+
+
+/**
+ * @classdesc
+ * A vector object for geographic features with a geometry and other
+ * attribute properties, similar to the features in vector file formats like
+ * GeoJSON.
+ *
+ * Features can be styled individually with `setStyle`; otherwise they use the
+ * style of their vector layer.
+ *
+ * Note that attribute properties are set as {@link ol.Object} properties on
+ * the feature object, so they are observable, and have get/set accessors.
+ *
+ * Typically, a feature has a single geometry property. You can set the
+ * geometry using the `setGeometry` method and get it with `getGeometry`.
+ * It is possible to store more than one geometry on a feature using attribute
+ * properties. By default, the geometry used for rendering is identified by
+ * the property name `geometry`. If you want to use another geometry property
+ * for rendering, use the `setGeometryName` method to change the attribute
+ * property associated with the geometry for the feature. For example:
+ *
+ * ```js
+ * var feature = new ol.Feature({
+ * geometry: new ol.geom.Polygon(polyCoords),
+ * labelPoint: new ol.geom.Point(labelCoords),
+ * name: 'My Polygon'
+ * });
+ *
+ * // get the polygon geometry
+ * var poly = feature.getGeometry();
+ *
+ * // Render the feature as a point using the coordinates from labelPoint
+ * feature.setGeometryName('labelPoint');
+ *
+ * // get the point geometry
+ * var point = feature.getGeometry();
+ * ```
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties
+ * You may pass a Geometry object directly, or an object literal
+ * containing properties. If you pass an object literal, you may
+ * include a Geometry associated with a `geometry` key.
+ * @api stable
+ */
+ol.Feature = function(opt_geometryOrProperties) {
+
+ ol.Object.call(this);
+
+ /**
+ * @private
+ * @type {number|string|undefined}
+ */
+ this.id_ = undefined;
+
+ /**
+ * @type {string}
+ * @private
+ */
+ this.geometryName_ = 'geometry';
+
+ /**
+ * User provided style.
+ * @private
+ * @type {ol.style.Style|Array.<ol.style.Style>|
+ * ol.FeatureStyleFunction}
+ */
+ this.style_ = null;
+
+ /**
+ * @private
+ * @type {ol.FeatureStyleFunction|undefined}
+ */
+ this.styleFunction_ = undefined;
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.geometryChangeKey_ = null;
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(this.geometryName_),
+ this.handleGeometryChanged_, this);
+
+ if (opt_geometryOrProperties !== undefined) {
+ if (opt_geometryOrProperties instanceof ol.geom.Geometry ||
+ !opt_geometryOrProperties) {
+ var geometry = opt_geometryOrProperties;
+ this.setGeometry(geometry);
+ } else {
+ goog.asserts.assert(goog.isObject(opt_geometryOrProperties),
+ 'opt_geometryOrProperties should be an Object');
+ /** @type {Object.<string, *>} */
+ var properties = opt_geometryOrProperties;
+ this.setProperties(properties);
+ }
+ }
+};
+ol.inherits(ol.Feature, ol.Object);
+
+
+/**
+ * Clone this feature. If the original feature has a geometry it
+ * is also cloned. The feature id is not set in the clone.
+ * @return {ol.Feature} The clone.
+ * @api stable
+ */
+ol.Feature.prototype.clone = function() {
+ var clone = new ol.Feature(this.getProperties());
+ clone.setGeometryName(this.getGeometryName());
+ var geometry = this.getGeometry();
+ if (geometry) {
+ clone.setGeometry(geometry.clone());
+ }
+ var style = this.getStyle();
+ if (style) {
+ clone.setStyle(style);
+ }
+ return clone;
+};
+
+
+/**
+ * Get the feature's default geometry. A feature may have any number of named
+ * geometries. The "default" geometry (the one that is rendered by default) is
+ * set when calling {@link ol.Feature#setGeometry}.
+ * @return {ol.geom.Geometry|undefined} The default geometry for the feature.
+ * @api stable
+ * @observable
+ */
+ol.Feature.prototype.getGeometry = function() {
+ return /** @type {ol.geom.Geometry|undefined} */ (
+ this.get(this.geometryName_));
+};
+
+
+/**
+ * Get the feature identifier. This is a stable identifier for the feature and
+ * is either set when reading data from a remote source or set explicitly by
+ * calling {@link ol.Feature#setId}.
+ * @return {number|string|undefined} Id.
+ * @api stable
+ * @observable
+ */
+ol.Feature.prototype.getId = function() {
+ return this.id_;
+};
+
+
+/**
+ * Get the name of the feature's default geometry. By default, the default
+ * geometry is named `geometry`.
+ * @return {string} Get the property name associated with the default geometry
+ * for this feature.
+ * @api stable
+ */
+ol.Feature.prototype.getGeometryName = function() {
+ return this.geometryName_;
+};
+
+
+/**
+ * Get the feature's style. This return for this method depends on what was
+ * provided to the {@link ol.Feature#setStyle} method.
+ * @return {ol.style.Style|Array.<ol.style.Style>|
+ * ol.FeatureStyleFunction} The feature style.
+ * @api stable
+ * @observable
+ */
+ol.Feature.prototype.getStyle = function() {
+ return this.style_;
+};
+
+
+/**
+ * Get the feature's style function.
+ * @return {ol.FeatureStyleFunction|undefined} Return a function
+ * representing the current style of this feature.
+ * @api stable
+ */
+ol.Feature.prototype.getStyleFunction = function() {
+ return this.styleFunction_;
+};
+
+
+/**
+ * @private
+ */
+ol.Feature.prototype.handleGeometryChange_ = function() {
+ this.changed();
+};
+
+
+/**
+ * @private
+ */
+ol.Feature.prototype.handleGeometryChanged_ = function() {
+ if (this.geometryChangeKey_) {
+ ol.events.unlistenByKey(this.geometryChangeKey_);
+ this.geometryChangeKey_ = null;
+ }
+ var geometry = this.getGeometry();
+ if (geometry) {
+ this.geometryChangeKey_ = ol.events.listen(geometry,
+ ol.events.EventType.CHANGE, this.handleGeometryChange_, this);
+ }
+ this.changed();
+};
+
+
+/**
+ * Set the default geometry for the feature. This will update the property
+ * with the name returned by {@link ol.Feature#getGeometryName}.
+ * @param {ol.geom.Geometry|undefined} geometry The new geometry.
+ * @api stable
+ * @observable
+ */
+ol.Feature.prototype.setGeometry = function(geometry) {
+ this.set(this.geometryName_, geometry);
+};
+
+
+/**
+ * Set the style for the feature. This can be a single style object, an array
+ * of styles, or a function that takes a resolution and returns an array of
+ * styles. If it is `null` the feature has no style (a `null` style).
+ * @param {ol.style.Style|Array.<ol.style.Style>|
+ * ol.FeatureStyleFunction} style Style for this feature.
+ * @api stable
+ * @observable
+ */
+ol.Feature.prototype.setStyle = function(style) {
+ this.style_ = style;
+ this.styleFunction_ = !style ?
+ undefined : ol.Feature.createStyleFunction(style);
+ this.changed();
+};
+
+
+/**
+ * Set the feature id. The feature id is considered stable and may be used when
+ * requesting features or comparing identifiers returned from a remote source.
+ * The feature id can be used with the {@link ol.source.Vector#getFeatureById}
+ * method.
+ * @param {number|string|undefined} id The feature id.
+ * @api stable
+ * @observable
+ */
+ol.Feature.prototype.setId = function(id) {
+ this.id_ = id;
+ this.changed();
+};
+
+
+/**
+ * Set the property name to be used when getting the feature's default geometry.
+ * When calling {@link ol.Feature#getGeometry}, the value of the property with
+ * this name will be returned.
+ * @param {string} name The property name of the default geometry.
+ * @api stable
+ */
+ol.Feature.prototype.setGeometryName = function(name) {
+ ol.events.unlisten(
+ this, ol.Object.getChangeEventType(this.geometryName_),
+ this.handleGeometryChanged_, this);
+ this.geometryName_ = name;
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(this.geometryName_),
+ this.handleGeometryChanged_, this);
+ this.handleGeometryChanged_();
+};
+
+
+/**
+ * Convert the provided object into a feature style function. Functions passed
+ * through unchanged. Arrays of ol.style.Style or single style objects wrapped
+ * in a new feature style function.
+ * @param {ol.FeatureStyleFunction|!Array.<ol.style.Style>|!ol.style.Style} obj
+ * A feature style function, a single style, or an array of styles.
+ * @return {ol.FeatureStyleFunction} A style function.
+ */
+ol.Feature.createStyleFunction = function(obj) {
+ var styleFunction;
+
+ if (typeof obj === 'function') {
+ styleFunction = obj;
+ } else {
+ /**
+ * @type {Array.<ol.style.Style>}
+ */
+ var styles;
+ if (Array.isArray(obj)) {
+ styles = obj;
+ } else {
+ goog.asserts.assertInstanceof(obj, ol.style.Style,
+ 'obj should be an ol.style.Style');
+ styles = [obj];
+ }
+ styleFunction = function() {
+ return styles;
+ };
+ }
+ return styleFunction;
+};
+
+goog.provide('ol.VectorTile');
+
+goog.require('ol.Tile');
+goog.require('ol.TileState');
+goog.require('ol.dom');
+goog.require('ol.proj.Projection');
+
+
+/**
+ * @constructor
+ * @extends {ol.Tile}
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.TileState} state State.
+ * @param {string} src Data source url.
+ * @param {ol.format.Feature} format Feature format.
+ * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
+ */
+ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
+
+ ol.Tile.call(this, tileCoord, state);
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = ol.dom.createCanvasContext2D();
+
+ /**
+ * @private
+ * @type {ol.format.Feature}
+ */
+ this.format_ = format;
+
+ /**
+ * @private
+ * @type {Array.<ol.Feature>}
+ */
+ this.features_ = null;
+
+ /**
+ * @private
+ * @type {ol.FeatureLoader}
+ */
+ this.loader_;
+
+ /**
+ * Data projection
+ * @private
+ * @type {ol.proj.Projection}
+ */
+ this.projection_;
+
+ /**
+ * @private
+ * @type {ol.TileReplayState}
+ */
+ this.replayState_ = {
+ dirty: false,
+ renderedRenderOrder: null,
+ renderedRevision: -1,
+ renderedTileRevision: -1,
+ replayGroup: null,
+ skippedFeatures: []
+ };
+
+ /**
+ * @private
+ * @type {ol.TileLoadFunctionType}
+ */
+ this.tileLoadFunction_ = tileLoadFunction;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.url_ = src;
+
+};
+ol.inherits(ol.VectorTile, ol.Tile);
+
+
+/**
+ * @return {CanvasRenderingContext2D} The rendering context.
+ */
+ol.VectorTile.prototype.getContext = function() {
+ return this.context_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.VectorTile.prototype.getImage = function() {
+ return this.replayState_.renderedTileRevision == -1 ?
+ null : this.context_.canvas;
+};
+
+
+/**
+ * Get the feature format assigned for reading this tile's features.
+ * @return {ol.format.Feature} Feature format.
+ * @api
+ */
+ol.VectorTile.prototype.getFormat = function() {
+ return this.format_;
+};
+
+
+/**
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.VectorTile.prototype.getFeatures = function() {
+ return this.features_;
+};
+
+
+/**
+ * @return {ol.TileReplayState} The replay state.
+ */
+ol.VectorTile.prototype.getReplayState = function() {
+ return this.replayState_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.VectorTile.prototype.getKey = function() {
+ return this.url_;
+};
+
+
+/**
+ * @return {ol.proj.Projection} Feature projection.
+ */
+ol.VectorTile.prototype.getProjection = function() {
+ return this.projection_;
+};
+
+
+/**
+ * Load the tile.
+ */
+ol.VectorTile.prototype.load = function() {
+ if (this.state == ol.TileState.IDLE) {
+ this.setState(ol.TileState.LOADING);
+ this.tileLoadFunction_(this, this.url_);
+ this.loader_(null, NaN, null);
+ }
+};
+
+
+/**
+ * @param {Array.<ol.Feature>} features Features.
+ * @api
+ */
+ol.VectorTile.prototype.setFeatures = function(features) {
+ this.features_ = features;
+ this.setState(ol.TileState.LOADED);
+};
+
+
+/**
+ * Set the projection of the features that were added with {@link #setFeatures}.
+ * @param {ol.proj.Projection} projection Feature projection.
+ * @api
+ */
+ol.VectorTile.prototype.setProjection = function(projection) {
+ this.projection_ = projection;
+};
+
+
+/**
+ * @param {ol.TileState} tileState Tile state.
+ */
+ol.VectorTile.prototype.setState = function(tileState) {
+ this.state = tileState;
+ this.changed();
+};
+
+
+/**
+ * Set the feature loader for reading this tile's features.
+ * @param {ol.FeatureLoader} loader Feature loader.
+ * @api
+ */
+ol.VectorTile.prototype.setLoader = function(loader) {
+ this.loader_ = loader;
+};
+
+goog.provide('ol.format.FormatType');
+
+
+/**
+ * @enum {string}
+ */
+ol.format.FormatType = {
+ ARRAY_BUFFER: 'arraybuffer',
+ JSON: 'json',
+ TEXT: 'text',
+ XML: 'xml'
+};
+
+goog.provide('ol.xml');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+
+
+/**
+ * This document should be used when creating nodes for XML serializations. This
+ * document is also used by {@link ol.xml.createElementNS} and
+ * {@link ol.xml.setAttributeNS}
+ * @const
+ * @type {Document}
+ */
+ol.xml.DOCUMENT = document.implementation.createDocument('', '', null);
+
+
+/**
+ * @param {string} namespaceURI Namespace URI.
+ * @param {string} qualifiedName Qualified name.
+ * @return {Node} Node.
+ */
+ol.xml.createElementNS = function(namespaceURI, qualifiedName) {
+ return ol.xml.DOCUMENT.createElementNS(namespaceURI, qualifiedName);
+};
+
+
+/**
+ * Recursively grab all text content of child nodes into a single string.
+ * @param {Node} node Node.
+ * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line
+ * breaks.
+ * @return {string} All text content.
+ * @api
+ */
+ol.xml.getAllTextContent = function(node, normalizeWhitespace) {
+ return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join('');
+};
+
+
+/**
+ * Recursively grab all text content of child nodes into a single string.
+ * @param {Node} node Node.
+ * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line
+ * breaks.
+ * @param {Array.<string>} accumulator Accumulator.
+ * @private
+ * @return {Array.<string>} Accumulator.
+ */
+ol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) {
+ if (node.nodeType == Node.CDATA_SECTION_NODE ||
+ node.nodeType == Node.TEXT_NODE) {
+ if (normalizeWhitespace) {
+ accumulator.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
+ } else {
+ accumulator.push(node.nodeValue);
+ }
+ } else {
+ var n;
+ for (n = node.firstChild; n; n = n.nextSibling) {
+ ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator);
+ }
+ }
+ return accumulator;
+};
+
+
+/**
+ * @param {?} value Value.
+ * @return {boolean} Is document.
+ */
+ol.xml.isDocument = function(value) {
+ return value instanceof Document;
+};
+
+
+/**
+ * @param {?} value Value.
+ * @return {boolean} Is node.
+ */
+ol.xml.isNode = function(value) {
+ return value instanceof Node;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {?string} namespaceURI Namespace URI.
+ * @param {string} name Attribute name.
+ * @return {string} Value
+ */
+ol.xml.getAttributeNS = function(node, namespaceURI, name) {
+ return node.getAttributeNS(namespaceURI, name) || '';
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {?string} namespaceURI Namespace URI.
+ * @param {string} name Attribute name.
+ * @param {string|number} value Value.
+ */
+ol.xml.setAttributeNS = function(node, namespaceURI, name, value) {
+ node.setAttributeNS(namespaceURI, name, value);
+};
+
+
+/**
+ * Parse an XML string to an XML Document.
+ * @param {string} xml XML.
+ * @return {Document} Document.
+ * @api
+ */
+ol.xml.parse = function(xml) {
+ return new DOMParser().parseFromString(xml, 'application/xml');
+};
+
+
+/**
+ * Make an array extender function for extending the array at the top of the
+ * object stack.
+ * @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)}
+ * valueReader Value reader.
+ * @param {T=} opt_this The object to use as `this` in `valueReader`.
+ * @return {ol.XmlParser} Parser.
+ * @template T
+ */
+ol.xml.makeArrayExtender = function(valueReader, opt_this) {
+ return (
+ /**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ */
+ function(node, objectStack) {
+ var value = valueReader.call(opt_this, node, objectStack);
+ if (value !== undefined) {
+ goog.asserts.assert(Array.isArray(value),
+ 'valueReader function is expected to return an array of values');
+ var array = /** @type {Array.<*>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(array),
+ 'objectStack is supposed to be an array of arrays');
+ ol.array.extend(array, value);
+ }
+ });
+};
+
+
+/**
+ * Make an array pusher function for pushing to the array at the top of the
+ * object stack.
+ * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
+ * @param {T=} opt_this The object to use as `this` in `valueReader`.
+ * @return {ol.XmlParser} Parser.
+ * @template T
+ */
+ol.xml.makeArrayPusher = function(valueReader, opt_this) {
+ return (
+ /**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ */
+ function(node, objectStack) {
+ var value = valueReader.call(opt_this !== undefined ? opt_this : this,
+ node, objectStack);
+ if (value !== undefined) {
+ var array = objectStack[objectStack.length - 1];
+ goog.asserts.assert(Array.isArray(array),
+ 'objectStack is supposed to be an array of arrays');
+ array.push(value);
+ }
+ });
+};
+
+
+/**
+ * Make an object stack replacer function for replacing the object at the
+ * top of the stack.
+ * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
+ * @param {T=} opt_this The object to use as `this` in `valueReader`.
+ * @return {ol.XmlParser} Parser.
+ * @template T
+ */
+ol.xml.makeReplacer = function(valueReader, opt_this) {
+ return (
+ /**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ */
+ function(node, objectStack) {
+ var value = valueReader.call(opt_this !== undefined ? opt_this : this,
+ node, objectStack);
+ if (value !== undefined) {
+ objectStack[objectStack.length - 1] = value;
+ }
+ });
+};
+
+
+/**
+ * Make an object property pusher function for adding a property to the
+ * object at the top of the stack.
+ * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
+ * @param {string=} opt_property Property.
+ * @param {T=} opt_this The object to use as `this` in `valueReader`.
+ * @return {ol.XmlParser} Parser.
+ * @template T
+ */
+ol.xml.makeObjectPropertyPusher = function(valueReader, opt_property, opt_this) {
+ goog.asserts.assert(valueReader !== undefined,
+ 'undefined valueReader, expected function(this: T, Node, Array.<*>)');
+ return (
+ /**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ */
+ function(node, objectStack) {
+ var value = valueReader.call(opt_this !== undefined ? opt_this : this,
+ node, objectStack);
+ if (value !== undefined) {
+ var object = /** @type {Object} */
+ (objectStack[objectStack.length - 1]);
+ var property = opt_property !== undefined ?
+ opt_property : node.localName;
+ goog.asserts.assert(goog.isObject(object),
+ 'entity from stack was not an object');
+ var array;
+ if (property in object) {
+ array = object[property];
+ } else {
+ array = object[property] = [];
+ }
+ array.push(value);
+ }
+ });
+};
+
+
+/**
+ * Make an object property setter function.
+ * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
+ * @param {string=} opt_property Property.
+ * @param {T=} opt_this The object to use as `this` in `valueReader`.
+ * @return {ol.XmlParser} Parser.
+ * @template T
+ */
+ol.xml.makeObjectPropertySetter = function(valueReader, opt_property, opt_this) {
+ goog.asserts.assert(valueReader !== undefined,
+ 'undefined valueReader, expected function(this: T, Node, Array.<*>)');
+ return (
+ /**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ */
+ function(node, objectStack) {
+ var value = valueReader.call(opt_this !== undefined ? opt_this : this,
+ node, objectStack);
+ if (value !== undefined) {
+ var object = /** @type {Object} */
+ (objectStack[objectStack.length - 1]);
+ var property = opt_property !== undefined ?
+ opt_property : node.localName;
+ goog.asserts.assert(goog.isObject(object),
+ 'entity from stack was not an object');
+ object[property] = value;
+ }
+ });
+};
+
+
+/**
+ * Create a serializer that appends nodes written by its `nodeWriter` to its
+ * designated parent. The parent is the `node` of the
+ * {@link ol.XmlNodeStackItem} at the top of the `objectStack`.
+ * @param {function(this: T, Node, V, Array.<*>)}
+ * nodeWriter Node writer.
+ * @param {T=} opt_this The object to use as `this` in `nodeWriter`.
+ * @return {ol.XmlSerializer} Serializer.
+ * @template T, V
+ */
+ol.xml.makeChildAppender = function(nodeWriter, opt_this) {
+ return function(node, value, objectStack) {
+ nodeWriter.call(opt_this !== undefined ? opt_this : this,
+ node, value, objectStack);
+ var parent = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(parent),
+ 'entity from stack was not an object');
+ var parentNode = parent.node;
+ goog.asserts.assert(ol.xml.isNode(parentNode) ||
+ ol.xml.isDocument(parentNode),
+ 'expected parentNode %s to be a Node or a Document', parentNode);
+ parentNode.appendChild(node);
+ };
+};
+
+
+/**
+ * Create a serializer that calls the provided `nodeWriter` from
+ * {@link ol.xml.serialize}. This can be used by the parent writer to have the
+ * 'nodeWriter' called with an array of values when the `nodeWriter` was
+ * designed to serialize a single item. An example would be a LineString
+ * geometry writer, which could be reused for writing MultiLineString
+ * geometries.
+ * @param {function(this: T, Node, V, Array.<*>)}
+ * nodeWriter Node writer.
+ * @param {T=} opt_this The object to use as `this` in `nodeWriter`.
+ * @return {ol.XmlSerializer} Serializer.
+ * @template T, V
+ */
+ol.xml.makeArraySerializer = function(nodeWriter, opt_this) {
+ var serializersNS, nodeFactory;
+ return function(node, value, objectStack) {
+ if (serializersNS === undefined) {
+ serializersNS = {};
+ var serializers = {};
+ serializers[node.localName] = nodeWriter;
+ serializersNS[node.namespaceURI] = serializers;
+ nodeFactory = ol.xml.makeSimpleNodeFactory(node.localName);
+ }
+ ol.xml.serialize(serializersNS, nodeFactory, value, objectStack);
+ };
+};
+
+
+/**
+ * Create a node factory which can use the `opt_keys` passed to
+ * {@link ol.xml.serialize} or {@link ol.xml.pushSerializeAndPop} as node names,
+ * or a fixed node name. The namespace of the created nodes can either be fixed,
+ * or the parent namespace will be used.
+ * @param {string=} opt_nodeName Fixed node name which will be used for all
+ * created nodes. If not provided, the 3rd argument to the resulting node
+ * factory needs to be provided and will be the nodeName.
+ * @param {string=} opt_namespaceURI Fixed namespace URI which will be used for
+ * all created nodes. If not provided, the namespace of the parent node will
+ * be used.
+ * @return {function(*, Array.<*>, string=): (Node|undefined)} Node factory.
+ */
+ol.xml.makeSimpleNodeFactory = function(opt_nodeName, opt_namespaceURI) {
+ var fixedNodeName = opt_nodeName;
+ return (
+ /**
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node} Node.
+ */
+ function(value, objectStack, opt_nodeName) {
+ var context = objectStack[objectStack.length - 1];
+ var node = context.node;
+ goog.asserts.assert(ol.xml.isNode(node) || ol.xml.isDocument(node),
+ 'expected node %s to be a Node or a Document', node);
+ var nodeName = fixedNodeName;
+ if (nodeName === undefined) {
+ nodeName = opt_nodeName;
+ }
+ var namespaceURI = opt_namespaceURI;
+ if (opt_namespaceURI === undefined) {
+ namespaceURI = node.namespaceURI;
+ }
+ goog.asserts.assert(nodeName !== undefined, 'nodeName was undefined');
+ return ol.xml.createElementNS(namespaceURI, nodeName);
+ }
+ );
+};
+
+
+/**
+ * A node factory that creates a node using the parent's `namespaceURI` and the
+ * `nodeName` passed by {@link ol.xml.serialize} or
+ * {@link ol.xml.pushSerializeAndPop} to the node factory.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ */
+ol.xml.OBJECT_PROPERTY_NODE_FACTORY = ol.xml.makeSimpleNodeFactory();
+
+
+/**
+ * Create an array of `values` to be used with {@link ol.xml.serialize} or
+ * {@link ol.xml.pushSerializeAndPop}, where `orderedKeys` has to be provided as
+ * `opt_key` argument.
+ * @param {Object.<string, V>} object Key-value pairs for the sequence. Keys can
+ * be a subset of the `orderedKeys`.
+ * @param {Array.<string>} orderedKeys Keys in the order of the sequence.
+ * @return {Array.<V>} Values in the order of the sequence. The resulting array
+ * has the same length as the `orderedKeys` array. Values that are not
+ * present in `object` will be `undefined` in the resulting array.
+ * @template V
+ */
+ol.xml.makeSequence = function(object, orderedKeys) {
+ var length = orderedKeys.length;
+ var sequence = new Array(length);
+ for (var i = 0; i < length; ++i) {
+ sequence[i] = object[orderedKeys[i]];
+ }
+ return sequence;
+};
+
+
+/**
+ * Create a namespaced structure, using the same values for each namespace.
+ * This can be used as a starting point for versioned parsers, when only a few
+ * values are version specific.
+ * @param {Array.<string>} namespaceURIs Namespace URIs.
+ * @param {T} structure Structure.
+ * @param {Object.<string, T>=} opt_structureNS Namespaced structure to add to.
+ * @return {Object.<string, T>} Namespaced structure.
+ * @template T
+ */
+ol.xml.makeStructureNS = function(namespaceURIs, structure, opt_structureNS) {
+ /**
+ * @type {Object.<string, *>}
+ */
+ var structureNS = opt_structureNS !== undefined ? opt_structureNS : {};
+ var i, ii;
+ for (i = 0, ii = namespaceURIs.length; i < ii; ++i) {
+ structureNS[namespaceURIs[i]] = structure;
+ }
+ return structureNS;
+};
+
+
+/**
+ * Parse a node using the parsers and object stack.
+ * @param {Object.<string, Object.<string, ol.XmlParser>>} parsersNS
+ * Parsers by namespace.
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {*=} opt_this The object to use as `this`.
+ */
+ol.xml.parseNode = function(parsersNS, node, objectStack, opt_this) {
+ var n;
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ var parsers = parsersNS[n.namespaceURI];
+ if (parsers !== undefined) {
+ var parser = parsers[n.localName];
+ if (parser !== undefined) {
+ parser.call(opt_this, n, objectStack);
+ }
+ }
+ }
+};
+
+
+/**
+ * Push an object on top of the stack, parse and return the popped object.
+ * @param {T} object Object.
+ * @param {Object.<string, Object.<string, ol.XmlParser>>} parsersNS
+ * Parsers by namespace.
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {*=} opt_this The object to use as `this`.
+ * @return {T} Object.
+ * @template T
+ */
+ol.xml.pushParseAndPop = function(
+ object, parsersNS, node, objectStack, opt_this) {
+ objectStack.push(object);
+ ol.xml.parseNode(parsersNS, node, objectStack, opt_this);
+ return objectStack.pop();
+};
+
+
+/**
+ * Walk through an array of `values` and call a serializer for each value.
+ * @param {Object.<string, Object.<string, ol.XmlSerializer>>} serializersNS
+ * Namespaced serializers.
+ * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory
+ * Node factory. The `nodeFactory` creates the node whose namespace and name
+ * will be used to choose a node writer from `serializersNS`. This
+ * separation allows us to decide what kind of node to create, depending on
+ * the value we want to serialize. An example for this would be different
+ * geometry writers based on the geometry type.
+ * @param {Array.<*>} values Values to serialize. An example would be an array
+ * of {@link ol.Feature} instances.
+ * @param {Array.<*>} objectStack Node stack.
+ * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the
+ * `nodeFactory`. This is used for serializing object literals where the
+ * node name relates to the property key. The array length of `opt_keys` has
+ * to match the length of `values`. For serializing a sequence, `opt_keys`
+ * determines the order of the sequence.
+ * @param {T=} opt_this The object to use as `this` for the node factory and
+ * serializers.
+ * @template T
+ */
+ol.xml.serialize = function(
+ serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) {
+ var length = (opt_keys !== undefined ? opt_keys : values).length;
+ var value, node;
+ for (var i = 0; i < length; ++i) {
+ value = values[i];
+ if (value !== undefined) {
+ node = nodeFactory.call(opt_this, value, objectStack,
+ opt_keys !== undefined ? opt_keys[i] : undefined);
+ if (node !== undefined) {
+ serializersNS[node.namespaceURI][node.localName]
+ .call(opt_this, node, value, objectStack);
+ }
+ }
+ }
+};
+
+
+/**
+ * @param {O} object Object.
+ * @param {Object.<string, Object.<string, ol.XmlSerializer>>} serializersNS
+ * Namespaced serializers.
+ * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory
+ * Node factory. The `nodeFactory` creates the node whose namespace and name
+ * will be used to choose a node writer from `serializersNS`. This
+ * separation allows us to decide what kind of node to create, depending on
+ * the value we want to serialize. An example for this would be different
+ * geometry writers based on the geometry type.
+ * @param {Array.<*>} values Values to serialize. An example would be an array
+ * of {@link ol.Feature} instances.
+ * @param {Array.<*>} objectStack Node stack.
+ * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the
+ * `nodeFactory`. This is used for serializing object literals where the
+ * node name relates to the property key. The array length of `opt_keys` has
+ * to match the length of `values`. For serializing a sequence, `opt_keys`
+ * determines the order of the sequence.
+ * @param {T=} opt_this The object to use as `this` for the node factory and
+ * serializers.
+ * @return {O|undefined} Object.
+ * @template O, T
+ */
+ol.xml.pushSerializeAndPop = function(object,
+ serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) {
+ objectStack.push(object);
+ ol.xml.serialize(
+ serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this);
+ return objectStack.pop();
+};
+
+goog.provide('ol.featureloader');
+
+goog.require('goog.asserts');
+goog.require('ol.TileState');
+goog.require('ol.VectorTile');
+goog.require('ol.format.FormatType');
+goog.require('ol.proj');
+goog.require('ol.proj.Projection');
+goog.require('ol.xml');
+
+
+/**
+ * @param {string|ol.FeatureUrlFunction} url Feature URL service.
+ * @param {ol.format.Feature} format Feature format.
+ * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection)|function(this:ol.source.Vector, Array.<ol.Feature>)} success
+ * Function called with the loaded features and optionally with the data
+ * projection. Called with the vector tile or source as `this`.
+ * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure
+ * Function called when loading failed. Called with the vector tile or
+ * source as `this`.
+ * @return {ol.FeatureLoader} The feature loader.
+ */
+ol.featureloader.loadFeaturesXhr = function(url, format, success, failure) {
+ return (
+ /**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {ol.proj.Projection} projection Projection.
+ * @this {ol.source.Vector|ol.VectorTile}
+ */
+ function(extent, resolution, projection) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET',
+ typeof url === 'function' ? url(extent, resolution, projection) : url,
+ true);
+ if (format.getType() == ol.format.FormatType.ARRAY_BUFFER) {
+ xhr.responseType = 'arraybuffer';
+ }
+ /**
+ * @param {Event} event Event.
+ * @private
+ */
+ xhr.onload = function(event) {
+ if (xhr.status >= 200 && xhr.status < 300) {
+ var type = format.getType();
+ /** @type {Document|Node|Object|string|undefined} */
+ var source;
+ if (type == ol.format.FormatType.JSON ||
+ type == ol.format.FormatType.TEXT) {
+ source = xhr.responseText;
+ } else if (type == ol.format.FormatType.XML) {
+ source = xhr.responseXML;
+ if (!source) {
+ source = ol.xml.parse(xhr.responseText);
+ }
+ } else if (type == ol.format.FormatType.ARRAY_BUFFER) {
+ source = /** @type {ArrayBuffer} */ (xhr.response);
+ } else {
+ goog.asserts.fail('unexpected format type');
+ }
+ if (source) {
+ success.call(this, format.readFeatures(source,
+ {featureProjection: projection}),
+ format.readProjection(source));
+ } else {
+ goog.asserts.fail('undefined or null source');
+ }
+ } else {
+ failure.call(this);
+ }
+ }.bind(this);
+ xhr.send();
+ });
+};
+
+
+/**
+ * Create an XHR feature loader for a `url` and `format`. The feature loader
+ * loads features (with XHR), parses the features, and adds them to the
+ * vector tile.
+ * @param {string|ol.FeatureUrlFunction} url Feature URL service.
+ * @param {ol.format.Feature} format Feature format.
+ * @return {ol.FeatureLoader} The feature loader.
+ * @api
+ */
+ol.featureloader.tile = function(url, format) {
+ return ol.featureloader.loadFeaturesXhr(url, format,
+ /**
+ * @param {Array.<ol.Feature>} features The loaded features.
+ * @param {ol.proj.Projection} dataProjection Data projection.
+ * @this {ol.VectorTile}
+ */
+ function(features, dataProjection) {
+ this.setProjection(dataProjection);
+ this.setFeatures(features);
+ },
+ /**
+ * @this {ol.VectorTile}
+ */
+ function() {
+ this.setState(ol.TileState.ERROR);
+ });
+};
+
+
+/**
+ * Create an XHR feature loader for a `url` and `format`. The feature loader
+ * loads features (with XHR), parses the features, and adds them to the
+ * vector source.
+ * @param {string|ol.FeatureUrlFunction} url Feature URL service.
+ * @param {ol.format.Feature} format Feature format.
+ * @return {ol.FeatureLoader} The feature loader.
+ * @api
+ */
+ol.featureloader.xhr = function(url, format) {
+ return ol.featureloader.loadFeaturesXhr(url, format,
+ /**
+ * @param {Array.<ol.Feature>} features The loaded features.
+ * @param {ol.proj.Projection} dataProjection Data projection.
+ * @this {ol.source.Vector}
+ */
+ function(features, dataProjection) {
+ this.addFeatures(features);
+ }, /* FIXME handle error */ ol.nullFunction);
+};
+
+goog.provide('ol.loadingstrategy');
+
+
+/**
+ * Strategy function for loading all features with a single request.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @return {Array.<ol.Extent>} Extents.
+ * @api
+ */
+ol.loadingstrategy.all = function(extent, resolution) {
+ return [[-Infinity, -Infinity, Infinity, Infinity]];
+};
+
+
+/**
+ * Strategy function for loading features based on the view's extent and
+ * resolution.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @return {Array.<ol.Extent>} Extents.
+ * @api
+ */
+ol.loadingstrategy.bbox = function(extent, resolution) {
+ return [extent];
+};
+
+
+/**
+ * Creates a strategy function for loading features based on a tile grid.
+ * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @return {function(ol.Extent, number): Array.<ol.Extent>} Loading strategy.
+ * @api
+ */
+ol.loadingstrategy.tile = function(tileGrid) {
+ return (
+ /**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @return {Array.<ol.Extent>} Extents.
+ */
+ function(extent, resolution) {
+ var z = tileGrid.getZForResolution(resolution);
+ var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
+ /** @type {Array.<ol.Extent>} */
+ var extents = [];
+ /** @type {ol.TileCoord} */
+ var tileCoord = [z, 0, 0];
+ for (tileCoord[1] = tileRange.minX; tileCoord[1] <= tileRange.maxX;
+ ++tileCoord[1]) {
+ for (tileCoord[2] = tileRange.minY; tileCoord[2] <= tileRange.maxY;
+ ++tileCoord[2]) {
+ extents.push(tileGrid.getTileCoordExtent(tileCoord));
+ }
+ }
+ return extents;
+ });
+};
+
+goog.provide('ol.ext.rbush');
+/** @typedef {function(*)} */
+ol.ext.rbush;
+(function() {
+var exports = {};
+var module = {exports: exports};
+var define;
+/**
+ * @fileoverview
+ * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.rbush = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = rbush;
+
+var quickselect = _dereq_('quickselect');
+
+function rbush(maxEntries, format) {
+ if (!(this instanceof rbush)) return new rbush(maxEntries, format);
+
+ // max entries in a node is 9 by default; min node fill is 40% for best performance
+ this._maxEntries = Math.max(4, maxEntries || 9);
+ this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
+
+ if (format) {
+ this._initFormat(format);
+ }
+
+ this.clear();
+}
+
+rbush.prototype = {
+
+ all: function () {
+ return this._all(this.data, []);
+ },
+
+ search: function (bbox) {
+
+ var node = this.data,
+ result = [],
+ toBBox = this.toBBox;
+
+ if (!intersects(bbox, node)) return result;
+
+ var nodesToSearch = [],
+ i, len, child, childBBox;
+
+ while (node) {
+ for (i = 0, len = node.children.length; i < len; i++) {
+
+ child = node.children[i];
+ childBBox = node.leaf ? toBBox(child) : child;
+
+ if (intersects(bbox, childBBox)) {
+ if (node.leaf) result.push(child);
+ else if (contains(bbox, childBBox)) this._all(child, result);
+ else nodesToSearch.push(child);
+ }
+ }
+ node = nodesToSearch.pop();
+ }
+
+ return result;
+ },
+
+ collides: function (bbox) {
+
+ var node = this.data,
+ toBBox = this.toBBox;
+
+ if (!intersects(bbox, node)) return false;
+
+ var nodesToSearch = [],
+ i, len, child, childBBox;
+
+ while (node) {
+ for (i = 0, len = node.children.length; i < len; i++) {
+
+ child = node.children[i];
+ childBBox = node.leaf ? toBBox(child) : child;
+
+ if (intersects(bbox, childBBox)) {
+ if (node.leaf || contains(bbox, childBBox)) return true;
+ nodesToSearch.push(child);
+ }
+ }
+ node = nodesToSearch.pop();
+ }
+
+ return false;
+ },
+
+ load: function (data) {
+ if (!(data && data.length)) return this;
+
+ if (data.length < this._minEntries) {
+ for (var i = 0, len = data.length; i < len; i++) {
+ this.insert(data[i]);
+ }
+ return this;
+ }
+
+ // recursively build the tree with the given data from stratch using OMT algorithm
+ var node = this._build(data.slice(), 0, data.length - 1, 0);
+
+ if (!this.data.children.length) {
+ // save as is if tree is empty
+ this.data = node;
+
+ } else if (this.data.height === node.height) {
+ // split root if trees have the same height
+ this._splitRoot(this.data, node);
+
+ } else {
+ if (this.data.height < node.height) {
+ // swap trees if inserted one is bigger
+ var tmpNode = this.data;
+ this.data = node;
+ node = tmpNode;
+ }
+
+ // insert the small tree into the large tree at appropriate level
+ this._insert(node, this.data.height - node.height - 1, true);
+ }
+
+ return this;
+ },
+
+ insert: function (item) {
+ if (item) this._insert(item, this.data.height - 1);
+ return this;
+ },
+
+ clear: function () {
+ this.data = createNode([]);
+ return this;
+ },
+
+ remove: function (item, equalsFn) {
+ if (!item) return this;
+
+ var node = this.data,
+ bbox = this.toBBox(item),
+ path = [],
+ indexes = [],
+ i, parent, index, goingUp;
+
+ // depth-first iterative tree traversal
+ while (node || path.length) {
+
+ if (!node) { // go up
+ node = path.pop();
+ parent = path[path.length - 1];
+ i = indexes.pop();
+ goingUp = true;
+ }
+
+ if (node.leaf) { // check current node
+ index = findItem(item, node.children, equalsFn);
+
+ if (index !== -1) {
+ // item found, remove the item and condense tree upwards
+ node.children.splice(index, 1);
+ path.push(node);
+ this._condense(path);
+ return this;
+ }
+ }
+
+ if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
+ path.push(node);
+ indexes.push(i);
+ i = 0;
+ parent = node;
+ node = node.children[0];
+
+ } else if (parent) { // go right
+ i++;
+ node = parent.children[i];
+ goingUp = false;
+
+ } else node = null; // nothing found
+ }
+
+ return this;
+ },
+
+ toBBox: function (item) { return item; },
+
+ compareMinX: compareNodeMinX,
+ compareMinY: compareNodeMinY,
+
+ toJSON: function () { return this.data; },
+
+ fromJSON: function (data) {
+ this.data = data;
+ return this;
+ },
+
+ _all: function (node, result) {
+ var nodesToSearch = [];
+ while (node) {
+ if (node.leaf) result.push.apply(result, node.children);
+ else nodesToSearch.push.apply(nodesToSearch, node.children);
+
+ node = nodesToSearch.pop();
+ }
+ return result;
+ },
+
+ _build: function (items, left, right, height) {
+
+ var N = right - left + 1,
+ M = this._maxEntries,
+ node;
+
+ if (N <= M) {
+ // reached leaf level; return leaf
+ node = createNode(items.slice(left, right + 1));
+ calcBBox(node, this.toBBox);
+ return node;
+ }
+
+ if (!height) {
+ // target height of the bulk-loaded tree
+ height = Math.ceil(Math.log(N) / Math.log(M));
+
+ // target number of root entries to maximize storage utilization
+ M = Math.ceil(N / Math.pow(M, height - 1));
+ }
+
+ node = createNode([]);
+ node.leaf = false;
+ node.height = height;
+
+ // split the items into M mostly square tiles
+
+ var N2 = Math.ceil(N / M),
+ N1 = N2 * Math.ceil(Math.sqrt(M)),
+ i, j, right2, right3;
+
+ multiSelect(items, left, right, N1, this.compareMinX);
+
+ for (i = left; i <= right; i += N1) {
+
+ right2 = Math.min(i + N1 - 1, right);
+
+ multiSelect(items, i, right2, N2, this.compareMinY);
+
+ for (j = i; j <= right2; j += N2) {
+
+ right3 = Math.min(j + N2 - 1, right2);
+
+ // pack each entry recursively
+ node.children.push(this._build(items, j, right3, height - 1));
+ }
+ }
+
+ calcBBox(node, this.toBBox);
+
+ return node;
+ },
+
+ _chooseSubtree: function (bbox, node, level, path) {
+
+ var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
+
+ while (true) {
+ path.push(node);
+
+ if (node.leaf || path.length - 1 === level) break;
+
+ minArea = minEnlargement = Infinity;
+
+ for (i = 0, len = node.children.length; i < len; i++) {
+ child = node.children[i];
+ area = bboxArea(child);
+ enlargement = enlargedArea(bbox, child) - area;
+
+ // choose entry with the least area enlargement
+ if (enlargement < minEnlargement) {
+ minEnlargement = enlargement;
+ minArea = area < minArea ? area : minArea;
+ targetNode = child;
+
+ } else if (enlargement === minEnlargement) {
+ // otherwise choose one with the smallest area
+ if (area < minArea) {
+ minArea = area;
+ targetNode = child;
+ }
+ }
+ }
+
+ node = targetNode || node.children[0];
+ }
+
+ return node;
+ },
+
+ _insert: function (item, level, isNode) {
+
+ var toBBox = this.toBBox,
+ bbox = isNode ? item : toBBox(item),
+ insertPath = [];
+
+ // find the best node for accommodating the item, saving all nodes along the path too
+ var node = this._chooseSubtree(bbox, this.data, level, insertPath);
+
+ // put the item into the node
+ node.children.push(item);
+ extend(node, bbox);
+
+ // split on node overflow; propagate upwards if necessary
+ while (level >= 0) {
+ if (insertPath[level].children.length > this._maxEntries) {
+ this._split(insertPath, level);
+ level--;
+ } else break;
+ }
+
+ // adjust bboxes along the insertion path
+ this._adjustParentBBoxes(bbox, insertPath, level);
+ },
+
+ // split overflowed node into two
+ _split: function (insertPath, level) {
+
+ var node = insertPath[level],
+ M = node.children.length,
+ m = this._minEntries;
+
+ this._chooseSplitAxis(node, m, M);
+
+ var splitIndex = this._chooseSplitIndex(node, m, M);
+
+ var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
+ newNode.height = node.height;
+ newNode.leaf = node.leaf;
+
+ calcBBox(node, this.toBBox);
+ calcBBox(newNode, this.toBBox);
+
+ if (level) insertPath[level - 1].children.push(newNode);
+ else this._splitRoot(node, newNode);
+ },
+
+ _splitRoot: function (node, newNode) {
+ // split root node
+ this.data = createNode([node, newNode]);
+ this.data.height = node.height + 1;
+ this.data.leaf = false;
+ calcBBox(this.data, this.toBBox);
+ },
+
+ _chooseSplitIndex: function (node, m, M) {
+
+ var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
+
+ minOverlap = minArea = Infinity;
+
+ for (i = m; i <= M - m; i++) {
+ bbox1 = distBBox(node, 0, i, this.toBBox);
+ bbox2 = distBBox(node, i, M, this.toBBox);
+
+ overlap = intersectionArea(bbox1, bbox2);
+ area = bboxArea(bbox1) + bboxArea(bbox2);
+
+ // choose distribution with minimum overlap
+ if (overlap < minOverlap) {
+ minOverlap = overlap;
+ index = i;
+
+ minArea = area < minArea ? area : minArea;
+
+ } else if (overlap === minOverlap) {
+ // otherwise choose distribution with minimum area
+ if (area < minArea) {
+ minArea = area;
+ index = i;
+ }
+ }
+ }
+
+ return index;
+ },
+
+ // sorts node children by the best axis for split
+ _chooseSplitAxis: function (node, m, M) {
+
+ var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
+ compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
+ xMargin = this._allDistMargin(node, m, M, compareMinX),
+ yMargin = this._allDistMargin(node, m, M, compareMinY);
+
+ // if total distributions margin value is minimal for x, sort by minX,
+ // otherwise it's already sorted by minY
+ if (xMargin < yMargin) node.children.sort(compareMinX);
+ },
+
+ // total margin of all possible split distributions where each node is at least m full
+ _allDistMargin: function (node, m, M, compare) {
+
+ node.children.sort(compare);
+
+ var toBBox = this.toBBox,
+ leftBBox = distBBox(node, 0, m, toBBox),
+ rightBBox = distBBox(node, M - m, M, toBBox),
+ margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
+ i, child;
+
+ for (i = m; i < M - m; i++) {
+ child = node.children[i];
+ extend(leftBBox, node.leaf ? toBBox(child) : child);
+ margin += bboxMargin(leftBBox);
+ }
+
+ for (i = M - m - 1; i >= m; i--) {
+ child = node.children[i];
+ extend(rightBBox, node.leaf ? toBBox(child) : child);
+ margin += bboxMargin(rightBBox);
+ }
+
+ return margin;
+ },
+
+ _adjustParentBBoxes: function (bbox, path, level) {
+ // adjust bboxes along the given tree path
+ for (var i = level; i >= 0; i--) {
+ extend(path[i], bbox);
+ }
+ },
+
+ _condense: function (path) {
+ // go through the path, removing empty nodes and updating bboxes
+ for (var i = path.length - 1, siblings; i >= 0; i--) {
+ if (path[i].children.length === 0) {
+ if (i > 0) {
+ siblings = path[i - 1].children;
+ siblings.splice(siblings.indexOf(path[i]), 1);
+
+ } else this.clear();
+
+ } else calcBBox(path[i], this.toBBox);
+ }
+ },
+
+ _initFormat: function (format) {
+ // data format (minX, minY, maxX, maxY accessors)
+
+ // uses eval-type function compilation instead of just accepting a toBBox function
+ // because the algorithms are very sensitive to sorting functions performance,
+ // so they should be dead simple and without inner calls
+
+ var compareArr = ['return a', ' - b', ';'];
+
+ this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
+ this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
+
+ this.toBBox = new Function('a',
+ 'return {minX: a' + format[0] +
+ ', minY: a' + format[1] +
+ ', maxX: a' + format[2] +
+ ', maxY: a' + format[3] + '};');
+ }
+};
+
+function findItem(item, items, equalsFn) {
+ if (!equalsFn) return items.indexOf(item);
+
+ for (var i = 0; i < items.length; i++) {
+ if (equalsFn(item, items[i])) return i;
+ }
+ return -1;
+}
+
+// calculate node's bbox from bboxes of its children
+function calcBBox(node, toBBox) {
+ distBBox(node, 0, node.children.length, toBBox, node);
+}
+
+// min bounding rectangle of node children from k to p-1
+function distBBox(node, k, p, toBBox, destNode) {
+ if (!destNode) destNode = createNode(null);
+ destNode.minX = Infinity;
+ destNode.minY = Infinity;
+ destNode.maxX = -Infinity;
+ destNode.maxY = -Infinity;
+
+ for (var i = k, child; i < p; i++) {
+ child = node.children[i];
+ extend(destNode, node.leaf ? toBBox(child) : child);
+ }
+
+ return destNode;
+}
+
+function extend(a, b) {
+ a.minX = Math.min(a.minX, b.minX);
+ a.minY = Math.min(a.minY, b.minY);
+ a.maxX = Math.max(a.maxX, b.maxX);
+ a.maxY = Math.max(a.maxY, b.maxY);
+ return a;
+}
+
+function compareNodeMinX(a, b) { return a.minX - b.minX; }
+function compareNodeMinY(a, b) { return a.minY - b.minY; }
+
+function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
+function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
+
+function enlargedArea(a, b) {
+ return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
+ (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
+}
+
+function intersectionArea(a, b) {
+ var minX = Math.max(a.minX, b.minX),
+ minY = Math.max(a.minY, b.minY),
+ maxX = Math.min(a.maxX, b.maxX),
+ maxY = Math.min(a.maxY, b.maxY);
+
+ return Math.max(0, maxX - minX) *
+ Math.max(0, maxY - minY);
+}
+
+function contains(a, b) {
+ return a.minX <= b.minX &&
+ a.minY <= b.minY &&
+ b.maxX <= a.maxX &&
+ b.maxY <= a.maxY;
+}
+
+function intersects(a, b) {
+ return b.minX <= a.maxX &&
+ b.minY <= a.maxY &&
+ b.maxX >= a.minX &&
+ b.maxY >= a.minY;
+}
+
+function createNode(children) {
+ return {
+ children: children,
+ height: 1,
+ leaf: true,
+ minX: Infinity,
+ minY: Infinity,
+ maxX: -Infinity,
+ maxY: -Infinity
+ };
+}
+
+// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
+// combines selection algorithm with binary divide & conquer approach
+
+function multiSelect(arr, left, right, n, compare) {
+ var stack = [left, right],
+ mid;
+
+ while (stack.length) {
+ right = stack.pop();
+ left = stack.pop();
+
+ if (right - left <= n) continue;
+
+ mid = left + Math.ceil((right - left) / n / 2) * n;
+ quickselect(arr, mid, left, right, compare);
+
+ stack.push(left, mid, mid, right);
+ }
+}
+
+},{"quickselect":2}],2:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = partialSort;
+
+// Floyd-Rivest selection algorithm:
+// Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
+// The k-th element will have the (k - left + 1)th smallest value in [left, right]
+
+function partialSort(arr, k, left, right, compare) {
+ left = left || 0;
+ right = right || (arr.length - 1);
+ compare = compare || defaultCompare;
+
+ while (right > left) {
+ if (right - left > 600) {
+ var n = right - left + 1;
+ var m = k - left + 1;
+ var z = Math.log(n);
+ var s = 0.5 * Math.exp(2 * z / 3);
+ var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
+ var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
+ var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
+ partialSort(arr, k, newLeft, newRight, compare);
+ }
+
+ var t = arr[k];
+ var i = left;
+ var j = right;
+
+ swap(arr, left, k);
+ if (compare(arr[right], t) > 0) swap(arr, left, right);
+
+ while (i < j) {
+ swap(arr, i, j);
+ i++;
+ j--;
+ while (compare(arr[i], t) < 0) i++;
+ while (compare(arr[j], t) > 0) j--;
+ }
+
+ if (compare(arr[left], t) === 0) swap(arr, left, j);
+ else {
+ j++;
+ swap(arr, j, right);
+ }
+
+ if (j <= k) left = j + 1;
+ if (k <= j) right = j - 1;
+ }
+}
+
+function swap(arr, i, j) {
+ var tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+}
+
+function defaultCompare(a, b) {
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+},{}]},{},[1])(1)
+});
+ol.ext.rbush = module.exports;
+})();
+
+goog.provide('ol.structs.RBush');
+
+goog.require('goog.asserts');
+goog.require('ol.ext.rbush');
+goog.require('ol.extent');
+goog.require('ol.object');
+
+
+/**
+ * Wrapper around the RBush by Vladimir Agafonkin.
+ *
+ * @constructor
+ * @param {number=} opt_maxEntries Max entries.
+ * @see https://github.com/mourner/rbush
+ * @struct
+ * @template T
+ */
+ol.structs.RBush = function(opt_maxEntries) {
+
+ /**
+ * @private
+ */
+ this.rbush_ = ol.ext.rbush(opt_maxEntries);
+
+ /**
+ * A mapping between the objects added to this rbush wrapper
+ * and the objects that are actually added to the internal rbush.
+ * @private
+ * @type {Object.<number, ol.RBushEntry>}
+ */
+ this.items_ = {};
+
+ if (goog.DEBUG) {
+ /**
+ * @private
+ * @type {number}
+ */
+ this.readers_ = 0;
+ }
+};
+
+
+/**
+ * Insert a value into the RBush.
+ * @param {ol.Extent} extent Extent.
+ * @param {T} value Value.
+ */
+ol.structs.RBush.prototype.insert = function(extent, value) {
+ if (goog.DEBUG && this.readers_) {
+ throw new Error('Can not insert value while reading');
+ }
+ /** @type {ol.RBushEntry} */
+ var item = {
+ minX: extent[0],
+ minY: extent[1],
+ maxX: extent[2],
+ maxY: extent[3],
+ value: value
+ };
+
+ this.rbush_.insert(item);
+ // remember the object that was added to the internal rbush
+ goog.asserts.assert(!(goog.getUid(value) in this.items_),
+ 'uid (%s) of value (%s) already exists', goog.getUid(value), value);
+ this.items_[goog.getUid(value)] = item;
+};
+
+
+/**
+ * Bulk-insert values into the RBush.
+ * @param {Array.<ol.Extent>} extents Extents.
+ * @param {Array.<T>} values Values.
+ */
+ol.structs.RBush.prototype.load = function(extents, values) {
+ if (goog.DEBUG && this.readers_) {
+ throw new Error('Can not insert values while reading');
+ }
+ goog.asserts.assert(extents.length === values.length,
+ 'extens and values must have same length (%s === %s)',
+ extents.length, values.length);
+
+ var items = new Array(values.length);
+ for (var i = 0, l = values.length; i < l; i++) {
+ var extent = extents[i];
+ var value = values[i];
+
+ /** @type {ol.RBushEntry} */
+ var item = {
+ minX: extent[0],
+ minY: extent[1],
+ maxX: extent[2],
+ maxY: extent[3],
+ value: value
+ };
+ items[i] = item;
+ goog.asserts.assert(!(goog.getUid(value) in this.items_),
+ 'uid (%s) of value (%s) already exists', goog.getUid(value), value);
+ this.items_[goog.getUid(value)] = item;
+ }
+ this.rbush_.load(items);
+};
+
+
+/**
+ * Remove a value from the RBush.
+ * @param {T} value Value.
+ * @return {boolean} Removed.
+ */
+ol.structs.RBush.prototype.remove = function(value) {
+ if (goog.DEBUG && this.readers_) {
+ throw new Error('Can not remove value while reading');
+ }
+ var uid = goog.getUid(value);
+ goog.asserts.assert(uid in this.items_,
+ 'uid (%s) of value (%s) does not exist', uid, value);
+
+ // get the object in which the value was wrapped when adding to the
+ // internal rbush. then use that object to do the removal.
+ var item = this.items_[uid];
+ delete this.items_[uid];
+ return this.rbush_.remove(item) !== null;
+};
+
+
+/**
+ * Update the extent of a value in the RBush.
+ * @param {ol.Extent} extent Extent.
+ * @param {T} value Value.
+ */
+ol.structs.RBush.prototype.update = function(extent, value) {
+ var uid = goog.getUid(value);
+ goog.asserts.assert(uid in this.items_,
+ 'uid (%s) of value (%s) does not exist', uid, value);
+
+ var item = this.items_[uid];
+ var bbox = [item.minX, item.minY, item.maxX, item.maxY];
+ if (!ol.extent.equals(bbox, extent)) {
+ if (goog.DEBUG && this.readers_) {
+ throw new Error('Can not update extent while reading');
+ }
+ this.remove(value);
+ this.insert(extent, value);
+ }
+};
+
+
+/**
+ * Return all values in the RBush.
+ * @return {Array.<T>} All.
+ */
+ol.structs.RBush.prototype.getAll = function() {
+ var items = this.rbush_.all();
+ return items.map(function(item) {
+ return item.value;
+ });
+};
+
+
+/**
+ * Return all values in the given extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {Array.<T>} All in extent.
+ */
+ol.structs.RBush.prototype.getInExtent = function(extent) {
+ /** @type {ol.RBushEntry} */
+ var bbox = {
+ minX: extent[0],
+ minY: extent[1],
+ maxX: extent[2],
+ maxY: extent[3]
+ };
+ var items = this.rbush_.search(bbox);
+ return items.map(function(item) {
+ return item.value;
+ });
+};
+
+
+/**
+ * Calls a callback function with each value in the tree.
+ * If the callback returns a truthy value, this value is returned without
+ * checking the rest of the tree.
+ * @param {function(this: S, T): *} callback Callback.
+ * @param {S=} opt_this The object to use as `this` in `callback`.
+ * @return {*} Callback return value.
+ * @template S
+ */
+ol.structs.RBush.prototype.forEach = function(callback, opt_this) {
+ if (goog.DEBUG) {
+ ++this.readers_;
+ try {
+ return this.forEach_(this.getAll(), callback, opt_this);
+ } finally {
+ --this.readers_;
+ }
+ } else {
+ return this.forEach_(this.getAll(), callback, opt_this);
+ }
+};
+
+
+/**
+ * Calls a callback function with each value in the provided extent.
+ * @param {ol.Extent} extent Extent.
+ * @param {function(this: S, T): *} callback Callback.
+ * @param {S=} opt_this The object to use as `this` in `callback`.
+ * @return {*} Callback return value.
+ * @template S
+ */
+ol.structs.RBush.prototype.forEachInExtent = function(extent, callback, opt_this) {
+ if (goog.DEBUG) {
+ ++this.readers_;
+ try {
+ return this.forEach_(this.getInExtent(extent), callback, opt_this);
+ } finally {
+ --this.readers_;
+ }
+ } else {
+ return this.forEach_(this.getInExtent(extent), callback, opt_this);
+ }
+};
+
+
+/**
+ * @param {Array.<T>} values Values.
+ * @param {function(this: S, T): *} callback Callback.
+ * @param {S=} opt_this The object to use as `this` in `callback`.
+ * @private
+ * @return {*} Callback return value.
+ * @template S
+ */
+ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) {
+ var result;
+ for (var i = 0, l = values.length; i < l; i++) {
+ result = callback.call(opt_this, values[i]);
+ if (result) {
+ return result;
+ }
+ }
+ return result;
+};
+
+
+/**
+ * @return {boolean} Is empty.
+ */
+ol.structs.RBush.prototype.isEmpty = function() {
+ return ol.object.isEmpty(this.items_);
+};
+
+
+/**
+ * Remove all values from the RBush.
+ */
+ol.structs.RBush.prototype.clear = function() {
+ this.rbush_.clear();
+ this.items_ = {};
+};
+
+
+/**
+ * @param {ol.Extent=} opt_extent Extent.
+ * @return {!ol.Extent} Extent.
+ */
+ol.structs.RBush.prototype.getExtent = function(opt_extent) {
+ // FIXME add getExtent() to rbush
+ var data = this.rbush_.data;
+ return [data.minX, data.minY, data.maxX, data.maxY];
+};
+
+// FIXME bulk feature upload - suppress events
+// FIXME make change-detection more refined (notably, geometry hint)
+
+goog.provide('ol.source.Vector');
+goog.provide('ol.source.VectorEvent');
+goog.provide('ol.source.VectorEventType');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.Collection');
+goog.require('ol.CollectionEventType');
+goog.require('ol.Feature');
+goog.require('ol.ObjectEventType');
+goog.require('ol.array');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.featureloader');
+goog.require('ol.loadingstrategy');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.source.Source');
+goog.require('ol.source.State');
+goog.require('ol.structs.RBush');
+
+
+/**
+ * @enum {string}
+ */
+ol.source.VectorEventType = {
+ /**
+ * Triggered when a feature is added to the source.
+ * @event ol.source.VectorEvent#addfeature
+ * @api stable
+ */
+ ADDFEATURE: 'addfeature',
+
+ /**
+ * Triggered when a feature is updated.
+ * @event ol.source.VectorEvent#changefeature
+ * @api
+ */
+ CHANGEFEATURE: 'changefeature',
+
+ /**
+ * Triggered when the clear method is called on the source.
+ * @event ol.source.VectorEvent#clear
+ * @api
+ */
+ CLEAR: 'clear',
+
+ /**
+ * Triggered when a feature is removed from the source.
+ * See {@link ol.source.Vector#clear source.clear()} for exceptions.
+ * @event ol.source.VectorEvent#removefeature
+ * @api stable
+ */
+ REMOVEFEATURE: 'removefeature'
+};
+
+
+/**
+ * @classdesc
+ * Provides a source of features for vector layers. Vector features provided
+ * by this source are suitable for editing. See {@link ol.source.VectorTile} for
+ * vector data that is optimized for rendering.
+ *
+ * @constructor
+ * @extends {ol.source.Source}
+ * @fires ol.source.VectorEvent
+ * @param {olx.source.VectorOptions=} opt_options Vector source options.
+ * @api stable
+ */
+ol.source.Vector = function(opt_options) {
+
+ var options = opt_options || {};
+
+ ol.source.Source.call(this, {
+ attributions: options.attributions,
+ logo: options.logo,
+ projection: undefined,
+ state: ol.source.State.READY,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+ /**
+ * @private
+ * @type {ol.FeatureLoader}
+ */
+ this.loader_ = ol.nullFunction;
+
+ /**
+ * @private
+ * @type {ol.format.Feature|undefined}
+ */
+ this.format_ = options.format;
+
+ /**
+ * @private
+ * @type {string|ol.FeatureUrlFunction|undefined}
+ */
+ this.url_ = options.url;
+
+ if (options.loader !== undefined) {
+ this.loader_ = options.loader;
+ } else if (this.url_ !== undefined) {
+ goog.asserts.assert(this.format_ !== undefined,
+ 'format must be set when url is set');
+ // create a XHR feature loader for "url" and "format"
+ this.loader_ = ol.featureloader.xhr(this.url_, this.format_);
+ }
+
+ /**
+ * @private
+ * @type {ol.LoadingStrategy}
+ */
+ this.strategy_ = options.strategy !== undefined ? options.strategy :
+ ol.loadingstrategy.all;
+
+ var useSpatialIndex =
+ options.useSpatialIndex !== undefined ? options.useSpatialIndex : true;
+
+ /**
+ * @private
+ * @type {ol.structs.RBush.<ol.Feature>}
+ */
+ this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null;
+
+ /**
+ * @private
+ * @type {ol.structs.RBush.<{extent: ol.Extent}>}
+ */
+ this.loadedExtentsRtree_ = new ol.structs.RBush();
+
+ /**
+ * @private
+ * @type {Object.<string, ol.Feature>}
+ */
+ this.nullGeometryFeatures_ = {};
+
+ /**
+ * A lookup of features by id (the return from feature.getId()).
+ * @private
+ * @type {Object.<string, ol.Feature>}
+ */
+ this.idIndex_ = {};
+
+ /**
+ * A lookup of features without id (keyed by goog.getUid(feature)).
+ * @private
+ * @type {Object.<string, ol.Feature>}
+ */
+ this.undefIdIndex_ = {};
+
+ /**
+ * @private
+ * @type {Object.<string, Array.<ol.EventsKey>>}
+ */
+ this.featureChangeKeys_ = {};
+
+ /**
+ * @private
+ * @type {ol.Collection.<ol.Feature>}
+ */
+ this.featuresCollection_ = null;
+
+ var collection, features;
+ if (options.features instanceof ol.Collection) {
+ collection = options.features;
+ features = collection.getArray();
+ } else if (Array.isArray(options.features)) {
+ features = options.features;
+ }
+ if (!useSpatialIndex && collection === undefined) {
+ collection = new ol.Collection(features);
+ }
+ if (features !== undefined) {
+ this.addFeaturesInternal(features);
+ }
+ if (collection !== undefined) {
+ this.bindFeaturesCollection_(collection);
+ }
+
+};
+ol.inherits(ol.source.Vector, ol.source.Source);
+
+
+/**
+ * Add a single feature to the source. If you want to add a batch of features
+ * at once, call {@link ol.source.Vector#addFeatures source.addFeatures()}
+ * instead.
+ * @param {ol.Feature} feature Feature to add.
+ * @api stable
+ */
+ol.source.Vector.prototype.addFeature = function(feature) {
+ this.addFeatureInternal(feature);
+ this.changed();
+};
+
+
+/**
+ * Add a feature without firing a `change` event.
+ * @param {ol.Feature} feature Feature.
+ * @protected
+ */
+ol.source.Vector.prototype.addFeatureInternal = function(feature) {
+ var featureKey = goog.getUid(feature).toString();
+
+ if (!this.addToIndex_(featureKey, feature)) {
+ return;
+ }
+
+ this.setupChangeEvents_(featureKey, feature);
+
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ var extent = geometry.getExtent();
+ if (this.featuresRtree_) {
+ this.featuresRtree_.insert(extent, feature);
+ }
+ } else {
+ this.nullGeometryFeatures_[featureKey] = feature;
+ }
+
+ this.dispatchEvent(
+ new ol.source.VectorEvent(ol.source.VectorEventType.ADDFEATURE, feature));
+};
+
+
+/**
+ * @param {string} featureKey Unique identifier for the feature.
+ * @param {ol.Feature} feature The feature.
+ * @private
+ */
+ol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) {
+ goog.asserts.assert(!(featureKey in this.featureChangeKeys_),
+ 'key (%s) not yet registered in featureChangeKey', featureKey);
+ this.featureChangeKeys_[featureKey] = [
+ ol.events.listen(feature, ol.events.EventType.CHANGE,
+ this.handleFeatureChange_, this),
+ ol.events.listen(feature, ol.ObjectEventType.PROPERTYCHANGE,
+ this.handleFeatureChange_, this)
+ ];
+};
+
+
+/**
+ * @param {string} featureKey Unique identifier for the feature.
+ * @param {ol.Feature} feature The feature.
+ * @return {boolean} The feature is "valid", in the sense that it is also a
+ * candidate for insertion into the Rtree.
+ * @private
+ */
+ol.source.Vector.prototype.addToIndex_ = function(featureKey, feature) {
+ var valid = true;
+ var id = feature.getId();
+ if (id !== undefined) {
+ if (!(id.toString() in this.idIndex_)) {
+ this.idIndex_[id.toString()] = feature;
+ } else {
+ valid = false;
+ }
+ } else {
+ goog.asserts.assert(!(featureKey in this.undefIdIndex_),
+ 'Feature already added to the source');
+ this.undefIdIndex_[featureKey] = feature;
+ }
+ return valid;
+};
+
+
+/**
+ * Add a batch of features to the source.
+ * @param {Array.<ol.Feature>} features Features to add.
+ * @api stable
+ */
+ol.source.Vector.prototype.addFeatures = function(features) {
+ this.addFeaturesInternal(features);
+ this.changed();
+};
+
+
+/**
+ * Add features without firing a `change` event.
+ * @param {Array.<ol.Feature>} features Features.
+ * @protected
+ */
+ol.source.Vector.prototype.addFeaturesInternal = function(features) {
+ var featureKey, i, length, feature;
+
+ var extents = [];
+ var newFeatures = [];
+ var geometryFeatures = [];
+
+ for (i = 0, length = features.length; i < length; i++) {
+ feature = features[i];
+ featureKey = goog.getUid(feature).toString();
+ if (this.addToIndex_(featureKey, feature)) {
+ newFeatures.push(feature);
+ }
+ }
+
+ for (i = 0, length = newFeatures.length; i < length; i++) {
+ feature = newFeatures[i];
+ featureKey = goog.getUid(feature).toString();
+ this.setupChangeEvents_(featureKey, feature);
+
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ var extent = geometry.getExtent();
+ extents.push(extent);
+ geometryFeatures.push(feature);
+ } else {
+ this.nullGeometryFeatures_[featureKey] = feature;
+ }
+ }
+ if (this.featuresRtree_) {
+ this.featuresRtree_.load(extents, geometryFeatures);
+ }
+
+ for (i = 0, length = newFeatures.length; i < length; i++) {
+ this.dispatchEvent(new ol.source.VectorEvent(
+ ol.source.VectorEventType.ADDFEATURE, newFeatures[i]));
+ }
+};
+
+
+/**
+ * @param {!ol.Collection.<ol.Feature>} collection Collection.
+ * @private
+ */
+ol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) {
+ goog.asserts.assert(!this.featuresCollection_,
+ 'bindFeaturesCollection can only be called once');
+ var modifyingCollection = false;
+ ol.events.listen(this, ol.source.VectorEventType.ADDFEATURE,
+ function(evt) {
+ if (!modifyingCollection) {
+ modifyingCollection = true;
+ collection.push(evt.feature);
+ modifyingCollection = false;
+ }
+ });
+ ol.events.listen(this, ol.source.VectorEventType.REMOVEFEATURE,
+ function(evt) {
+ if (!modifyingCollection) {
+ modifyingCollection = true;
+ collection.remove(evt.feature);
+ modifyingCollection = false;
+ }
+ });
+ ol.events.listen(collection, ol.CollectionEventType.ADD,
+ function(evt) {
+ if (!modifyingCollection) {
+ var feature = evt.element;
+ goog.asserts.assertInstanceof(feature, ol.Feature);
+ modifyingCollection = true;
+ this.addFeature(feature);
+ modifyingCollection = false;
+ }
+ }, this);
+ ol.events.listen(collection, ol.CollectionEventType.REMOVE,
+ function(evt) {
+ if (!modifyingCollection) {
+ var feature = evt.element;
+ goog.asserts.assertInstanceof(feature, ol.Feature);
+ modifyingCollection = true;
+ this.removeFeature(feature);
+ modifyingCollection = false;
+ }
+ }, this);
+ this.featuresCollection_ = collection;
+};
+
+
+/**
+ * Remove all features from the source.
+ * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events.
+ * @api stable
+ */
+ol.source.Vector.prototype.clear = function(opt_fast) {
+ if (opt_fast) {
+ for (var featureId in this.featureChangeKeys_) {
+ var keys = this.featureChangeKeys_[featureId];
+ keys.forEach(ol.events.unlistenByKey);
+ }
+ if (!this.featuresCollection_) {
+ this.featureChangeKeys_ = {};
+ this.idIndex_ = {};
+ this.undefIdIndex_ = {};
+ }
+ } else {
+ if (this.featuresRtree_) {
+ this.featuresRtree_.forEach(this.removeFeatureInternal, this);
+ for (var id in this.nullGeometryFeatures_) {
+ this.removeFeatureInternal(this.nullGeometryFeatures_[id]);
+ }
+ }
+ }
+ if (this.featuresCollection_) {
+ this.featuresCollection_.clear();
+ }
+ goog.asserts.assert(ol.object.isEmpty(this.featureChangeKeys_),
+ 'featureChangeKeys is an empty object now');
+ goog.asserts.assert(ol.object.isEmpty(this.idIndex_),
+ 'idIndex is an empty object now');
+ goog.asserts.assert(ol.object.isEmpty(this.undefIdIndex_),
+ 'undefIdIndex is an empty object now');
+
+ if (this.featuresRtree_) {
+ this.featuresRtree_.clear();
+ }
+ this.loadedExtentsRtree_.clear();
+ this.nullGeometryFeatures_ = {};
+
+ var clearEvent = new ol.source.VectorEvent(ol.source.VectorEventType.CLEAR);
+ this.dispatchEvent(clearEvent);
+ this.changed();
+};
+
+
+/**
+ * Iterate through all features on the source, calling the provided callback
+ * with each one. If the callback returns any "truthy" value, iteration will
+ * stop and the function will return the same value.
+ *
+ * @param {function(this: T, ol.Feature): S} callback Called with each feature
+ * on the source. Return a truthy value to stop iteration.
+ * @param {T=} opt_this The object to use as `this` in the callback.
+ * @return {S|undefined} The return value from the last call to the callback.
+ * @template T,S
+ * @api stable
+ */
+ol.source.Vector.prototype.forEachFeature = function(callback, opt_this) {
+ if (this.featuresRtree_) {
+ return this.featuresRtree_.forEach(callback, opt_this);
+ } else if (this.featuresCollection_) {
+ return this.featuresCollection_.forEach(callback, opt_this);
+ }
+};
+
+
+/**
+ * Iterate through all features whose geometries contain the provided
+ * coordinate, calling the callback with each feature. If the callback returns
+ * a "truthy" value, iteration will stop and the function will return the same
+ * value.
+ *
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {function(this: T, ol.Feature): S} callback Called with each feature
+ * whose goemetry contains the provided coordinate.
+ * @param {T=} opt_this The object to use as `this` in the callback.
+ * @return {S|undefined} The return value from the last call to the callback.
+ * @template T,S
+ */
+ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect = function(coordinate, callback, opt_this) {
+ var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]];
+ return this.forEachFeatureInExtent(extent, function(feature) {
+ var geometry = feature.getGeometry();
+ goog.asserts.assert(geometry, 'feature geometry is defined and not null');
+ if (geometry.containsCoordinate(coordinate)) {
+ return callback.call(opt_this, feature);
+ } else {
+ return undefined;
+ }
+ });
+};
+
+
+/**
+ * Iterate through all features whose bounding box intersects the provided
+ * extent (note that the feature's geometry may not intersect the extent),
+ * calling the callback with each feature. If the callback returns a "truthy"
+ * value, iteration will stop and the function will return the same value.
+ *
+ * If you are interested in features whose geometry intersects an extent, call
+ * the {@link ol.source.Vector#forEachFeatureIntersectingExtent
+ * source.forEachFeatureIntersectingExtent()} method instead.
+ *
+ * When `useSpatialIndex` is set to false, this method will loop through all
+ * features, equivalent to {@link ol.source.Vector#forEachFeature}.
+ *
+ * @param {ol.Extent} extent Extent.
+ * @param {function(this: T, ol.Feature): S} callback Called with each feature
+ * whose bounding box intersects the provided extent.
+ * @param {T=} opt_this The object to use as `this` in the callback.
+ * @return {S|undefined} The return value from the last call to the callback.
+ * @template T,S
+ * @api
+ */
+ol.source.Vector.prototype.forEachFeatureInExtent = function(extent, callback, opt_this) {
+ if (this.featuresRtree_) {
+ return this.featuresRtree_.forEachInExtent(extent, callback, opt_this);
+ } else if (this.featuresCollection_) {
+ return this.featuresCollection_.forEach(callback, opt_this);
+ }
+};
+
+
+/**
+ * Iterate through all features whose geometry intersects the provided extent,
+ * calling the callback with each feature. If the callback returns a "truthy"
+ * value, iteration will stop and the function will return the same value.
+ *
+ * If you only want to test for bounding box intersection, call the
+ * {@link ol.source.Vector#forEachFeatureInExtent
+ * source.forEachFeatureInExtent()} method instead.
+ *
+ * @param {ol.Extent} extent Extent.
+ * @param {function(this: T, ol.Feature): S} callback Called with each feature
+ * whose geometry intersects the provided extent.
+ * @param {T=} opt_this The object to use as `this` in the callback.
+ * @return {S|undefined} The return value from the last call to the callback.
+ * @template T,S
+ * @api
+ */
+ol.source.Vector.prototype.forEachFeatureIntersectingExtent = function(extent, callback, opt_this) {
+ return this.forEachFeatureInExtent(extent,
+ /**
+ * @param {ol.Feature} feature Feature.
+ * @return {S|undefined} The return value from the last call to the callback.
+ * @template S
+ */
+ function(feature) {
+ var geometry = feature.getGeometry();
+ goog.asserts.assert(geometry,
+ 'feature geometry is defined and not null');
+ if (geometry.intersectsExtent(extent)) {
+ var result = callback.call(opt_this, feature);
+ if (result) {
+ return result;
+ }
+ }
+ });
+};
+
+
+/**
+ * Get the features collection associated with this source. Will be `null`
+ * unless the source was configured with `useSpatialIndex` set to `false`, or
+ * with an {@link ol.Collection} as `features`.
+ * @return {ol.Collection.<ol.Feature>} The collection of features.
+ * @api
+ */
+ol.source.Vector.prototype.getFeaturesCollection = function() {
+ return this.featuresCollection_;
+};
+
+
+/**
+ * Get all features on the source.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.source.Vector.prototype.getFeatures = function() {
+ var features;
+ if (this.featuresCollection_) {
+ features = this.featuresCollection_.getArray();
+ } else if (this.featuresRtree_) {
+ features = this.featuresRtree_.getAll();
+ if (!ol.object.isEmpty(this.nullGeometryFeatures_)) {
+ ol.array.extend(
+ features, ol.object.getValues(this.nullGeometryFeatures_));
+ }
+ }
+ goog.asserts.assert(features !== undefined,
+ 'Neither featuresRtree_ nor featuresCollection_ are available');
+ return features;
+};
+
+
+/**
+ * Get all features whose geometry intersects the provided coordinate.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) {
+ var features = [];
+ this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) {
+ features.push(feature);
+ });
+ return features;
+};
+
+
+/**
+ * Get all features in the provided extent. Note that this returns all features
+ * whose bounding boxes intersect the given extent (so it may include features
+ * whose geometries do not intersect the extent).
+ *
+ * This method is not available when the source is configured with
+ * `useSpatialIndex` set to `false`.
+ * @param {ol.Extent} extent Extent.
+ * @return {Array.<ol.Feature>} Features.
+ * @api
+ */
+ol.source.Vector.prototype.getFeaturesInExtent = function(extent) {
+ goog.asserts.assert(this.featuresRtree_,
+ 'getFeaturesInExtent does not work when useSpatialIndex is set to false');
+ return this.featuresRtree_.getInExtent(extent);
+};
+
+
+/**
+ * Get the closest feature to the provided coordinate.
+ *
+ * This method is not available when the source is configured with
+ * `useSpatialIndex` set to `false`.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {function(ol.Feature):boolean=} opt_filter Feature filter function.
+ * The filter function will receive one argument, the {@link ol.Feature feature}
+ * and it should return a boolean value. By default, no filtering is made.
+ * @return {ol.Feature} Closest feature.
+ * @api stable
+ */
+ol.source.Vector.prototype.getClosestFeatureToCoordinate = function(coordinate, opt_filter) {
+ // Find the closest feature using branch and bound. We start searching an
+ // infinite extent, and find the distance from the first feature found. This
+ // becomes the closest feature. We then compute a smaller extent which any
+ // closer feature must intersect. We continue searching with this smaller
+ // extent, trying to find a closer feature. Every time we find a closer
+ // feature, we update the extent being searched so that any even closer
+ // feature must intersect it. We continue until we run out of features.
+ var x = coordinate[0];
+ var y = coordinate[1];
+ var closestFeature = null;
+ var closestPoint = [NaN, NaN];
+ var minSquaredDistance = Infinity;
+ var extent = [-Infinity, -Infinity, Infinity, Infinity];
+ goog.asserts.assert(this.featuresRtree_,
+ 'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' +
+ 'to false');
+ var filter = opt_filter ? opt_filter : ol.functions.TRUE;
+ this.featuresRtree_.forEachInExtent(extent,
+ /**
+ * @param {ol.Feature} feature Feature.
+ */
+ function(feature) {
+ if (filter(feature)) {
+ var geometry = feature.getGeometry();
+ goog.asserts.assert(geometry,
+ 'feature geometry is defined and not null');
+ var previousMinSquaredDistance = minSquaredDistance;
+ minSquaredDistance = geometry.closestPointXY(
+ x, y, closestPoint, minSquaredDistance);
+ if (minSquaredDistance < previousMinSquaredDistance) {
+ closestFeature = feature;
+ // This is sneaky. Reduce the extent that it is currently being
+ // searched while the R-Tree traversal using this same extent object
+ // is still in progress. This is safe because the new extent is
+ // strictly contained by the old extent.
+ var minDistance = Math.sqrt(minSquaredDistance);
+ extent[0] = x - minDistance;
+ extent[1] = y - minDistance;
+ extent[2] = x + minDistance;
+ extent[3] = y + minDistance;
+ }
+ }
+ });
+ return closestFeature;
+};
+
+
+/**
+ * Get the extent of the features currently in the source.
+ *
+ * This method is not available when the source is configured with
+ * `useSpatialIndex` set to `false`.
+ * @return {!ol.Extent} Extent.
+ * @api stable
+ */
+ol.source.Vector.prototype.getExtent = function() {
+ goog.asserts.assert(this.featuresRtree_,
+ 'getExtent does not work when useSpatialIndex is set to false');
+ return this.featuresRtree_.getExtent();
+};
+
+
+/**
+ * Get a feature by its identifier (the value returned by feature.getId()).
+ * Note that the index treats string and numeric identifiers as the same. So
+ * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`.
+ *
+ * @param {string|number} id Feature identifier.
+ * @return {ol.Feature} The feature (or `null` if not found).
+ * @api stable
+ */
+ol.source.Vector.prototype.getFeatureById = function(id) {
+ var feature = this.idIndex_[id.toString()];
+ return feature !== undefined ? feature : null;
+};
+
+
+/**
+ * Get the format associated with this source.
+ *
+ * @return {ol.format.Feature|undefined} The feature format.
+ * @api
+ */
+ol.source.Vector.prototype.getFormat = function() {
+ return this.format_;
+};
+
+
+/**
+ * Get the url associated with this source.
+ *
+ * @return {string|ol.FeatureUrlFunction|undefined} The url.
+ * @api
+ */
+ol.source.Vector.prototype.getUrl = function() {
+ return this.url_;
+};
+
+
+/**
+ * @param {ol.events.Event} event Event.
+ * @private
+ */
+ol.source.Vector.prototype.handleFeatureChange_ = function(event) {
+ var feature = /** @type {ol.Feature} */ (event.target);
+ var featureKey = goog.getUid(feature).toString();
+ var geometry = feature.getGeometry();
+ if (!geometry) {
+ if (!(featureKey in this.nullGeometryFeatures_)) {
+ if (this.featuresRtree_) {
+ this.featuresRtree_.remove(feature);
+ }
+ this.nullGeometryFeatures_[featureKey] = feature;
+ }
+ } else {
+ var extent = geometry.getExtent();
+ if (featureKey in this.nullGeometryFeatures_) {
+ delete this.nullGeometryFeatures_[featureKey];
+ if (this.featuresRtree_) {
+ this.featuresRtree_.insert(extent, feature);
+ }
+ } else {
+ if (this.featuresRtree_) {
+ this.featuresRtree_.update(extent, feature);
+ }
+ }
+ }
+ var id = feature.getId();
+ var removed;
+ if (id !== undefined) {
+ var sid = id.toString();
+ if (featureKey in this.undefIdIndex_) {
+ delete this.undefIdIndex_[featureKey];
+ this.idIndex_[sid] = feature;
+ } else {
+ if (this.idIndex_[sid] !== feature) {
+ removed = this.removeFromIdIndex_(feature);
+ goog.asserts.assert(removed,
+ 'Expected feature to be removed from index');
+ this.idIndex_[sid] = feature;
+ }
+ }
+ } else {
+ if (!(featureKey in this.undefIdIndex_)) {
+ removed = this.removeFromIdIndex_(feature);
+ goog.asserts.assert(removed,
+ 'Expected feature to be removed from index');
+ this.undefIdIndex_[featureKey] = feature;
+ } else {
+ goog.asserts.assert(this.undefIdIndex_[featureKey] === feature,
+ 'feature keyed under %s in undefIdKeys', featureKey);
+ }
+ }
+ this.changed();
+ this.dispatchEvent(new ol.source.VectorEvent(
+ ol.source.VectorEventType.CHANGEFEATURE, feature));
+};
+
+
+/**
+ * @return {boolean} Is empty.
+ */
+ol.source.Vector.prototype.isEmpty = function() {
+ return this.featuresRtree_.isEmpty() &&
+ ol.object.isEmpty(this.nullGeometryFeatures_);
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {ol.proj.Projection} projection Projection.
+ */
+ol.source.Vector.prototype.loadFeatures = function(
+ extent, resolution, projection) {
+ var loadedExtentsRtree = this.loadedExtentsRtree_;
+ var extentsToLoad = this.strategy_(extent, resolution);
+ var i, ii;
+ for (i = 0, ii = extentsToLoad.length; i < ii; ++i) {
+ var extentToLoad = extentsToLoad[i];
+ var alreadyLoaded = loadedExtentsRtree.forEachInExtent(extentToLoad,
+ /**
+ * @param {{extent: ol.Extent}} object Object.
+ * @return {boolean} Contains.
+ */
+ function(object) {
+ return ol.extent.containsExtent(object.extent, extentToLoad);
+ });
+ if (!alreadyLoaded) {
+ this.loader_.call(this, extentToLoad, resolution, projection);
+ loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()});
+ }
+ }
+};
+
+
+/**
+ * Remove a single feature from the source. If you want to remove all features
+ * at once, use the {@link ol.source.Vector#clear source.clear()} method
+ * instead.
+ * @param {ol.Feature} feature Feature to remove.
+ * @api stable
+ */
+ol.source.Vector.prototype.removeFeature = function(feature) {
+ var featureKey = goog.getUid(feature).toString();
+ if (featureKey in this.nullGeometryFeatures_) {
+ delete this.nullGeometryFeatures_[featureKey];
+ } else {
+ if (this.featuresRtree_) {
+ this.featuresRtree_.remove(feature);
+ }
+ }
+ this.removeFeatureInternal(feature);
+ this.changed();
+};
+
+
+/**
+ * Remove feature without firing a `change` event.
+ * @param {ol.Feature} feature Feature.
+ * @protected
+ */
+ol.source.Vector.prototype.removeFeatureInternal = function(feature) {
+ var featureKey = goog.getUid(feature).toString();
+ goog.asserts.assert(featureKey in this.featureChangeKeys_,
+ 'featureKey exists in featureChangeKeys');
+ this.featureChangeKeys_[featureKey].forEach(ol.events.unlistenByKey);
+ delete this.featureChangeKeys_[featureKey];
+ var id = feature.getId();
+ if (id !== undefined) {
+ delete this.idIndex_[id.toString()];
+ } else {
+ delete this.undefIdIndex_[featureKey];
+ }
+ this.dispatchEvent(new ol.source.VectorEvent(
+ ol.source.VectorEventType.REMOVEFEATURE, feature));
+};
+
+
+/**
+ * Remove a feature from the id index. Called internally when the feature id
+ * may have changed.
+ * @param {ol.Feature} feature The feature.
+ * @return {boolean} Removed the feature from the index.
+ * @private
+ */
+ol.source.Vector.prototype.removeFromIdIndex_ = function(feature) {
+ var removed = false;
+ for (var id in this.idIndex_) {
+ if (this.idIndex_[id] === feature) {
+ delete this.idIndex_[id];
+ removed = true;
+ break;
+ }
+ }
+ return removed;
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.source.Vector} instances are instances of this
+ * type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.source.VectorEvent}
+ * @param {string} type Type.
+ * @param {ol.Feature=} opt_feature Feature.
+ */
+ol.source.VectorEvent = function(type, opt_feature) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The feature being added or removed.
+ * @type {ol.Feature|undefined}
+ * @api stable
+ */
+ this.feature = opt_feature;
+
+};
+ol.inherits(ol.source.VectorEvent, ol.events.Event);
+
+goog.provide('ol.source.ImageVector');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('goog.vec.Mat4');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.render.canvas.ReplayGroup');
+goog.require('ol.renderer.vector');
+goog.require('ol.source.ImageCanvas');
+goog.require('ol.source.Vector');
+goog.require('ol.style.Style');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @classdesc
+ * An image source whose images are canvas elements into which vector features
+ * read from a vector source (`ol.source.Vector`) are drawn. An
+ * `ol.source.ImageVector` object is to be used as the `source` of an image
+ * layer (`ol.layer.Image`). Image layers are rotated, scaled, and translated,
+ * as opposed to being re-rendered, during animations and interactions. So, like
+ * any other image layer, an image layer configured with an
+ * `ol.source.ImageVector` will exhibit this behaviour. This is in contrast to a
+ * vector layer, where vector features are re-drawn during animations and
+ * interactions.
+ *
+ * @constructor
+ * @extends {ol.source.ImageCanvas}
+ * @param {olx.source.ImageVectorOptions} options Options.
+ * @api
+ */
+ol.source.ImageVector = function(options) {
+
+ /**
+ * @private
+ * @type {ol.source.Vector}
+ */
+ this.source_ = options.source;
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.canvasContext_ = ol.dom.createCanvasContext2D();
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.canvasSize_ = [0, 0];
+
+ /**
+ * @private
+ * @type {ol.render.canvas.ReplayGroup}
+ */
+ this.replayGroup_ = null;
+
+ ol.source.ImageCanvas.call(this, {
+ attributions: options.attributions,
+ canvasFunction: this.canvasFunctionInternal_.bind(this),
+ logo: options.logo,
+ projection: options.projection,
+ ratio: options.ratio,
+ resolutions: options.resolutions,
+ state: this.source_.getState()
+ });
+
+ /**
+ * User provided style.
+ * @type {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
+ * @private
+ */
+ this.style_ = null;
+
+ /**
+ * Style function for use within the library.
+ * @type {ol.StyleFunction|undefined}
+ * @private
+ */
+ this.styleFunction_ = undefined;
+
+ this.setStyle(options.style);
+
+ ol.events.listen(this.source_, ol.events.EventType.CHANGE,
+ this.handleSourceChange_, this);
+
+};
+ol.inherits(ol.source.ImageVector, ol.source.ImageCanvas);
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.Size} size Size.
+ * @param {ol.proj.Projection} projection Projection;
+ * @return {HTMLCanvasElement} Canvas element.
+ * @private
+ */
+ol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resolution, pixelRatio, size, projection) {
+
+ var replayGroup = new ol.render.canvas.ReplayGroup(
+ ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
+ resolution);
+
+ this.source_.loadFeatures(extent, resolution, projection);
+
+ var loading = false;
+ this.source_.forEachFeatureInExtent(extent,
+ /**
+ * @param {ol.Feature} feature Feature.
+ */
+ function(feature) {
+ loading = loading ||
+ this.renderFeature_(feature, resolution, pixelRatio, replayGroup);
+ }, this);
+ replayGroup.finish();
+
+ if (loading) {
+ return null;
+ }
+
+ if (this.canvasSize_[0] != size[0] || this.canvasSize_[1] != size[1]) {
+ this.canvasContext_.canvas.width = size[0];
+ this.canvasContext_.canvas.height = size[1];
+ this.canvasSize_[0] = size[0];
+ this.canvasSize_[1] = size[1];
+ } else {
+ this.canvasContext_.clearRect(0, 0, size[0], size[1]);
+ }
+
+ var transform = this.getTransform_(ol.extent.getCenter(extent),
+ resolution, pixelRatio, size);
+ replayGroup.replay(this.canvasContext_, pixelRatio, transform, 0, {});
+
+ this.replayGroup_ = replayGroup;
+
+ return this.canvasContext_.canvas;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(
+ coordinate, resolution, rotation, skippedFeatureUids, callback) {
+ if (!this.replayGroup_) {
+ return undefined;
+ } else {
+ /** @type {Object.<string, boolean>} */
+ var features = {};
+ return this.replayGroup_.forEachFeatureAtCoordinate(
+ coordinate, resolution, 0, skippedFeatureUids,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ goog.asserts.assert(feature !== undefined, 'passed a feature');
+ var key = goog.getUid(feature).toString();
+ if (!(key in features)) {
+ features[key] = true;
+ return callback(feature);
+ }
+ });
+ }
+};
+
+
+/**
+ * Get a reference to the wrapped source.
+ * @return {ol.source.Vector} Source.
+ * @api
+ */
+ol.source.ImageVector.prototype.getSource = function() {
+ return this.source_;
+};
+
+
+/**
+ * Get the style for features. This returns whatever was passed to the `style`
+ * option at construction or to the `setStyle` method.
+ * @return {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
+ * Layer style.
+ * @api stable
+ */
+ol.source.ImageVector.prototype.getStyle = function() {
+ return this.style_;
+};
+
+
+/**
+ * Get the style function.
+ * @return {ol.StyleFunction|undefined} Layer style function.
+ * @api stable
+ */
+ol.source.ImageVector.prototype.getStyleFunction = function() {
+ return this.styleFunction_;
+};
+
+
+/**
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.Size} size Size.
+ * @return {!goog.vec.Mat4.Number} Transform.
+ * @private
+ */
+ol.source.ImageVector.prototype.getTransform_ = function(center, resolution, pixelRatio, size) {
+ return ol.vec.Mat4.makeTransform2D(this.transform_,
+ size[0] / 2, size[1] / 2,
+ pixelRatio / resolution, -pixelRatio / resolution,
+ 0,
+ -center[0], -center[1]);
+};
+
+
+/**
+ * Handle changes in image style state.
+ * @param {ol.events.Event} event Image style change event.
+ * @private
+ */
+ol.source.ImageVector.prototype.handleImageChange_ = function(event) {
+ this.changed();
+};
+
+
+/**
+ * @private
+ */
+ol.source.ImageVector.prototype.handleSourceChange_ = function() {
+ // setState will trigger a CHANGE event, so we always rely
+ // change events by calling setState.
+ this.setState(this.source_.getState());
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
+ * @return {boolean} `true` if an image is loading.
+ * @private
+ */
+ol.source.ImageVector.prototype.renderFeature_ = function(feature, resolution, pixelRatio, replayGroup) {
+ var styles;
+ var styleFunction = feature.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction.call(feature, resolution);
+ } else if (this.styleFunction_) {
+ styles = this.styleFunction_(feature, resolution);
+ }
+ if (!styles) {
+ return false;
+ }
+ var i, ii, loading = false;
+ if (!Array.isArray(styles)) {
+ styles = [styles];
+ }
+ for (i = 0, ii = styles.length; i < ii; ++i) {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles[i],
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleImageChange_, this) || loading;
+ }
+ return loading;
+};
+
+
+/**
+ * Set the style for features. This can be a single style object, an array
+ * of styles, or a function that takes a feature and resolution and returns
+ * an array of styles. If it is `undefined` the default style is used. If
+ * it is `null` the layer has no style (a `null` style), so only features
+ * that have their own styles will be rendered in the layer. See
+ * {@link ol.style} for information on the default style.
+ * @param {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined}
+ * style Layer style.
+ * @api stable
+ */
+ol.source.ImageVector.prototype.setStyle = function(style) {
+ this.style_ = style !== undefined ? style : ol.style.defaultStyleFunction;
+ this.styleFunction_ = !style ?
+ undefined : ol.style.createStyleFunction(this.style_);
+ this.changed();
+};
+
+goog.provide('ol.renderer.canvas.ImageLayer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.functions');
+goog.require('ol.ImageBase');
+goog.require('ol.ViewHint');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.layer.Image');
+goog.require('ol.proj');
+goog.require('ol.renderer.canvas.Layer');
+goog.require('ol.source.ImageVector');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.canvas.Layer}
+ * @param {ol.layer.Image} imageLayer Single image layer.
+ */
+ol.renderer.canvas.ImageLayer = function(imageLayer) {
+
+ ol.renderer.canvas.Layer.call(this, imageLayer);
+
+ /**
+ * @private
+ * @type {?ol.ImageBase}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.imageTransform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @private
+ * @type {?goog.vec.Mat4.Number}
+ */
+ this.imageTransformInv_ = null;
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.hitCanvasContext_ = null;
+
+};
+ol.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ var layer = this.getLayer();
+ var source = layer.getSource();
+ var resolution = frameState.viewState.resolution;
+ var rotation = frameState.viewState.rotation;
+ var skippedFeatureUids = frameState.skippedFeatureUids;
+ return source.forEachFeatureAtCoordinate(
+ coordinate, resolution, rotation, skippedFeatureUids,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ return callback.call(thisArg, feature, layer);
+ });
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
+ if (!this.getImage()) {
+ return undefined;
+ }
+
+ if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
+ // for ImageVector sources use the original hit-detection logic,
+ // so that for example also transparent polygons are detected
+ var coordinate = pixel.slice();
+ ol.vec.Mat4.multVec2(
+ frameState.pixelToCoordinateMatrix, coordinate, coordinate);
+ var hasFeature = this.forEachFeatureAtCoordinate(
+ coordinate, frameState, ol.functions.TRUE, this);
+
+ if (hasFeature) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+ } else {
+ // for all other image sources directly check the image
+ if (!this.imageTransformInv_) {
+ this.imageTransformInv_ = goog.vec.Mat4.createNumber();
+ goog.vec.Mat4.invert(this.imageTransform_, this.imageTransformInv_);
+ }
+
+ var pixelOnCanvas =
+ this.getPixelOnCanvas(pixel, this.imageTransformInv_);
+
+ if (!this.hitCanvasContext_) {
+ this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);
+ }
+
+ this.hitCanvasContext_.clearRect(0, 0, 1, 1);
+ this.hitCanvasContext_.drawImage(
+ this.getImage(), pixelOnCanvas[0], pixelOnCanvas[1], 1, 1, 0, 0, 1, 1);
+
+ var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;
+ if (imageData[3] > 0) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.ImageLayer.prototype.getImage = function() {
+ return !this.image_ ? null : this.image_.getImage();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() {
+ return this.imageTransform_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, layerState) {
+
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var viewCenter = viewState.center;
+ var viewResolution = viewState.resolution;
+
+ var image;
+ var imageLayer = this.getLayer();
+ goog.asserts.assertInstanceof(imageLayer, ol.layer.Image,
+ 'layer is an instance of ol.layer.Image');
+ var imageSource = imageLayer.getSource();
+
+ var hints = frameState.viewHints;
+
+ var renderedExtent = frameState.extent;
+ if (layerState.extent !== undefined) {
+ renderedExtent = ol.extent.getIntersection(
+ renderedExtent, layerState.extent);
+ }
+
+ if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] &&
+ !ol.extent.isEmpty(renderedExtent)) {
+ var projection = viewState.projection;
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ var sourceProjection = imageSource.getProjection();
+ if (sourceProjection) {
+ goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection),
+ 'projection and sourceProjection are equivalent');
+ projection = sourceProjection;
+ }
+ }
+ image = imageSource.getImage(
+ renderedExtent, viewResolution, pixelRatio, projection);
+ if (image) {
+ var loaded = this.loadImage(image);
+ if (loaded) {
+ this.image_ = image;
+ }
+ }
+ }
+
+ if (this.image_) {
+ image = this.image_;
+ var imageExtent = image.getExtent();
+ var imageResolution = image.getResolution();
+ var imagePixelRatio = image.getPixelRatio();
+ var scale = pixelRatio * imageResolution /
+ (viewResolution * imagePixelRatio);
+ ol.vec.Mat4.makeTransform2D(this.imageTransform_,
+ pixelRatio * frameState.size[0] / 2,
+ pixelRatio * frameState.size[1] / 2,
+ scale, scale,
+ 0,
+ imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution,
+ imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution);
+ this.imageTransformInv_ = null;
+ this.updateAttributions(frameState.attributions, image.getAttributions());
+ this.updateLogos(frameState, imageSource);
+ }
+
+ return !!this.image_;
+};
+
+// FIXME find correct globalCompositeOperation
+
+goog.provide('ol.renderer.canvas.TileLayer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.TileRange');
+goog.require('ol.TileState');
+goog.require('ol.array');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.render.EventType');
+goog.require('ol.renderer.canvas.Layer');
+goog.require('ol.size');
+goog.require('ol.source.Tile');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.canvas.Layer}
+ * @param {ol.layer.Tile|ol.layer.VectorTile} tileLayer Tile layer.
+ */
+ol.renderer.canvas.TileLayer = function(tileLayer) {
+
+ ol.renderer.canvas.Layer.call(this, tileLayer);
+
+ /**
+ * @protected
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context = ol.dom.createCanvasContext2D();
+
+ /**
+ * @protected
+ * @type {Array.<ol.Tile|undefined>}
+ */
+ this.renderedTiles = null;
+
+ /**
+ * @protected
+ * @type {ol.Extent}
+ */
+ this.tmpExtent = ol.extent.createEmpty();
+
+ /**
+ * @private
+ * @type {ol.TileCoord}
+ */
+ this.tmpTileCoord_ = [0, 0, 0];
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.imageTransform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @protected
+ * @type {number}
+ */
+ this.zDirection = 0;
+
+};
+ol.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
+ frameState, layerState, context) {
+ var transform = this.getTransform(frameState, 0);
+ this.dispatchPreComposeEvent(context, frameState, transform);
+ this.renderTileImages(context, frameState, layerState);
+ this.dispatchPostComposeEvent(context, frameState, transform);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
+ frameState, layerState) {
+
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+
+ var tileLayer = this.getLayer();
+ var tileSource = tileLayer.getSource();
+ goog.asserts.assertInstanceof(tileSource, ol.source.Tile,
+ 'source is an ol.source.Tile');
+ var tileGrid = tileSource.getTileGridForProjection(projection);
+ var z = tileGrid.getZForResolution(viewState.resolution, this.zDirection);
+ var tileResolution = tileGrid.getResolution(z);
+ var center = viewState.center;
+ var extent;
+ if (tileResolution == viewState.resolution) {
+ center = this.snapCenterToPixel(center, tileResolution, frameState.size);
+ extent = ol.extent.getForViewAndSize(
+ center, tileResolution, viewState.rotation, frameState.size);
+ } else {
+ extent = frameState.extent;
+ }
+
+ if (layerState.extent !== undefined) {
+ extent = ol.extent.getIntersection(extent, layerState.extent);
+ }
+ if (ol.extent.isEmpty(extent)) {
+ // Return false to prevent the rendering of the layer.
+ return false;
+ }
+
+ var tileRange = tileGrid.getTileRangeForExtentAndResolution(
+ extent, tileResolution);
+
+ /**
+ * @type {Object.<number, Object.<string, ol.Tile>>}
+ */
+ var tilesToDrawByZ = {};
+ tilesToDrawByZ[z] = {};
+
+ var findLoadedTiles = this.createLoadedTileFinder(
+ tileSource, projection, tilesToDrawByZ);
+
+ var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
+
+ var tmpExtent = ol.extent.createEmpty();
+ var tmpTileRange = new ol.TileRange(0, 0, 0, 0);
+ var childTileRange, fullyLoaded, tile, x, y;
+ var drawableTile = (
+ /**
+ * @param {!ol.Tile} tile Tile.
+ * @return {boolean} Tile is selected.
+ */
+ function(tile) {
+ var tileState = tile.getState();
+ return tileState == ol.TileState.LOADED ||
+ tileState == ol.TileState.EMPTY ||
+ tileState == ol.TileState.ERROR && !useInterimTilesOnError;
+ });
+ for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
+ for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
+ tile = tileSource.getTile(z, x, y, pixelRatio, projection);
+ if (!drawableTile(tile) && tile.interimTile) {
+ tile = tile.interimTile;
+ }
+ goog.asserts.assert(tile);
+ if (drawableTile(tile)) {
+ tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
+ continue;
+ }
+ fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
+ tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
+ if (!fullyLoaded) {
+ childTileRange = tileGrid.getTileCoordChildTileRange(
+ tile.tileCoord, tmpTileRange, tmpExtent);
+ if (childTileRange) {
+ findLoadedTiles(z + 1, childTileRange);
+ }
+ }
+
+ }
+ }
+
+ /** @type {Array.<number>} */
+ var zs = Object.keys(tilesToDrawByZ).map(Number);
+ zs.sort(ol.array.numberSafeCompareFunction);
+ var renderables = [];
+ var i, ii, currentZ, tileCoordKey, tilesToDraw;
+ for (i = 0, ii = zs.length; i < ii; ++i) {
+ currentZ = zs[i];
+ tilesToDraw = tilesToDrawByZ[currentZ];
+ for (tileCoordKey in tilesToDraw) {
+ tile = tilesToDraw[tileCoordKey];
+ if (tile.getState() == ol.TileState.LOADED) {
+ renderables.push(tile);
+ }
+ }
+ }
+ this.renderedTiles = renderables;
+
+ this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
+ this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
+ projection, extent, z, tileLayer.getPreload());
+ this.scheduleExpireCache(frameState, tileSource);
+ this.updateLogos(frameState, tileSource);
+
+ return true;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(
+ pixel, frameState, callback, thisArg) {
+ var canvas = this.context.canvas;
+ var size = frameState.size;
+ canvas.width = size[0];
+ canvas.height = size[1];
+ this.composeFrame(frameState, this.getLayer().getLayerState(), this.context);
+
+ var imageData = this.context.getImageData(
+ pixel[0], pixel[1], 1, 1).data;
+
+ if (imageData[3] > 0) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @protected
+ */
+ol.renderer.canvas.TileLayer.prototype.renderTileImages = function(context, frameState, layerState) {
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var center = viewState.center;
+ var projection = viewState.projection;
+ var resolution = viewState.resolution;
+ var rotation = viewState.rotation;
+ var size = frameState.size;
+ var offsetX = Math.round(pixelRatio * size[0] / 2);
+ var offsetY = Math.round(pixelRatio * size[1] / 2);
+ var pixelScale = pixelRatio / resolution;
+ var layer = this.getLayer();
+ var source = layer.getSource();
+ goog.asserts.assertInstanceof(source, ol.source.Tile,
+ 'source is an ol.source.Tile');
+ var tileGutter = source.getGutter(projection);
+ var tileGrid = source.getTileGridForProjection(projection);
+
+ var hasRenderListeners = layer.hasListener(ol.render.EventType.RENDER);
+ var renderContext = context;
+ var drawOffsetX, drawOffsetY, drawScale, drawSize;
+ if (rotation || hasRenderListeners) {
+ renderContext = this.context;
+ var renderCanvas = renderContext.canvas;
+ var drawZ = tileGrid.getZForResolution(resolution);
+ var drawTileSize = source.getTilePixelSize(drawZ, pixelRatio, projection);
+ var tileSize = ol.size.toSize(tileGrid.getTileSize(drawZ));
+ drawScale = drawTileSize[0] / tileSize[0];
+ var width = context.canvas.width * drawScale;
+ var height = context.canvas.height * drawScale;
+ // Make sure the canvas is big enough for all possible rotation angles
+ drawSize = Math.round(Math.sqrt(width * width + height * height));
+ if (renderCanvas.width != drawSize) {
+ renderCanvas.width = renderCanvas.height = drawSize;
+ } else {
+ renderContext.clearRect(0, 0, drawSize, drawSize);
+ }
+ drawOffsetX = (drawSize - width) / 2 / drawScale;
+ drawOffsetY = (drawSize - height) / 2 / drawScale;
+ pixelScale *= drawScale;
+ offsetX = Math.round(drawScale * (offsetX + drawOffsetX));
+ offsetY = Math.round(drawScale * (offsetY + drawOffsetY));
+ }
+ // for performance reasons, context.save / context.restore is not used
+ // to save and restore the transformation matrix and the opacity.
+ // see http://jsperf.com/context-save-restore-versus-variable
+ var alpha = renderContext.globalAlpha;
+ renderContext.globalAlpha = layerState.opacity;
+
+ var tilesToDraw = this.renderedTiles;
+
+ var pixelExtents;
+ var opaque = source.getOpaque(projection) && layerState.opacity == 1;
+ if (!opaque) {
+ tilesToDraw.reverse();
+ pixelExtents = [];
+ }
+
+ var extent = layerState.extent;
+ var clipped = extent !== undefined;
+ if (clipped) {
+ goog.asserts.assert(extent !== undefined,
+ 'layerState extent is defined');
+ var topLeft = ol.extent.getTopLeft(extent);
+ var topRight = ol.extent.getTopRight(extent);
+ var bottomRight = ol.extent.getBottomRight(extent);
+ var bottomLeft = ol.extent.getBottomLeft(extent);
+
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ topLeft, topLeft);
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ topRight, topRight);
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ bottomRight, bottomRight);
+ ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix,
+ bottomLeft, bottomLeft);
+
+ var ox = drawOffsetX || 0;
+ var oy = drawOffsetY || 0;
+ renderContext.save();
+ var cx = (renderContext.canvas.width * pixelRatio) / 2;
+ var cy = (renderContext.canvas.height * pixelRatio) / 2;
+ ol.render.canvas.rotateAtOffset(renderContext, -rotation, cx, cy);
+ renderContext.beginPath();
+ renderContext.moveTo(topLeft[0] * pixelRatio + ox, topLeft[1] * pixelRatio + oy);
+ renderContext.lineTo(topRight[0] * pixelRatio + ox, topRight[1] * pixelRatio + oy);
+ renderContext.lineTo(bottomRight[0] * pixelRatio + ox, bottomRight[1] * pixelRatio + oy);
+ renderContext.lineTo(bottomLeft[0] * pixelRatio + ox, bottomLeft[1] * pixelRatio + oy);
+ renderContext.clip();
+ ol.render.canvas.rotateAtOffset(renderContext, rotation, cx, cy);
+ }
+
+ for (var i = 0, ii = tilesToDraw.length; i < ii; ++i) {
+ var tile = tilesToDraw[i];
+ var tileCoord = tile.getTileCoord();
+ var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
+ var currentZ = tileCoord[0];
+ // Calculate all insert points by tile widths from a common origin to avoid
+ // gaps caused by rounding
+ var origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
+ tileGrid.getTileCoordForCoordAndZ(center, currentZ, this.tmpTileCoord_)));
+ var w = Math.round(ol.extent.getWidth(tileExtent) * pixelScale);
+ var h = Math.round(ol.extent.getHeight(tileExtent) * pixelScale);
+ var left = Math.round((tileExtent[0] - origin[0]) * pixelScale / w) * w +
+ offsetX + Math.round((origin[0] - center[0]) * pixelScale);
+ var top = Math.round((origin[1] - tileExtent[3]) * pixelScale / h) * h +
+ offsetY + Math.round((center[1] - origin[1]) * pixelScale);
+ if (!opaque) {
+ var pixelExtent = [left, top, left + w, top + h];
+ // Create a clip mask for regions in this low resolution tile that are
+ // already filled by a higher resolution tile
+ renderContext.save();
+ for (var j = 0, jj = pixelExtents.length; j < jj; ++j) {
+ var clipExtent = pixelExtents[j];
+ if (ol.extent.intersects(pixelExtent, clipExtent)) {
+ renderContext.beginPath();
+ // counter-clockwise (outer ring) for current tile
+ renderContext.moveTo(pixelExtent[0], pixelExtent[1]);
+ renderContext.lineTo(pixelExtent[0], pixelExtent[3]);
+ renderContext.lineTo(pixelExtent[2], pixelExtent[3]);
+ renderContext.lineTo(pixelExtent[2], pixelExtent[1]);
+ // clockwise (inner ring) for higher resolution tile
+ renderContext.moveTo(clipExtent[0], clipExtent[1]);
+ renderContext.lineTo(clipExtent[2], clipExtent[1]);
+ renderContext.lineTo(clipExtent[2], clipExtent[3]);
+ renderContext.lineTo(clipExtent[0], clipExtent[3]);
+ renderContext.closePath();
+ renderContext.clip();
+ }
+ }
+ pixelExtents.push(pixelExtent);
+ }
+ var tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection);
+ renderContext.drawImage(tile.getImage(), tileGutter, tileGutter,
+ tilePixelSize[0], tilePixelSize[1], left, top, w, h);
+ if (!opaque) {
+ renderContext.restore();
+ }
+ }
+
+ if (clipped) {
+ renderContext.restore();
+ }
+
+ if (hasRenderListeners) {
+ var dX = drawOffsetX - offsetX / drawScale + offsetX;
+ var dY = drawOffsetY - offsetY / drawScale + offsetY;
+ var imageTransform = ol.vec.Mat4.makeTransform2D(this.imageTransform_,
+ drawSize / 2 - dX, drawSize / 2 - dY, pixelScale, -pixelScale,
+ -rotation, -center[0] + dX / pixelScale, -center[1] - dY / pixelScale);
+ this.dispatchRenderEvent(renderContext, frameState, imageTransform);
+ }
+ if (rotation || hasRenderListeners) {
+ context.drawImage(renderContext.canvas, -Math.round(drawOffsetX),
+ -Math.round(drawOffsetY), drawSize / drawScale, drawSize / drawScale);
+ }
+ renderContext.globalAlpha = alpha;
+};
+
+
+/**
+ * @function
+ * @return {ol.layer.Tile|ol.layer.VectorTile}
+ */
+ol.renderer.canvas.TileLayer.prototype.getLayer;
+
+goog.provide('ol.renderer.canvas.VectorLayer');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.ViewHint');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.layer.Vector');
+goog.require('ol.render.EventType');
+goog.require('ol.render.canvas');
+goog.require('ol.render.canvas.ReplayGroup');
+goog.require('ol.renderer.canvas.Layer');
+goog.require('ol.renderer.vector');
+goog.require('ol.source.Vector');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.canvas.Layer}
+ * @param {ol.layer.Vector} vectorLayer Vector layer.
+ */
+ol.renderer.canvas.VectorLayer = function(vectorLayer) {
+
+ ol.renderer.canvas.Layer.call(this, vectorLayer);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.dirty_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedResolution_ = NaN;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.renderedExtent_ = ol.extent.createEmpty();
+
+ /**
+ * @private
+ * @type {function(ol.Feature, ol.Feature): number|null}
+ */
+ this.renderedRenderOrder_ = null;
+
+ /**
+ * @private
+ * @type {ol.render.canvas.ReplayGroup}
+ */
+ this.replayGroup_ = null;
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = ol.dom.createCanvasContext2D();
+
+};
+ol.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {
+
+ var extent = frameState.extent;
+ var pixelRatio = frameState.pixelRatio;
+ var skippedFeatureUids = layerState.managed ?
+ frameState.skippedFeatureUids : {};
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+ var rotation = viewState.rotation;
+ var projectionExtent = projection.getExtent();
+ var vectorSource = this.getLayer().getSource();
+ goog.asserts.assertInstanceof(vectorSource, ol.source.Vector);
+
+ var transform = this.getTransform(frameState, 0);
+
+ this.dispatchPreComposeEvent(context, frameState, transform);
+
+ var replayGroup = this.replayGroup_;
+ if (replayGroup && !replayGroup.isEmpty()) {
+ var layer = this.getLayer();
+ var replayContext;
+ if (layer.hasListener(ol.render.EventType.RENDER)) {
+ // resize and clear
+ this.context_.canvas.width = context.canvas.width;
+ this.context_.canvas.height = context.canvas.height;
+ replayContext = this.context_;
+ } else {
+ replayContext = context;
+ }
+ // for performance reasons, context.save / context.restore is not used
+ // to save and restore the transformation matrix and the opacity.
+ // see http://jsperf.com/context-save-restore-versus-variable
+ var alpha = replayContext.globalAlpha;
+ replayContext.globalAlpha = layerState.opacity;
+
+ var width = frameState.size[0] * pixelRatio;
+ var height = frameState.size[1] * pixelRatio;
+ ol.render.canvas.rotateAtOffset(replayContext, -rotation,
+ width / 2, height / 2);
+ replayGroup.replay(replayContext, pixelRatio, transform, rotation,
+ skippedFeatureUids);
+ if (vectorSource.getWrapX() && projection.canWrapX() &&
+ !ol.extent.containsExtent(projectionExtent, extent)) {
+ var startX = extent[0];
+ var worldWidth = ol.extent.getWidth(projectionExtent);
+ var world = 0;
+ var offsetX;
+ while (startX < projectionExtent[0]) {
+ --world;
+ offsetX = worldWidth * world;
+ transform = this.getTransform(frameState, offsetX);
+ replayGroup.replay(replayContext, pixelRatio, transform, rotation,
+ skippedFeatureUids);
+ startX += worldWidth;
+ }
+ world = 0;
+ startX = extent[2];
+ while (startX > projectionExtent[2]) {
+ ++world;
+ offsetX = worldWidth * world;
+ transform = this.getTransform(frameState, offsetX);
+ replayGroup.replay(replayContext, pixelRatio, transform, rotation,
+ skippedFeatureUids);
+ startX -= worldWidth;
+ }
+ // restore original transform for render and compose events
+ transform = this.getTransform(frameState, 0);
+ }
+ ol.render.canvas.rotateAtOffset(replayContext, rotation,
+ width / 2, height / 2);
+
+ if (replayContext != context) {
+ this.dispatchRenderEvent(replayContext, frameState, transform);
+ context.drawImage(replayContext.canvas, 0, 0);
+ }
+ replayContext.globalAlpha = alpha;
+ }
+
+ this.dispatchPostComposeEvent(context, frameState, transform);
+
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ if (!this.replayGroup_) {
+ return undefined;
+ } else {
+ var resolution = frameState.viewState.resolution;
+ var rotation = frameState.viewState.rotation;
+ var layer = this.getLayer();
+ /** @type {Object.<string, boolean>} */
+ var features = {};
+ return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
+ rotation, {},
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ goog.asserts.assert(feature !== undefined, 'received a feature');
+ var key = goog.getUid(feature).toString();
+ if (!(key in features)) {
+ features[key] = true;
+ return callback.call(thisArg, feature, layer);
+ }
+ });
+ }
+};
+
+
+/**
+ * Handle changes in image style state.
+ * @param {ol.events.Event} event Image style change event.
+ * @private
+ */
+ol.renderer.canvas.VectorLayer.prototype.handleStyleImageChange_ = function(event) {
+ this.renderIfReadyAndVisible();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, layerState) {
+
+ var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
+ goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector,
+ 'layer is an instance of ol.layer.Vector');
+ var vectorSource = vectorLayer.getSource();
+
+ this.updateAttributions(
+ frameState.attributions, vectorSource.getAttributions());
+ this.updateLogos(frameState, vectorSource);
+
+ var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
+ var interacting = frameState.viewHints[ol.ViewHint.INTERACTING];
+ var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();
+ var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();
+
+ if (!this.dirty_ && (!updateWhileAnimating && animating) ||
+ (!updateWhileInteracting && interacting)) {
+ return true;
+ }
+
+ var frameStateExtent = frameState.extent;
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+ var resolution = viewState.resolution;
+ var pixelRatio = frameState.pixelRatio;
+ var vectorLayerRevision = vectorLayer.getRevision();
+ var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();
+ var vectorLayerRenderOrder = vectorLayer.getRenderOrder();
+
+ if (vectorLayerRenderOrder === undefined) {
+ vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;
+ }
+
+ var extent = ol.extent.buffer(frameStateExtent,
+ vectorLayerRenderBuffer * resolution);
+ var projectionExtent = viewState.projection.getExtent();
+
+ if (vectorSource.getWrapX() && viewState.projection.canWrapX() &&
+ !ol.extent.containsExtent(projectionExtent, frameState.extent)) {
+ // For the replay group, we need an extent that intersects the real world
+ // (-180° to +180°). To support geometries in a coordinate range from -540°
+ // to +540°, we add at least 1 world width on each side of the projection
+ // extent. If the viewport is wider than the world, we need to add half of
+ // the viewport width to make sure we cover the whole viewport.
+ var worldWidth = ol.extent.getWidth(projectionExtent);
+ var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth);
+ extent[0] = projectionExtent[0] - buffer;
+ extent[2] = projectionExtent[2] + buffer;
+ }
+
+ if (!this.dirty_ &&
+ this.renderedResolution_ == resolution &&
+ this.renderedRevision_ == vectorLayerRevision &&
+ this.renderedRenderOrder_ == vectorLayerRenderOrder &&
+ ol.extent.containsExtent(this.renderedExtent_, extent)) {
+ return true;
+ }
+
+ this.replayGroup_ = null;
+
+ this.dirty_ = false;
+
+ var replayGroup =
+ new ol.render.canvas.ReplayGroup(
+ ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
+ resolution, vectorLayer.getRenderBuffer());
+ vectorSource.loadFeatures(extent, resolution, projection);
+ /**
+ * @param {ol.Feature} feature Feature.
+ * @this {ol.renderer.canvas.VectorLayer}
+ */
+ var renderFeature = function(feature) {
+ var styles;
+ var styleFunction = feature.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction.call(feature, resolution);
+ } else {
+ styleFunction = vectorLayer.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction(feature, resolution);
+ }
+ }
+ if (styles) {
+ var dirty = this.renderFeature(
+ feature, resolution, pixelRatio, styles, replayGroup);
+ this.dirty_ = this.dirty_ || dirty;
+ }
+ };
+ if (vectorLayerRenderOrder) {
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ vectorSource.forEachFeatureInExtent(extent,
+ /**
+ * @param {ol.Feature} feature Feature.
+ */
+ function(feature) {
+ features.push(feature);
+ }, this);
+ features.sort(vectorLayerRenderOrder);
+ features.forEach(renderFeature, this);
+ } else {
+ vectorSource.forEachFeatureInExtent(extent, renderFeature, this);
+ }
+ replayGroup.finish();
+
+ this.renderedResolution_ = resolution;
+ this.renderedRevision_ = vectorLayerRevision;
+ this.renderedRenderOrder_ = vectorLayerRenderOrder;
+ this.renderedExtent_ = extent;
+ this.replayGroup_ = replayGroup;
+
+ return true;
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
+ * styles.
+ * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
+ * @return {boolean} `true` if an image is loading.
+ */
+ol.renderer.canvas.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {
+ if (!styles) {
+ return false;
+ }
+ var loading = false;
+ if (Array.isArray(styles)) {
+ for (var i = 0, ii = styles.length; i < ii; ++i) {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles[i],
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleStyleImageChange_, this) || loading;
+ }
+ } else {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles,
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleStyleImageChange_, this) || loading;
+ }
+ return loading;
+};
+
+goog.provide('ol.TileUrlFunction');
+
+goog.require('goog.asserts');
+goog.require('ol.math');
+goog.require('ol.tilecoord');
+
+
+/**
+ * @param {string} template Template.
+ * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @return {ol.TileUrlFunctionType} Tile URL function.
+ */
+ol.TileUrlFunction.createFromTemplate = function(template, tileGrid) {
+ var zRegEx = /\{z\}/g;
+ var xRegEx = /\{x\}/g;
+ var yRegEx = /\{y\}/g;
+ var dashYRegEx = /\{-y\}/g;
+ return (
+ /**
+ * @param {ol.TileCoord} tileCoord Tile Coordinate.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string|undefined} Tile URL.
+ */
+ function(tileCoord, pixelRatio, projection) {
+ if (!tileCoord) {
+ return undefined;
+ } else {
+ return template.replace(zRegEx, tileCoord[0].toString())
+ .replace(xRegEx, tileCoord[1].toString())
+ .replace(yRegEx, function() {
+ var y = -tileCoord[2] - 1;
+ return y.toString();
+ })
+ .replace(dashYRegEx, function() {
+ var z = tileCoord[0];
+ var range = tileGrid.getFullTileRange(z);
+ goog.asserts.assert(range,
+ 'The {-y} template requires a tile grid with extent');
+ var y = range.getHeight() + tileCoord[2];
+ return y.toString();
+ });
+ }
+ });
+};
+
+
+/**
+ * @param {Array.<string>} templates Templates.
+ * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @return {ol.TileUrlFunctionType} Tile URL function.
+ */
+ol.TileUrlFunction.createFromTemplates = function(templates, tileGrid) {
+ var len = templates.length;
+ var tileUrlFunctions = new Array(len);
+ for (var i = 0; i < len; ++i) {
+ tileUrlFunctions[i] = ol.TileUrlFunction.createFromTemplate(
+ templates[i], tileGrid);
+ }
+ return ol.TileUrlFunction.createFromTileUrlFunctions(tileUrlFunctions);
+};
+
+
+/**
+ * @param {Array.<ol.TileUrlFunctionType>} tileUrlFunctions Tile URL Functions.
+ * @return {ol.TileUrlFunctionType} Tile URL function.
+ */
+ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) {
+ goog.asserts.assert(tileUrlFunctions.length > 0,
+ 'Length of tile url functions should be greater than 0');
+ if (tileUrlFunctions.length === 1) {
+ return tileUrlFunctions[0];
+ }
+ return (
+ /**
+ * @param {ol.TileCoord} tileCoord Tile Coordinate.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string|undefined} Tile URL.
+ */
+ function(tileCoord, pixelRatio, projection) {
+ if (!tileCoord) {
+ return undefined;
+ } else {
+ var h = ol.tilecoord.hash(tileCoord);
+ var index = ol.math.modulo(h, tileUrlFunctions.length);
+ return tileUrlFunctions[index](tileCoord, pixelRatio, projection);
+ }
+ });
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string|undefined} Tile URL.
+ */
+ol.TileUrlFunction.nullTileUrlFunction = function(tileCoord, pixelRatio, projection) {
+ return undefined;
+};
+
+
+/**
+ * @param {string} url URL.
+ * @return {Array.<string>} Array of urls.
+ */
+ol.TileUrlFunction.expandUrl = function(url) {
+ var urls = [];
+ var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url);
+ if (match) {
+ var startCharCode = match[1].charCodeAt(0);
+ var stopCharCode = match[2].charCodeAt(0);
+ var charCode;
+ for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
+ urls.push(url.replace(match[0], String.fromCharCode(charCode)));
+ }
+ } else {
+ urls.push(url);
+ }
+ return urls;
+};
+
+goog.provide('ol.source.UrlTile');
+
+goog.require('ol.events');
+goog.require('ol.TileState');
+goog.require('ol.TileUrlFunction');
+goog.require('ol.source.Tile');
+goog.require('ol.source.TileEvent');
+
+
+/**
+ * @classdesc
+ * Base class for sources providing tiles divided into a tile grid over http.
+ *
+ * @constructor
+ * @fires ol.source.TileEvent
+ * @extends {ol.source.Tile}
+ * @param {ol.SourceUrlTileOptions} options Image tile options.
+ */
+ol.source.UrlTile = function(options) {
+
+ ol.source.Tile.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ extent: options.extent,
+ logo: options.logo,
+ opaque: options.opaque,
+ projection: options.projection,
+ state: options.state,
+ tileGrid: options.tileGrid,
+ tilePixelRatio: options.tilePixelRatio,
+ wrapX: options.wrapX
+ });
+
+ /**
+ * @protected
+ * @type {ol.TileLoadFunctionType}
+ */
+ this.tileLoadFunction = options.tileLoadFunction;
+
+ /**
+ * @protected
+ * @type {ol.TileUrlFunctionType}
+ */
+ this.tileUrlFunction = this.fixedTileUrlFunction ?
+ this.fixedTileUrlFunction.bind(this) :
+ ol.TileUrlFunction.nullTileUrlFunction;
+
+ /**
+ * @protected
+ * @type {!Array.<string>|null}
+ */
+ this.urls = null;
+
+ if (options.urls) {
+ this.setUrls(options.urls);
+ } else if (options.url) {
+ this.setUrl(options.url);
+ }
+ if (options.tileUrlFunction) {
+ this.setTileUrlFunction(options.tileUrlFunction);
+ }
+
+};
+ol.inherits(ol.source.UrlTile, ol.source.Tile);
+
+
+/**
+ * @type {ol.TileUrlFunctionType|undefined}
+ * @protected
+ */
+ol.source.UrlTile.prototype.fixedTileUrlFunction;
+
+/**
+ * Return the tile load function of the source.
+ * @return {ol.TileLoadFunctionType} TileLoadFunction
+ * @api
+ */
+ol.source.UrlTile.prototype.getTileLoadFunction = function() {
+ return this.tileLoadFunction;
+};
+
+
+/**
+ * Return the tile URL function of the source.
+ * @return {ol.TileUrlFunctionType} TileUrlFunction
+ * @api
+ */
+ol.source.UrlTile.prototype.getTileUrlFunction = function() {
+ return this.tileUrlFunction;
+};
+
+
+/**
+ * Return the URLs used for this source.
+ * When a tileUrlFunction is used instead of url or urls,
+ * null will be returned.
+ * @return {!Array.<string>|null} URLs.
+ * @api
+ */
+ol.source.UrlTile.prototype.getUrls = function() {
+ return this.urls;
+};
+
+
+/**
+ * Handle tile change events.
+ * @param {ol.events.Event} event Event.
+ * @protected
+ */
+ol.source.UrlTile.prototype.handleTileChange = function(event) {
+ var tile = /** @type {ol.Tile} */ (event.target);
+ switch (tile.getState()) {
+ case ol.TileState.LOADING:
+ this.dispatchEvent(
+ new ol.source.TileEvent(ol.source.TileEventType.TILELOADSTART, tile));
+ break;
+ case ol.TileState.LOADED:
+ this.dispatchEvent(
+ new ol.source.TileEvent(ol.source.TileEventType.TILELOADEND, tile));
+ break;
+ case ol.TileState.ERROR:
+ this.dispatchEvent(
+ new ol.source.TileEvent(ol.source.TileEventType.TILELOADERROR, tile));
+ break;
+ default:
+ // pass
+ }
+};
+
+
+/**
+ * Set the tile load function of the source.
+ * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
+ * @api
+ */
+ol.source.UrlTile.prototype.setTileLoadFunction = function(tileLoadFunction) {
+ this.tileCache.clear();
+ this.tileLoadFunction = tileLoadFunction;
+ this.changed();
+};
+
+
+/**
+ * Set the tile URL function of the source.
+ * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function.
+ * @param {string=} opt_key Optional new tile key for the source.
+ * @api
+ */
+ol.source.UrlTile.prototype.setTileUrlFunction = function(tileUrlFunction, opt_key) {
+ this.tileUrlFunction = tileUrlFunction;
+ if (typeof opt_key !== 'undefined') {
+ this.setKey(opt_key);
+ } else {
+ this.changed();
+ }
+};
+
+
+/**
+ * Set the URL to use for requests.
+ * @param {string} url URL.
+ * @api stable
+ */
+ol.source.UrlTile.prototype.setUrl = function(url) {
+ var urls = this.urls = ol.TileUrlFunction.expandUrl(url);
+ this.setTileUrlFunction(this.fixedTileUrlFunction ?
+ this.fixedTileUrlFunction.bind(this) :
+ ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), url);
+};
+
+
+/**
+ * Set the URLs to use for requests.
+ * @param {Array.<string>} urls URLs.
+ * @api stable
+ */
+ol.source.UrlTile.prototype.setUrls = function(urls) {
+ this.urls = urls;
+ var key = urls.join('\n');
+ this.setTileUrlFunction(this.fixedTileUrlFunction ?
+ this.fixedTileUrlFunction.bind(this) :
+ ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), key);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.UrlTile.prototype.useTile = function(z, x, y) {
+ var tileCoordKey = this.getKeyZXY(z, x, y);
+ if (this.tileCache.containsKey(tileCoordKey)) {
+ this.tileCache.get(tileCoordKey);
+ }
+};
+
+goog.provide('ol.source.VectorTile');
+
+goog.require('ol.TileState');
+goog.require('ol.VectorTile');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.featureloader');
+goog.require('ol.size');
+goog.require('ol.source.UrlTile');
+
+
+/**
+ * @classdesc
+ * Class for layer sources providing vector data divided into a tile grid, to be
+ * used with {@link ol.layer.VectorTile}. Although this source receives tiles
+ * with vector features from the server, it is not meant for feature editing.
+ * Features are optimized for rendering, their geometries are clipped at or near
+ * tile boundaries and simplified for a view resolution. See
+ * {@link ol.source.Vector} for vector sources that are suitable for feature
+ * editing.
+ *
+ * @constructor
+ * @fires ol.source.TileEvent
+ * @extends {ol.source.UrlTile}
+ * @param {olx.source.VectorTileOptions} options Vector tile options.
+ * @api
+ */
+ol.source.VectorTile = function(options) {
+
+ ol.source.UrlTile.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize !== undefined ? options.cacheSize : 128,
+ extent: options.extent,
+ logo: options.logo,
+ opaque: false,
+ projection: options.projection,
+ state: options.state,
+ tileGrid: options.tileGrid,
+ tileLoadFunction: options.tileLoadFunction ?
+ options.tileLoadFunction : ol.source.VectorTile.defaultTileLoadFunction,
+ tileUrlFunction: options.tileUrlFunction,
+ tilePixelRatio: options.tilePixelRatio,
+ url: options.url,
+ urls: options.urls,
+ wrapX: options.wrapX === undefined ? true : options.wrapX
+ });
+
+ /**
+ * @private
+ * @type {ol.format.Feature}
+ */
+ this.format_ = options.format ? options.format : null;
+
+ /**
+ * @protected
+ * @type {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string,
+ * ol.format.Feature, ol.TileLoadFunctionType)}
+ */
+ this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile;
+
+};
+ol.inherits(ol.source.VectorTile, ol.source.UrlTile);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projection) {
+ var tileCoordKey = this.getKeyZXY(z, x, y);
+ if (this.tileCache.containsKey(tileCoordKey)) {
+ return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
+ } else {
+ var tileCoord = [z, x, y];
+ var urlTileCoord = this.getTileCoordForTileUrlFunction(
+ tileCoord, projection);
+ var tileUrl = urlTileCoord ?
+ this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
+ var tile = new this.tileClass(
+ tileCoord,
+ tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
+ tileUrl !== undefined ? tileUrl : '',
+ this.format_, this.tileLoadFunction);
+ ol.events.listen(tile, ol.events.EventType.CHANGE,
+ this.handleTileChange, this);
+
+ this.tileCache.set(tileCoordKey, tile);
+ return tile;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.VectorTile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
+ var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
+ return [tileSize[0] * pixelRatio, tileSize[1] * pixelRatio];
+};
+
+
+/**
+ * @param {ol.VectorTile} vectorTile Vector tile.
+ * @param {string} url URL.
+ */
+ol.source.VectorTile.defaultTileLoadFunction = function(vectorTile, url) {
+ vectorTile.setLoader(ol.featureloader.tile(url, vectorTile.getFormat()));
+};
+
+goog.provide('ol.renderer.canvas.VectorTileLayer');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('goog.vec.Mat4');
+goog.require('ol.Feature');
+goog.require('ol.VectorTile');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.layer.VectorTile');
+goog.require('ol.proj');
+goog.require('ol.proj.Units');
+goog.require('ol.render.EventType');
+goog.require('ol.render.canvas');
+goog.require('ol.render.canvas.ReplayGroup');
+goog.require('ol.renderer.canvas.TileLayer');
+goog.require('ol.renderer.vector');
+goog.require('ol.size');
+goog.require('ol.source.VectorTile');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @const
+ * @type {!Object.<string, Array.<ol.render.ReplayType>>}
+ */
+ol.renderer.canvas.IMAGE_REPLAYS = {
+ 'image': ol.render.REPLAY_ORDER,
+ 'hybrid': [ol.render.ReplayType.POLYGON, ol.render.ReplayType.LINE_STRING]
+};
+
+
+/**
+ * @const
+ * @type {!Object.<string, Array.<ol.render.ReplayType>>}
+ */
+ol.renderer.canvas.VECTOR_REPLAYS = {
+ 'hybrid': [ol.render.ReplayType.IMAGE, ol.render.ReplayType.TEXT],
+ 'vector': ol.render.REPLAY_ORDER
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.canvas.TileLayer}
+ * @param {ol.layer.VectorTile} layer VectorTile layer.
+ */
+ol.renderer.canvas.VectorTileLayer = function(layer) {
+
+ ol.renderer.canvas.TileLayer.call(this, layer);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.dirty_ = false;
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.tmpTransform_ = goog.vec.Mat4.createNumber();
+
+ // Use lower resolution for pure vector rendering. Closest resolution otherwise.
+ this.zDirection =
+ layer.getRenderMode() == ol.layer.VectorTileRenderType.VECTOR ? 1 : 0;
+
+};
+ol.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(
+ frameState, layerState, context) {
+ var transform = this.getTransform(frameState, 0);
+ this.dispatchPreComposeEvent(context, frameState, transform);
+ var renderMode = this.getLayer().getRenderMode();
+ if (renderMode !== ol.layer.VectorTileRenderType.VECTOR) {
+ this.renderTileImages(context, frameState, layerState);
+ }
+ if (renderMode !== ol.layer.VectorTileRenderType.IMAGE) {
+ this.renderTileReplays_(context, frameState, layerState);
+ }
+ this.dispatchPostComposeEvent(context, frameState, transform);
+};
+
+
+/**
+ * @param {CanvasRenderingContext2D} context Context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @private
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.renderTileReplays_ = function(
+ context, frameState, layerState) {
+
+ var layer = this.getLayer();
+ var replays = ol.renderer.canvas.VECTOR_REPLAYS[layer.getRenderMode()];
+ var pixelRatio = frameState.pixelRatio;
+ var skippedFeatureUids = layerState.managed ?
+ frameState.skippedFeatureUids : {};
+ var viewState = frameState.viewState;
+ var center = viewState.center;
+ var resolution = viewState.resolution;
+ var rotation = viewState.rotation;
+ var size = frameState.size;
+ var pixelScale = pixelRatio / resolution;
+ var source = layer.getSource();
+ goog.asserts.assertInstanceof(source, ol.source.VectorTile,
+ 'Source is an ol.source.VectorTile');
+ var tilePixelRatio = source.getTilePixelRatio(pixelRatio);
+
+ var transform = this.getTransform(frameState, 0);
+
+ var replayContext;
+ if (layer.hasListener(ol.render.EventType.RENDER)) {
+ // resize and clear
+ this.context.canvas.width = context.canvas.width;
+ this.context.canvas.height = context.canvas.height;
+ replayContext = this.context;
+ } else {
+ replayContext = context;
+ }
+ // for performance reasons, context.save / context.restore is not used
+ // to save and restore the transformation matrix and the opacity.
+ // see http://jsperf.com/context-save-restore-versus-variable
+ var alpha = replayContext.globalAlpha;
+ replayContext.globalAlpha = layerState.opacity;
+
+ var tilesToDraw = this.renderedTiles;
+ var tileGrid = source.getTileGrid();
+
+ var currentZ, i, ii, offsetX, offsetY, origin, pixelSpace, replayState;
+ var tile, tileExtent, tilePixelResolution, tileResolution, tileTransform;
+ for (i = 0, ii = tilesToDraw.length; i < ii; ++i) {
+ tile = tilesToDraw[i];
+ replayState = tile.getReplayState();
+ tileExtent = tileGrid.getTileCoordExtent(
+ tile.getTileCoord(), this.tmpExtent);
+ currentZ = tile.getTileCoord()[0];
+ pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS;
+ tileResolution = tileGrid.getResolution(currentZ);
+ tilePixelResolution = tileResolution / tilePixelRatio;
+ offsetX = Math.round(pixelRatio * size[0] / 2);
+ offsetY = Math.round(pixelRatio * size[1] / 2);
+
+ if (pixelSpace) {
+ origin = ol.extent.getTopLeft(tileExtent);
+ tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
+ offsetX, offsetY,
+ pixelScale * tilePixelResolution,
+ pixelScale * tilePixelResolution,
+ rotation,
+ (origin[0] - center[0]) / tilePixelResolution,
+ (center[1] - origin[1]) / tilePixelResolution);
+ } else {
+ tileTransform = transform;
+ }
+ ol.render.canvas.rotateAtOffset(replayContext, -rotation, offsetX, offsetY);
+ replayState.replayGroup.replay(replayContext, pixelRatio,
+ tileTransform, rotation, skippedFeatureUids, replays);
+ ol.render.canvas.rotateAtOffset(replayContext, rotation, offsetX, offsetY);
+ }
+
+ if (replayContext != context) {
+ this.dispatchRenderEvent(replayContext, frameState, transform);
+ context.drawImage(replayContext.canvas, 0, 0);
+ }
+ replayContext.globalAlpha = alpha;
+};
+
+
+/**
+ * @param {ol.VectorTile} tile Tile.
+ * @param {olx.FrameState} frameState Frame state.
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile,
+ frameState) {
+ var layer = this.getLayer();
+ var pixelRatio = frameState.pixelRatio;
+ var projection = frameState.viewState.projection;
+ var revision = layer.getRevision();
+ var renderOrder = layer.getRenderOrder() || null;
+
+ var replayState = tile.getReplayState();
+ if (!replayState.dirty && replayState.renderedRevision == revision &&
+ replayState.renderedRenderOrder == renderOrder) {
+ return;
+ }
+
+ replayState.replayGroup = null;
+ replayState.dirty = false;
+
+ var source = layer.getSource();
+ goog.asserts.assertInstanceof(source, ol.source.VectorTile,
+ 'Source is an ol.source.VectorTile');
+ var tileGrid = source.getTileGrid();
+ var tileCoord = tile.getTileCoord();
+ var tileProjection = tile.getProjection();
+ var pixelSpace = tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS;
+ var resolution = tileGrid.getResolution(tileCoord[0]);
+ var extent, reproject, tileResolution;
+ if (pixelSpace) {
+ var tilePixelRatio = tileResolution = source.getTilePixelRatio(pixelRatio);
+ var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]));
+ extent = [0, 0, tileSize[0] * tilePixelRatio, tileSize[1] * tilePixelRatio];
+ } else {
+ tileResolution = resolution;
+ extent = tileGrid.getTileCoordExtent(tileCoord);
+ if (!ol.proj.equivalent(projection, tileProjection)) {
+ reproject = true;
+ tile.setProjection(projection);
+ }
+ }
+ replayState.dirty = false;
+ var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
+ tileResolution, layer.getRenderBuffer());
+ var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
+ tileResolution, pixelRatio);
+
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @this {ol.renderer.canvas.VectorTileLayer}
+ */
+ function renderFeature(feature) {
+ var styles;
+ var styleFunction = feature.getStyleFunction();
+ if (styleFunction) {
+ goog.asserts.assertInstanceof(feature, ol.Feature, 'Got an ol.Feature');
+ styles = styleFunction.call(feature, resolution);
+ } else {
+ styleFunction = layer.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction(feature, resolution);
+ }
+ }
+ if (styles) {
+ if (!Array.isArray(styles)) {
+ styles = [styles];
+ }
+ var dirty = this.renderFeature(feature, squaredTolerance, styles,
+ replayGroup);
+ this.dirty_ = this.dirty_ || dirty;
+ replayState.dirty = replayState.dirty || dirty;
+ }
+ }
+
+ var features = tile.getFeatures();
+ if (renderOrder && renderOrder !== replayState.renderedRenderOrder) {
+ features.sort(renderOrder);
+ }
+ var feature;
+ for (var i = 0, ii = features.length; i < ii; ++i) {
+ feature = features[i];
+ if (reproject) {
+ feature.getGeometry().transform(tileProjection, projection);
+ }
+ renderFeature.call(this, feature);
+ }
+
+ replayGroup.finish();
+
+ replayState.renderedRevision = revision;
+ replayState.renderedRenderOrder = renderOrder;
+ replayState.replayGroup = replayGroup;
+ replayState.resolution = NaN;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ var pixelRatio = frameState.pixelRatio;
+ var resolution = frameState.viewState.resolution;
+ var rotation = frameState.viewState.rotation;
+ var layer = this.getLayer();
+ /** @type {Object.<string, boolean>} */
+ var features = {};
+
+ var replayables = this.renderedTiles;
+ var source = layer.getSource();
+ goog.asserts.assertInstanceof(source, ol.source.VectorTile,
+ 'Source is an ol.source.VectorTile');
+ var tileGrid = source.getTileGrid();
+ var found, tileSpaceCoordinate;
+ var i, ii, origin, replayGroup;
+ var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution;
+ for (i = 0, ii = replayables.length; i < ii; ++i) {
+ tile = replayables[i];
+ tileCoord = tile.getTileCoord();
+ tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord,
+ this.tmpExtent);
+ if (!ol.extent.containsCoordinate(tileExtent, coordinate)) {
+ continue;
+ }
+ if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {
+ origin = ol.extent.getTopLeft(tileExtent);
+ tilePixelRatio = source.getTilePixelRatio(pixelRatio);
+ tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio;
+ tileSpaceCoordinate = [
+ (coordinate[0] - origin[0]) / tileResolution,
+ (origin[1] - coordinate[1]) / tileResolution
+ ];
+ resolution = tilePixelRatio;
+ } else {
+ tileSpaceCoordinate = coordinate;
+ }
+ replayGroup = tile.getReplayState().replayGroup;
+ found = found || replayGroup.forEachFeatureAtCoordinate(
+ tileSpaceCoordinate, resolution, rotation, {},
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ goog.asserts.assert(feature, 'received a feature');
+ var key = goog.getUid(feature).toString();
+ if (!(key in features)) {
+ features[key] = true;
+ return callback.call(thisArg, feature, layer);
+ }
+ });
+ }
+ return found;
+};
+
+
+/**
+ * Handle changes in image style state.
+ * @param {ol.events.Event} event Image style change event.
+ * @private
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(event) {
+ this.renderIfReadyAndVisible();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = function(frameState, layerState) {
+ var prepared = ol.renderer.canvas.TileLayer.prototype.prepareFrame.call(this, frameState, layerState);
+ if (prepared) {
+ var skippedFeatures = Object.keys(frameState.skippedFeatureUids_ || {});
+ for (var i = 0, ii = this.renderedTiles.length; i < ii; ++i) {
+ var tile = this.renderedTiles[i];
+ goog.asserts.assertInstanceof(tile, ol.VectorTile, 'got an ol.VectorTile');
+ this.createReplayGroup(tile, frameState);
+ this.renderTileImage_(tile, frameState, layerState, skippedFeatures);
+ }
+ }
+ return prepared;
+};
+
+
+/**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
+ * styles.
+ * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
+ * @return {boolean} `true` if an image is loading.
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, squaredTolerance, styles, replayGroup) {
+ if (!styles) {
+ return false;
+ }
+ var loading = false;
+ if (Array.isArray(styles)) {
+ for (var i = 0, ii = styles.length; i < ii; ++i) {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles[i], squaredTolerance,
+ this.handleStyleImageChange_, this) || loading;
+ }
+ } else {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles, squaredTolerance,
+ this.handleStyleImageChange_, this) || loading;
+ }
+ return loading;
+};
+
+
+/**
+ * @param {ol.VectorTile} tile Tile.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @param {Array.<string>} skippedFeatures Skipped features.
+ * @private
+ */
+ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(
+ tile, frameState, layerState, skippedFeatures) {
+ var layer = this.getLayer();
+ var replays = ol.renderer.canvas.IMAGE_REPLAYS[layer.getRenderMode()];
+ if (!replays) {
+ // do not create an image in 'vector' mode
+ return;
+ }
+ var pixelRatio = frameState.pixelRatio;
+ var replayState = tile.getReplayState();
+ var revision = layer.getRevision();
+ if (!ol.array.equals(replayState.skippedFeatures, skippedFeatures) ||
+ replayState.renderedTileRevision !== revision) {
+ replayState.skippedFeatures = skippedFeatures;
+ replayState.renderedTileRevision = revision;
+ var tileContext = tile.getContext();
+ var source = layer.getSource();
+ var tileGrid = source.getTileGrid();
+ var currentZ = tile.getTileCoord()[0];
+ var resolution = tileGrid.getResolution(currentZ);
+ var tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ));
+ var tileResolution = tileGrid.getResolution(currentZ);
+ var resolutionRatio = tileResolution / resolution;
+ var width = tileSize[0] * pixelRatio * resolutionRatio;
+ var height = tileSize[1] * pixelRatio * resolutionRatio;
+ tileContext.canvas.width = width / resolutionRatio + 0.5;
+ tileContext.canvas.height = height / resolutionRatio + 0.5;
+ tileContext.scale(1 / resolutionRatio, 1 / resolutionRatio);
+ tileContext.translate(width / 2, height / 2);
+ var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS;
+ var pixelScale = pixelRatio / resolution;
+ var tilePixelRatio = source.getTilePixelRatio(pixelRatio);
+ var tilePixelResolution = tileResolution / tilePixelRatio;
+ var tileExtent = tileGrid.getTileCoordExtent(
+ tile.getTileCoord(), this.tmpExtent);
+ var tileTransform;
+ if (pixelSpace) {
+ tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
+ 0, 0,
+ pixelScale * tilePixelResolution, pixelScale * tilePixelResolution,
+ 0,
+ -tileSize[0] * tilePixelRatio / 2, -tileSize[1] * tilePixelRatio / 2);
+ } else {
+ var tileCenter = ol.extent.getCenter(tileExtent);
+ tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
+ 0, 0,
+ pixelScale, -pixelScale,
+ 0,
+ -tileCenter[0], -tileCenter[1]);
+ }
+
+ replayState.replayGroup.replay(tileContext, pixelRatio,
+ tileTransform, 0, frameState.skippedFeatureUids || {}, replays);
+ }
+};
+
+// FIXME offset panning
+
+goog.provide('ol.renderer.canvas.Map');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol');
+goog.require('ol.RendererType');
+goog.require('ol.array');
+goog.require('ol.css');
+goog.require('ol.dom');
+goog.require('ol.layer.Image');
+goog.require('ol.layer.Layer');
+goog.require('ol.layer.Tile');
+goog.require('ol.layer.Vector');
+goog.require('ol.layer.VectorTile');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.canvas');
+goog.require('ol.render.canvas.Immediate');
+goog.require('ol.renderer.Map');
+goog.require('ol.renderer.canvas.ImageLayer');
+goog.require('ol.renderer.canvas.Layer');
+goog.require('ol.renderer.canvas.TileLayer');
+goog.require('ol.renderer.canvas.VectorLayer');
+goog.require('ol.renderer.canvas.VectorTileLayer');
+goog.require('ol.source.State');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.Map}
+ * @param {Element} container Container.
+ * @param {ol.Map} map Map.
+ */
+ol.renderer.canvas.Map = function(container, map) {
+
+ ol.renderer.Map.call(this, container, map);
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = ol.dom.createCanvasContext2D();
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = this.context_.canvas;
+
+ this.canvas_.style.width = '100%';
+ this.canvas_.style.height = '100%';
+ this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
+ container.insertBefore(this.canvas_, container.childNodes[0] || null);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderedVisible_ = true;
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumber();
+
+};
+ol.inherits(ol.renderer.canvas.Map, ol.renderer.Map);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) {
+ if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) {
+ return new ol.renderer.canvas.ImageLayer(layer);
+ } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {
+ return new ol.renderer.canvas.TileLayer(layer);
+ } else if (ol.ENABLE_VECTOR_TILE && layer instanceof ol.layer.VectorTile) {
+ return new ol.renderer.canvas.VectorTileLayer(layer);
+ } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {
+ return new ol.renderer.canvas.VectorLayer(layer);
+ } else {
+ goog.asserts.fail('unexpected layer configuration');
+ return null;
+ }
+};
+
+
+/**
+ * @param {ol.render.EventType} type Event type.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {
+ var map = this.getMap();
+ var context = this.context_;
+ if (map.hasListener(type)) {
+ var extent = frameState.extent;
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var rotation = viewState.rotation;
+
+ var transform = this.getTransform(frameState);
+
+ var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
+ extent, transform, rotation);
+ var composeEvent = new ol.render.Event(type, map, vectorContext,
+ frameState, context, null);
+ map.dispatchEvent(composeEvent);
+ }
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @protected
+ * @return {!goog.vec.Mat4.Number} Transform.
+ */
+ol.renderer.canvas.Map.prototype.getTransform = function(frameState) {
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var resolution = viewState.resolution;
+ return ol.vec.Mat4.makeTransform2D(this.transform_,
+ this.canvas_.width / 2, this.canvas_.height / 2,
+ pixelRatio / resolution, -pixelRatio / resolution,
+ -viewState.rotation,
+ -viewState.center[0], -viewState.center[1]);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.Map.prototype.getType = function() {
+ return ol.RendererType.CANVAS;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
+
+ if (!frameState) {
+ if (this.renderedVisible_) {
+ this.canvas_.style.display = 'none';
+ this.renderedVisible_ = false;
+ }
+ return;
+ }
+
+ var context = this.context_;
+ var pixelRatio = frameState.pixelRatio;
+ var width = Math.round(frameState.size[0] * pixelRatio);
+ var height = Math.round(frameState.size[1] * pixelRatio);
+ if (this.canvas_.width != width || this.canvas_.height != height) {
+ this.canvas_.width = width;
+ this.canvas_.height = height;
+ } else {
+ context.clearRect(0, 0, width, height);
+ }
+
+ var rotation = frameState.viewState.rotation;
+
+ this.calculateMatrices2D(frameState);
+
+ this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
+
+ var layerStatesArray = frameState.layerStatesArray;
+ ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
+
+ ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
+
+ var viewResolution = frameState.viewState.resolution;
+ var i, ii, layer, layerRenderer, layerState;
+ for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
+ layerState = layerStatesArray[i];
+ layer = layerState.layer;
+ layerRenderer = this.getLayerRenderer(layer);
+ goog.asserts.assertInstanceof(layerRenderer, ol.renderer.canvas.Layer,
+ 'layerRenderer is an instance of ol.renderer.canvas.Layer');
+ if (!ol.layer.Layer.visibleAtResolution(layerState, viewResolution) ||
+ layerState.sourceState != ol.source.State.READY) {
+ continue;
+ }
+ if (layerRenderer.prepareFrame(frameState, layerState)) {
+ layerRenderer.composeFrame(frameState, layerState, context);
+ }
+ }
+
+ ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
+
+ this.dispatchComposeEvent_(
+ ol.render.EventType.POSTCOMPOSE, frameState);
+
+ if (!this.renderedVisible_) {
+ this.canvas_.style.display = '';
+ this.renderedVisible_ = true;
+ }
+
+ this.scheduleRemoveUnusedLayerRenderers(frameState);
+ this.scheduleExpireIconCache(frameState);
+};
+
+goog.provide('ol.renderer.dom.Layer');
+
+goog.require('ol');
+goog.require('ol.layer.Layer');
+goog.require('ol.renderer.Layer');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.Layer}
+ * @param {ol.layer.Layer} layer Layer.
+ * @param {!Element} target Target.
+ */
+ol.renderer.dom.Layer = function(layer, target) {
+
+ ol.renderer.Layer.call(this, layer);
+
+ /**
+ * @type {!Element}
+ * @protected
+ */
+ this.target = target;
+
+};
+ol.inherits(ol.renderer.dom.Layer, ol.renderer.Layer);
+
+
+/**
+ * Clear rendered elements.
+ */
+ol.renderer.dom.Layer.prototype.clearFrame = ol.nullFunction;
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ */
+ol.renderer.dom.Layer.prototype.composeFrame = ol.nullFunction;
+
+
+/**
+ * @return {!Element} Target.
+ */
+ol.renderer.dom.Layer.prototype.getTarget = function() {
+ return this.target;
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @return {boolean} whether composeFrame should be called.
+ */
+ol.renderer.dom.Layer.prototype.prepareFrame = goog.abstractMethod;
+
+goog.provide('ol.renderer.dom.ImageLayer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.ImageBase');
+goog.require('ol.ViewHint');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.layer.Image');
+goog.require('ol.proj');
+goog.require('ol.renderer.dom.Layer');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.dom.Layer}
+ * @param {ol.layer.Image} imageLayer Image layer.
+ */
+ol.renderer.dom.ImageLayer = function(imageLayer) {
+ var target = document.createElement('DIV');
+ target.style.position = 'absolute';
+
+ ol.renderer.dom.Layer.call(this, imageLayer, target);
+
+ /**
+ * The last rendered image.
+ * @private
+ * @type {?ol.ImageBase}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumberIdentity();
+
+};
+ol.inherits(ol.renderer.dom.ImageLayer, ol.renderer.dom.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.ImageLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ var layer = this.getLayer();
+ var source = layer.getSource();
+ var resolution = frameState.viewState.resolution;
+ var rotation = frameState.viewState.rotation;
+ var skippedFeatureUids = frameState.skippedFeatureUids;
+ return source.forEachFeatureAtCoordinate(
+ coordinate, resolution, rotation, skippedFeatureUids,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ return callback.call(thisArg, feature, layer);
+ });
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.ImageLayer.prototype.clearFrame = function() {
+ ol.dom.removeChildren(this.target);
+ this.image_ = null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.ImageLayer.prototype.prepareFrame = function(frameState, layerState) {
+
+ var viewState = frameState.viewState;
+ var viewCenter = viewState.center;
+ var viewResolution = viewState.resolution;
+ var viewRotation = viewState.rotation;
+
+ var image = this.image_;
+ var imageLayer = this.getLayer();
+ goog.asserts.assertInstanceof(imageLayer, ol.layer.Image,
+ 'layer is an instance of ol.layer.Image');
+ var imageSource = imageLayer.getSource();
+
+ var hints = frameState.viewHints;
+
+ var renderedExtent = frameState.extent;
+ if (layerState.extent !== undefined) {
+ renderedExtent = ol.extent.getIntersection(
+ renderedExtent, layerState.extent);
+ }
+
+ if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] &&
+ !ol.extent.isEmpty(renderedExtent)) {
+ var projection = viewState.projection;
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ var sourceProjection = imageSource.getProjection();
+ if (sourceProjection) {
+ goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection),
+ 'projection and sourceProjection are equivalent');
+ projection = sourceProjection;
+ }
+ }
+ var image_ = imageSource.getImage(renderedExtent, viewResolution,
+ frameState.pixelRatio, projection);
+ if (image_) {
+ var loaded = this.loadImage(image_);
+ if (loaded) {
+ image = image_;
+ }
+ }
+ }
+
+ if (image) {
+ var imageExtent = image.getExtent();
+ var imageResolution = image.getResolution();
+ var transform = goog.vec.Mat4.createNumber();
+ ol.vec.Mat4.makeTransform2D(transform,
+ frameState.size[0] / 2, frameState.size[1] / 2,
+ imageResolution / viewResolution, imageResolution / viewResolution,
+ viewRotation,
+ (imageExtent[0] - viewCenter[0]) / imageResolution,
+ (viewCenter[1] - imageExtent[3]) / imageResolution);
+ if (image != this.image_) {
+ var imageElement = image.getImage(this);
+ // Bootstrap sets the style max-width: 100% for all images, which breaks
+ // prevents the image from being displayed in FireFox. Workaround by
+ // overriding the max-width style.
+ imageElement.style.maxWidth = 'none';
+ imageElement.style.position = 'absolute';
+ ol.dom.removeChildren(this.target);
+ this.target.appendChild(imageElement);
+ this.image_ = image;
+ }
+ this.setTransform_(transform);
+ this.updateAttributions(frameState.attributions, image.getAttributions());
+ this.updateLogos(frameState, imageSource);
+ }
+
+ return true;
+};
+
+
+/**
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @private
+ */
+ol.renderer.dom.ImageLayer.prototype.setTransform_ = function(transform) {
+ if (!ol.vec.Mat4.equals2D(transform, this.transform_)) {
+ ol.dom.transformElement2D(this.target, transform, 6);
+ goog.vec.Mat4.setFromArray(this.transform_, transform);
+ }
+};
+
+// FIXME probably need to reset TileLayerZ if offsets get too large
+// FIXME when zooming out, preserve higher Z divs to avoid white flash
+
+goog.provide('ol.renderer.dom.TileLayer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol');
+goog.require('ol.TileRange');
+goog.require('ol.TileState');
+goog.require('ol.ViewHint');
+goog.require('ol.array');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.layer.Tile');
+goog.require('ol.renderer.dom.Layer');
+goog.require('ol.size');
+goog.require('ol.tilegrid.TileGrid');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.dom.Layer}
+ * @param {ol.layer.Tile} tileLayer Tile layer.
+ */
+ol.renderer.dom.TileLayer = function(tileLayer) {
+
+ var target = document.createElement('DIV');
+ target.style.position = 'absolute';
+
+ ol.renderer.dom.Layer.call(this, tileLayer, target);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderedVisible_ = true;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedOpacity_ = 1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = 0;
+
+ /**
+ * @private
+ * @type {!Object.<number, ol.renderer.dom.TileLayerZ_>}
+ */
+ this.tileLayerZs_ = {};
+
+};
+ol.inherits(ol.renderer.dom.TileLayer, ol.renderer.dom.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.TileLayer.prototype.clearFrame = function() {
+ ol.dom.removeChildren(this.target);
+ this.renderedRevision_ = 0;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.TileLayer.prototype.prepareFrame = function(frameState, layerState) {
+
+ if (!layerState.visible) {
+ if (this.renderedVisible_) {
+ this.target.style.display = 'none';
+ this.renderedVisible_ = false;
+ }
+ return true;
+ }
+
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+
+ var tileLayer = this.getLayer();
+ goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile,
+ 'layer is an instance of ol.layer.Tile');
+ var tileSource = tileLayer.getSource();
+ var tileGrid = tileSource.getTileGridForProjection(projection);
+ var tileGutter = tileSource.getGutter(projection);
+ var z = tileGrid.getZForResolution(viewState.resolution);
+ var tileResolution = tileGrid.getResolution(z);
+ var center = viewState.center;
+ var extent;
+ if (tileResolution == viewState.resolution) {
+ center = this.snapCenterToPixel(center, tileResolution, frameState.size);
+ extent = ol.extent.getForViewAndSize(
+ center, tileResolution, viewState.rotation, frameState.size);
+ } else {
+ extent = frameState.extent;
+ }
+
+ if (layerState.extent !== undefined) {
+ extent = ol.extent.getIntersection(extent, layerState.extent);
+ }
+
+ var tileRange = tileGrid.getTileRangeForExtentAndResolution(
+ extent, tileResolution);
+
+ /** @type {Object.<number, Object.<string, ol.Tile>>} */
+ var tilesToDrawByZ = {};
+ tilesToDrawByZ[z] = {};
+
+ var findLoadedTiles = this.createLoadedTileFinder(
+ tileSource, projection, tilesToDrawByZ);
+
+ var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
+
+ var tmpExtent = ol.extent.createEmpty();
+ var tmpTileRange = new ol.TileRange(0, 0, 0, 0);
+ var childTileRange, drawable, fullyLoaded, tile, tileState, x, y;
+ for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
+ for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
+ tile = tileSource.getTile(z, x, y, pixelRatio, projection);
+ tileState = tile.getState();
+ drawable = tileState == ol.TileState.LOADED ||
+ tileState == ol.TileState.EMPTY ||
+ tileState == ol.TileState.ERROR && !useInterimTilesOnError;
+ if (!drawable && tile.interimTile) {
+ tile = tile.interimTile;
+ }
+ goog.asserts.assert(tile);
+ tileState = tile.getState();
+ if (tileState == ol.TileState.LOADED) {
+ tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
+ continue;
+ } else if (tileState == ol.TileState.EMPTY ||
+ (tileState == ol.TileState.ERROR &&
+ !useInterimTilesOnError)) {
+ continue;
+ }
+ fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
+ tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
+ if (!fullyLoaded) {
+ childTileRange = tileGrid.getTileCoordChildTileRange(
+ tile.tileCoord, tmpTileRange, tmpExtent);
+ if (childTileRange) {
+ findLoadedTiles(z + 1, childTileRange);
+ }
+ }
+
+ }
+
+ }
+
+ // If the tile source revision changes, we destroy the existing DOM structure
+ // so that a new one will be created. It would be more efficient to modify
+ // the existing structure.
+ var tileLayerZ, tileLayerZKey;
+ if (this.renderedRevision_ != tileSource.getRevision()) {
+ for (tileLayerZKey in this.tileLayerZs_) {
+ tileLayerZ = this.tileLayerZs_[+tileLayerZKey];
+ ol.dom.removeNode(tileLayerZ.target);
+ }
+ this.tileLayerZs_ = {};
+ this.renderedRevision_ = tileSource.getRevision();
+ }
+
+ /** @type {Array.<number>} */
+ var zs = Object.keys(tilesToDrawByZ).map(Number);
+ zs.sort(ol.array.numberSafeCompareFunction);
+
+ /** @type {Object.<number, boolean>} */
+ var newTileLayerZKeys = {};
+
+ var iz, iziz, tileCoordKey, tileCoordOrigin, tilesToDraw;
+ for (iz = 0, iziz = zs.length; iz < iziz; ++iz) {
+ tileLayerZKey = zs[iz];
+ if (tileLayerZKey in this.tileLayerZs_) {
+ tileLayerZ = this.tileLayerZs_[tileLayerZKey];
+ } else {
+ tileCoordOrigin =
+ tileGrid.getTileCoordForCoordAndZ(center, tileLayerZKey);
+ tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin);
+ newTileLayerZKeys[tileLayerZKey] = true;
+ this.tileLayerZs_[tileLayerZKey] = tileLayerZ;
+ }
+ tilesToDraw = tilesToDrawByZ[tileLayerZKey];
+ for (tileCoordKey in tilesToDraw) {
+ tileLayerZ.addTile(tilesToDraw[tileCoordKey], tileGutter);
+ }
+ tileLayerZ.finalizeAddTiles();
+ }
+
+ /** @type {Array.<number>} */
+ var tileLayerZKeys = Object.keys(this.tileLayerZs_).map(Number);
+ tileLayerZKeys.sort(ol.array.numberSafeCompareFunction);
+
+ var i, ii, j, origin, resolution;
+ var transform = goog.vec.Mat4.createNumber();
+ for (i = 0, ii = tileLayerZKeys.length; i < ii; ++i) {
+ tileLayerZKey = tileLayerZKeys[i];
+ tileLayerZ = this.tileLayerZs_[tileLayerZKey];
+ if (!(tileLayerZKey in tilesToDrawByZ)) {
+ ol.dom.removeNode(tileLayerZ.target);
+ delete this.tileLayerZs_[tileLayerZKey];
+ continue;
+ }
+ resolution = tileLayerZ.getResolution();
+ origin = tileLayerZ.getOrigin();
+ ol.vec.Mat4.makeTransform2D(transform,
+ frameState.size[0] / 2, frameState.size[1] / 2,
+ resolution / viewState.resolution,
+ resolution / viewState.resolution,
+ viewState.rotation,
+ (origin[0] - center[0]) / resolution,
+ (center[1] - origin[1]) / resolution);
+ tileLayerZ.setTransform(transform);
+ if (tileLayerZKey in newTileLayerZKeys) {
+ for (j = tileLayerZKey - 1; j >= 0; --j) {
+ if (j in this.tileLayerZs_) {
+ if (this.tileLayerZs_[j].target.parentNode) {
+ this.tileLayerZs_[j].target.parentNode.insertBefore(tileLayerZ.target, this.tileLayerZs_[j].target.nextSibling);
+ }
+ break;
+ }
+ }
+ if (j < 0) {
+ this.target.insertBefore(tileLayerZ.target, this.target.childNodes[0] || null);
+ }
+ } else {
+ if (!frameState.viewHints[ol.ViewHint.ANIMATING] &&
+ !frameState.viewHints[ol.ViewHint.INTERACTING]) {
+ tileLayerZ.removeTilesOutsideExtent(extent, tmpTileRange);
+ }
+ }
+ }
+
+ if (layerState.opacity != this.renderedOpacity_) {
+ this.target.style.opacity = layerState.opacity;
+ this.renderedOpacity_ = layerState.opacity;
+ }
+
+ if (layerState.visible && !this.renderedVisible_) {
+ this.target.style.display = '';
+ this.renderedVisible_ = true;
+ }
+
+ this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
+ this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
+ projection, extent, z, tileLayer.getPreload());
+ this.scheduleExpireCache(frameState, tileSource);
+ this.updateLogos(frameState, tileSource);
+
+ return true;
+};
+
+
+/**
+ * @constructor
+ * @private
+ * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
+ * @param {ol.TileCoord} tileCoordOrigin Tile coord origin.
+ */
+ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) {
+
+ /**
+ * @type {!Element}
+ */
+ this.target = document.createElement('DIV');
+ this.target.style.position = 'absolute';
+ this.target.style.width = '100%';
+ this.target.style.height = '100%';
+
+ /**
+ * @private
+ * @type {ol.tilegrid.TileGrid}
+ */
+ this.tileGrid_ = tileGrid;
+
+ /**
+ * @private
+ * @type {ol.TileCoord}
+ */
+ this.tileCoordOrigin_ = tileCoordOrigin;
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.origin_ =
+ ol.extent.getTopLeft(tileGrid.getTileCoordExtent(tileCoordOrigin));
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.resolution_ = tileGrid.getResolution(tileCoordOrigin[0]);
+
+ /**
+ * @private
+ * @type {Object.<string, ol.Tile>}
+ */
+ this.tiles_ = {};
+
+ /**
+ * @private
+ * @type {DocumentFragment}
+ */
+ this.documentFragment_ = null;
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumberIdentity();
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.tmpSize_ = [0, 0];
+
+};
+
+
+/**
+ * @param {ol.Tile} tile Tile.
+ * @param {number} tileGutter Tile gutter.
+ */
+ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile, tileGutter) {
+ var tileCoord = tile.tileCoord;
+ var tileCoordZ = tileCoord[0];
+ var tileCoordX = tileCoord[1];
+ var tileCoordY = tileCoord[2];
+ goog.asserts.assert(tileCoordZ == this.tileCoordOrigin_[0],
+ 'tileCoordZ matches z of tileCoordOrigin');
+ var tileCoordKey = tileCoord.toString();
+ if (tileCoordKey in this.tiles_) {
+ return;
+ }
+ var tileSize = ol.size.toSize(
+ this.tileGrid_.getTileSize(tileCoordZ), this.tmpSize_);
+ var image = tile.getImage(this);
+ var imageStyle = image.style;
+ // Bootstrap sets the style max-width: 100% for all images, which
+ // prevents the tile from being displayed in FireFox. Workaround
+ // by overriding the max-width style.
+ imageStyle.maxWidth = 'none';
+ var tileElement;
+ var tileElementStyle;
+ if (tileGutter > 0) {
+ tileElement = document.createElement('DIV');
+ tileElementStyle = tileElement.style;
+ tileElementStyle.overflow = 'hidden';
+ tileElementStyle.width = tileSize[0] + 'px';
+ tileElementStyle.height = tileSize[1] + 'px';
+ imageStyle.position = 'absolute';
+ imageStyle.left = -tileGutter + 'px';
+ imageStyle.top = -tileGutter + 'px';
+ imageStyle.width = (tileSize[0] + 2 * tileGutter) + 'px';
+ imageStyle.height = (tileSize[1] + 2 * tileGutter) + 'px';
+ tileElement.appendChild(image);
+ } else {
+ imageStyle.width = tileSize[0] + 'px';
+ imageStyle.height = tileSize[1] + 'px';
+ tileElement = image;
+ tileElementStyle = imageStyle;
+ }
+ tileElementStyle.position = 'absolute';
+ tileElementStyle.left =
+ ((tileCoordX - this.tileCoordOrigin_[1]) * tileSize[0]) + 'px';
+ tileElementStyle.top =
+ ((this.tileCoordOrigin_[2] - tileCoordY) * tileSize[1]) + 'px';
+ if (!this.documentFragment_) {
+ this.documentFragment_ = document.createDocumentFragment();
+ }
+ this.documentFragment_.appendChild(tileElement);
+ this.tiles_[tileCoordKey] = tile;
+};
+
+
+/**
+ * FIXME empty description for jsdoc
+ */
+ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() {
+ if (this.documentFragment_) {
+ this.target.appendChild(this.documentFragment_);
+ this.documentFragment_ = null;
+ }
+};
+
+
+/**
+ * @return {ol.Coordinate} Origin.
+ */
+ol.renderer.dom.TileLayerZ_.prototype.getOrigin = function() {
+ return this.origin_;
+};
+
+
+/**
+ * @return {number} Resolution.
+ */
+ol.renderer.dom.TileLayerZ_.prototype.getResolution = function() {
+ return this.resolution_;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.
+ */
+ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent = function(extent, opt_tileRange) {
+ var tileRange = this.tileGrid_.getTileRangeForExtentAndZ(
+ extent, this.tileCoordOrigin_[0], opt_tileRange);
+ /** @type {Array.<ol.Tile>} */
+ var tilesToRemove = [];
+ var tile, tileCoordKey;
+ for (tileCoordKey in this.tiles_) {
+ tile = this.tiles_[tileCoordKey];
+ if (!tileRange.contains(tile.tileCoord)) {
+ tilesToRemove.push(tile);
+ }
+ }
+ var i, ii;
+ for (i = 0, ii = tilesToRemove.length; i < ii; ++i) {
+ tile = tilesToRemove[i];
+ tileCoordKey = tile.tileCoord.toString();
+ ol.dom.removeNode(tile.getImage(this));
+ delete this.tiles_[tileCoordKey];
+ }
+};
+
+
+/**
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ */
+ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) {
+ if (!ol.vec.Mat4.equals2D(transform, this.transform_)) {
+ ol.dom.transformElement2D(this.target, transform, 6);
+ goog.vec.Mat4.setFromArray(this.transform_, transform);
+ }
+};
+
+goog.provide('ol.renderer.dom.VectorLayer');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('goog.vec.Mat4');
+goog.require('ol.ViewHint');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.layer.Vector');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.canvas.Immediate');
+goog.require('ol.render.canvas.ReplayGroup');
+goog.require('ol.renderer.dom.Layer');
+goog.require('ol.renderer.vector');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.dom.Layer}
+ * @param {ol.layer.Vector} vectorLayer Vector layer.
+ */
+ol.renderer.dom.VectorLayer = function(vectorLayer) {
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = ol.dom.createCanvasContext2D();
+
+ var target = this.context_.canvas;
+ // Bootstrap sets the style max-width: 100% for all images, which breaks
+ // prevents the image from being displayed in FireFox. Workaround by
+ // overriding the max-width style.
+ target.style.maxWidth = 'none';
+ target.style.position = 'absolute';
+
+ ol.renderer.dom.Layer.call(this, vectorLayer, target);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.dirty_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedResolution_ = NaN;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.renderedExtent_ = ol.extent.createEmpty();
+
+ /**
+ * @private
+ * @type {function(ol.Feature, ol.Feature): number|null}
+ */
+ this.renderedRenderOrder_ = null;
+
+ /**
+ * @private
+ * @type {ol.render.canvas.ReplayGroup}
+ */
+ this.replayGroup_ = null;
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.elementTransform_ = goog.vec.Mat4.createNumber();
+
+};
+ol.inherits(ol.renderer.dom.VectorLayer, ol.renderer.dom.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.VectorLayer.prototype.clearFrame = function() {
+ // Clear the canvas
+ var canvas = this.context_.canvas;
+ canvas.width = canvas.width;
+ this.renderedRevision_ = 0;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.VectorLayer.prototype.composeFrame = function(frameState, layerState) {
+
+ var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
+ goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector,
+ 'layer is an instance of ol.layer.Vector');
+
+ var viewState = frameState.viewState;
+ var viewCenter = viewState.center;
+ var viewRotation = viewState.rotation;
+ var viewResolution = viewState.resolution;
+ var pixelRatio = frameState.pixelRatio;
+ var viewWidth = frameState.size[0];
+ var viewHeight = frameState.size[1];
+ var imageWidth = viewWidth * pixelRatio;
+ var imageHeight = viewHeight * pixelRatio;
+
+ var transform = ol.vec.Mat4.makeTransform2D(this.transform_,
+ pixelRatio * viewWidth / 2,
+ pixelRatio * viewHeight / 2,
+ pixelRatio / viewResolution,
+ -pixelRatio / viewResolution,
+ -viewRotation,
+ -viewCenter[0], -viewCenter[1]);
+
+ var context = this.context_;
+
+ // Clear the canvas and set the correct size
+ context.canvas.width = imageWidth;
+ context.canvas.height = imageHeight;
+
+ var elementTransform = ol.vec.Mat4.makeTransform2D(this.elementTransform_,
+ 0, 0,
+ 1 / pixelRatio, 1 / pixelRatio,
+ 0,
+ -(imageWidth - viewWidth) / 2 * pixelRatio,
+ -(imageHeight - viewHeight) / 2 * pixelRatio);
+ ol.dom.transformElement2D(context.canvas, elementTransform, 6);
+
+ this.dispatchEvent_(ol.render.EventType.PRECOMPOSE, frameState, transform);
+
+ var replayGroup = this.replayGroup_;
+
+ if (replayGroup && !replayGroup.isEmpty()) {
+
+ context.globalAlpha = layerState.opacity;
+ replayGroup.replay(context, pixelRatio, transform, viewRotation,
+ layerState.managed ? frameState.skippedFeatureUids : {});
+
+ this.dispatchEvent_(ol.render.EventType.RENDER, frameState, transform);
+ }
+
+ this.dispatchEvent_(ol.render.EventType.POSTCOMPOSE, frameState, transform);
+};
+
+
+/**
+ * @param {ol.render.EventType} type Event type.
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {goog.vec.Mat4.Number} transform Transform.
+ * @private
+ */
+ol.renderer.dom.VectorLayer.prototype.dispatchEvent_ = function(type, frameState, transform) {
+ var context = this.context_;
+ var layer = this.getLayer();
+ if (layer.hasListener(type)) {
+ var render = new ol.render.canvas.Immediate(
+ context, frameState.pixelRatio, frameState.extent, transform,
+ frameState.viewState.rotation);
+ var event = new ol.render.Event(type, layer, render, frameState,
+ context, null);
+ layer.dispatchEvent(event);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ if (!this.replayGroup_) {
+ return undefined;
+ } else {
+ var resolution = frameState.viewState.resolution;
+ var rotation = frameState.viewState.rotation;
+ var layer = this.getLayer();
+ /** @type {Object.<string, boolean>} */
+ var features = {};
+ return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
+ rotation, {},
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ goog.asserts.assert(feature !== undefined, 'received a feature');
+ var key = goog.getUid(feature).toString();
+ if (!(key in features)) {
+ features[key] = true;
+ return callback.call(thisArg, feature, layer);
+ }
+ });
+ }
+};
+
+
+/**
+ * Handle changes in image style state.
+ * @param {ol.events.Event} event Image style change event.
+ * @private
+ */
+ol.renderer.dom.VectorLayer.prototype.handleStyleImageChange_ = function(event) {
+ this.renderIfReadyAndVisible();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.VectorLayer.prototype.prepareFrame = function(frameState, layerState) {
+
+ var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
+ goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector,
+ 'layer is an instance of ol.layer.Vector');
+ var vectorSource = vectorLayer.getSource();
+
+ this.updateAttributions(
+ frameState.attributions, vectorSource.getAttributions());
+ this.updateLogos(frameState, vectorSource);
+
+ var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
+ var interacting = frameState.viewHints[ol.ViewHint.INTERACTING];
+ var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();
+ var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();
+
+ if (!this.dirty_ && (!updateWhileAnimating && animating) ||
+ (!updateWhileInteracting && interacting)) {
+ return true;
+ }
+
+ var frameStateExtent = frameState.extent;
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+ var resolution = viewState.resolution;
+ var pixelRatio = frameState.pixelRatio;
+ var vectorLayerRevision = vectorLayer.getRevision();
+ var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();
+ var vectorLayerRenderOrder = vectorLayer.getRenderOrder();
+
+ if (vectorLayerRenderOrder === undefined) {
+ vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;
+ }
+
+ var extent = ol.extent.buffer(frameStateExtent,
+ vectorLayerRenderBuffer * resolution);
+
+ if (!this.dirty_ &&
+ this.renderedResolution_ == resolution &&
+ this.renderedRevision_ == vectorLayerRevision &&
+ this.renderedRenderOrder_ == vectorLayerRenderOrder &&
+ ol.extent.containsExtent(this.renderedExtent_, extent)) {
+ return true;
+ }
+
+ this.replayGroup_ = null;
+
+ this.dirty_ = false;
+
+ var replayGroup =
+ new ol.render.canvas.ReplayGroup(
+ ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
+ resolution, vectorLayer.getRenderBuffer());
+ vectorSource.loadFeatures(extent, resolution, projection);
+ /**
+ * @param {ol.Feature} feature Feature.
+ * @this {ol.renderer.dom.VectorLayer}
+ */
+ var renderFeature = function(feature) {
+ var styles;
+ var styleFunction = feature.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction.call(feature, resolution);
+ } else {
+ styleFunction = vectorLayer.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction(feature, resolution);
+ }
+ }
+ if (styles) {
+ var dirty = this.renderFeature(
+ feature, resolution, pixelRatio, styles, replayGroup);
+ this.dirty_ = this.dirty_ || dirty;
+ }
+ };
+ if (vectorLayerRenderOrder) {
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ vectorSource.forEachFeatureInExtent(extent,
+ /**
+ * @param {ol.Feature} feature Feature.
+ */
+ function(feature) {
+ features.push(feature);
+ }, this);
+ features.sort(vectorLayerRenderOrder);
+ features.forEach(renderFeature, this);
+ } else {
+ vectorSource.forEachFeatureInExtent(extent, renderFeature, this);
+ }
+ replayGroup.finish();
+
+ this.renderedResolution_ = resolution;
+ this.renderedRevision_ = vectorLayerRevision;
+ this.renderedRenderOrder_ = vectorLayerRenderOrder;
+ this.renderedExtent_ = extent;
+ this.replayGroup_ = replayGroup;
+
+ return true;
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
+ * styles.
+ * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
+ * @return {boolean} `true` if an image is loading.
+ */
+ol.renderer.dom.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {
+ if (!styles) {
+ return false;
+ }
+ var loading = false;
+ if (Array.isArray(styles)) {
+ for (var i = 0, ii = styles.length; i < ii; ++i) {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles[i],
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleStyleImageChange_, this) || loading;
+ }
+ } else {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles,
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleStyleImageChange_, this) || loading;
+ }
+ return loading;
+};
+
+goog.provide('ol.renderer.dom.Map');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('goog.vec.Mat4');
+goog.require('ol');
+goog.require('ol.RendererType');
+goog.require('ol.array');
+goog.require('ol.css');
+goog.require('ol.dom');
+goog.require('ol.layer.Image');
+goog.require('ol.layer.Layer');
+goog.require('ol.layer.Tile');
+goog.require('ol.layer.Vector');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.canvas.Immediate');
+goog.require('ol.renderer.Map');
+goog.require('ol.renderer.dom.ImageLayer');
+goog.require('ol.renderer.dom.Layer');
+goog.require('ol.renderer.dom.TileLayer');
+goog.require('ol.renderer.dom.VectorLayer');
+goog.require('ol.source.State');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.Map}
+ * @param {Element} container Container.
+ * @param {ol.Map} map Map.
+ */
+ol.renderer.dom.Map = function(container, map) {
+
+ ol.renderer.Map.call(this, container, map);
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = ol.dom.createCanvasContext2D();
+ var canvas = this.context_.canvas;
+ canvas.style.position = 'absolute';
+ canvas.style.width = '100%';
+ canvas.style.height = '100%';
+ canvas.className = ol.css.CLASS_UNSELECTABLE;
+ container.insertBefore(canvas, container.childNodes[0] || null);
+
+ /**
+ * @private
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.transform_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @type {!Element}
+ * @private
+ */
+ this.layersPane_ = document.createElement('DIV');
+ this.layersPane_.className = ol.css.CLASS_UNSELECTABLE;
+ var style = this.layersPane_.style;
+ style.position = 'absolute';
+ style.width = '100%';
+ style.height = '100%';
+
+ // prevent the img context menu on mobile devices
+ ol.events.listen(this.layersPane_, ol.events.EventType.TOUCHSTART,
+ ol.events.Event.preventDefault);
+
+ container.insertBefore(this.layersPane_, container.childNodes[0] || null);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderedVisible_ = true;
+
+};
+ol.inherits(ol.renderer.dom.Map, ol.renderer.Map);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.Map.prototype.disposeInternal = function() {
+ ol.dom.removeNode(this.layersPane_);
+ ol.renderer.Map.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) {
+ var layerRenderer;
+ if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) {
+ layerRenderer = new ol.renderer.dom.ImageLayer(layer);
+ } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {
+ layerRenderer = new ol.renderer.dom.TileLayer(layer);
+ } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {
+ layerRenderer = new ol.renderer.dom.VectorLayer(layer);
+ } else {
+ goog.asserts.fail('unexpected layer configuration');
+ return null;
+ }
+ return layerRenderer;
+};
+
+
+/**
+ * @param {ol.render.EventType} type Event type.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.dom.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {
+ var map = this.getMap();
+ if (map.hasListener(type)) {
+ var extent = frameState.extent;
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var rotation = viewState.rotation;
+ var context = this.context_;
+ var canvas = context.canvas;
+
+ ol.vec.Mat4.makeTransform2D(this.transform_,
+ canvas.width / 2,
+ canvas.height / 2,
+ pixelRatio / viewState.resolution,
+ -pixelRatio / viewState.resolution,
+ -viewState.rotation,
+ -viewState.center[0], -viewState.center[1]);
+ var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
+ extent, this.transform_, rotation);
+ var composeEvent = new ol.render.Event(type, map, vectorContext,
+ frameState, context, null);
+ map.dispatchEvent(composeEvent);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.Map.prototype.getType = function() {
+ return ol.RendererType.DOM;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.dom.Map.prototype.renderFrame = function(frameState) {
+
+ if (!frameState) {
+ if (this.renderedVisible_) {
+ this.layersPane_.style.display = 'none';
+ this.renderedVisible_ = false;
+ }
+ return;
+ }
+
+ var map = this.getMap();
+ if (map.hasListener(ol.render.EventType.PRECOMPOSE) ||
+ map.hasListener(ol.render.EventType.POSTCOMPOSE)) {
+ var canvas = this.context_.canvas;
+ var pixelRatio = frameState.pixelRatio;
+ canvas.width = frameState.size[0] * pixelRatio;
+ canvas.height = frameState.size[1] * pixelRatio;
+ }
+
+ this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
+
+ var layerStatesArray = frameState.layerStatesArray;
+ ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
+
+ var viewResolution = frameState.viewState.resolution;
+ var i, ii, layer, layerRenderer, layerState;
+ for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
+ layerState = layerStatesArray[i];
+ layer = layerState.layer;
+ layerRenderer = /** @type {ol.renderer.dom.Layer} */ (
+ this.getLayerRenderer(layer));
+ goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer,
+ 'renderer is an instance of ol.renderer.dom.Layer');
+ this.layersPane_.insertBefore(layerRenderer.getTarget(), this.layersPane_.childNodes[i] || null);
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
+ layerState.sourceState == ol.source.State.READY) {
+ if (layerRenderer.prepareFrame(frameState, layerState)) {
+ layerRenderer.composeFrame(frameState, layerState);
+ }
+ } else {
+ layerRenderer.clearFrame();
+ }
+ }
+
+ var layerStates = frameState.layerStates;
+ var layerKey;
+ for (layerKey in this.getLayerRenderers()) {
+ if (!(layerKey in layerStates)) {
+ layerRenderer = this.getLayerRendererByKey(layerKey);
+ goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer,
+ 'renderer is an instance of ol.renderer.dom.Layer');
+ ol.dom.removeNode(layerRenderer.getTarget());
+ }
+ }
+
+ if (!this.renderedVisible_) {
+ this.layersPane_.style.display = '';
+ this.renderedVisible_ = true;
+ }
+
+ this.calculateMatrices2D(frameState);
+ this.scheduleRemoveUnusedLayerRenderers(frameState);
+ this.scheduleExpireIconCache(frameState);
+
+ this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState);
+};
+
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview Constants used by the WebGL rendering, including all of the
+ * constants used from the WebGL context. For example, instead of using
+ * context.ARRAY_BUFFER, your code can use
+ * goog.webgl.ARRAY_BUFFER. The benefits for doing this include allowing
+ * the compiler to optimize your code so that the compiled code does not have to
+ * contain large strings to reference these properties, and reducing runtime
+ * property access.
+ *
+ * Values are taken from the WebGL Spec:
+ * https://www.khronos.org/registry/webgl/specs/1.0/#WEBGLRENDERINGCONTEXT
+ */
+
+goog.provide('goog.webgl');
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_BUFFER_BIT = 0x00000100;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BUFFER_BIT = 0x00000400;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.COLOR_BUFFER_BIT = 0x00004000;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.POINTS = 0x0000;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINES = 0x0001;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINE_LOOP = 0x0002;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINE_STRIP = 0x0003;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TRIANGLES = 0x0004;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TRIANGLE_STRIP = 0x0005;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TRIANGLE_FAN = 0x0006;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ZERO = 0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE = 1;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SRC_COLOR = 0x0300;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE_MINUS_SRC_COLOR = 0x0301;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SRC_ALPHA = 0x0302;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE_MINUS_SRC_ALPHA = 0x0303;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DST_ALPHA = 0x0304;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE_MINUS_DST_ALPHA = 0x0305;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DST_COLOR = 0x0306;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE_MINUS_DST_COLOR = 0x0307;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SRC_ALPHA_SATURATE = 0x0308;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FUNC_ADD = 0x8006;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_EQUATION = 0x8009;
+
+
+/**
+ * Same as BLEND_EQUATION
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_EQUATION_RGB = 0x8009;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_EQUATION_ALPHA = 0x883D;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FUNC_SUBTRACT = 0x800A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FUNC_REVERSE_SUBTRACT = 0x800B;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_DST_RGB = 0x80C8;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_SRC_RGB = 0x80C9;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_DST_ALPHA = 0x80CA;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_SRC_ALPHA = 0x80CB;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CONSTANT_COLOR = 0x8001;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE_MINUS_CONSTANT_COLOR = 0x8002;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CONSTANT_ALPHA = 0x8003;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ONE_MINUS_CONSTANT_ALPHA = 0x8004;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND_COLOR = 0x8005;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ARRAY_BUFFER = 0x8892;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ELEMENT_ARRAY_BUFFER = 0x8893;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ARRAY_BUFFER_BINDING = 0x8894;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STREAM_DRAW = 0x88E0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STATIC_DRAW = 0x88E4;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DYNAMIC_DRAW = 0x88E8;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BUFFER_SIZE = 0x8764;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BUFFER_USAGE = 0x8765;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CURRENT_VERTEX_ATTRIB = 0x8626;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRONT = 0x0404;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BACK = 0x0405;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRONT_AND_BACK = 0x0408;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CULL_FACE = 0x0B44;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLEND = 0x0BE2;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DITHER = 0x0BD0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_TEST = 0x0B90;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_TEST = 0x0B71;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SCISSOR_TEST = 0x0C11;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.POLYGON_OFFSET_FILL = 0x8037;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLE_COVERAGE = 0x80A0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NO_ERROR = 0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INVALID_ENUM = 0x0500;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INVALID_VALUE = 0x0501;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INVALID_OPERATION = 0x0502;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.OUT_OF_MEMORY = 0x0505;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CW = 0x0900;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CCW = 0x0901;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINE_WIDTH = 0x0B21;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ALIASED_POINT_SIZE_RANGE = 0x846D;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ALIASED_LINE_WIDTH_RANGE = 0x846E;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CULL_FACE_MODE = 0x0B45;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRONT_FACE = 0x0B46;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_RANGE = 0x0B70;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_WRITEMASK = 0x0B72;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_CLEAR_VALUE = 0x0B73;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_FUNC = 0x0B74;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_CLEAR_VALUE = 0x0B91;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_FUNC = 0x0B92;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_FAIL = 0x0B94;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_PASS_DEPTH_FAIL = 0x0B95;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_PASS_DEPTH_PASS = 0x0B96;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_REF = 0x0B97;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_VALUE_MASK = 0x0B93;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_WRITEMASK = 0x0B98;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_FUNC = 0x8800;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_FAIL = 0x8801;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_REF = 0x8CA3;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_VALUE_MASK = 0x8CA4;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BACK_WRITEMASK = 0x8CA5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VIEWPORT = 0x0BA2;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SCISSOR_BOX = 0x0C10;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.COLOR_CLEAR_VALUE = 0x0C22;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.COLOR_WRITEMASK = 0x0C23;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNPACK_ALIGNMENT = 0x0CF5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.PACK_ALIGNMENT = 0x0D05;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_TEXTURE_SIZE = 0x0D33;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_VIEWPORT_DIMS = 0x0D3A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SUBPIXEL_BITS = 0x0D50;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RED_BITS = 0x0D52;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.GREEN_BITS = 0x0D53;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BLUE_BITS = 0x0D54;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ALPHA_BITS = 0x0D55;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_BITS = 0x0D56;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_BITS = 0x0D57;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.POLYGON_OFFSET_UNITS = 0x2A00;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.POLYGON_OFFSET_FACTOR = 0x8038;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_BINDING_2D = 0x8069;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLE_BUFFERS = 0x80A8;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLES = 0x80A9;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLE_COVERAGE_VALUE = 0x80AA;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLE_COVERAGE_INVERT = 0x80AB;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.COMPRESSED_TEXTURE_FORMATS = 0x86A3;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DONT_CARE = 0x1100;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FASTEST = 0x1101;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NICEST = 0x1102;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.GENERATE_MIPMAP_HINT = 0x8192;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BYTE = 0x1400;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNSIGNED_BYTE = 0x1401;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SHORT = 0x1402;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNSIGNED_SHORT = 0x1403;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INT = 0x1404;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNSIGNED_INT = 0x1405;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT = 0x1406;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_COMPONENT = 0x1902;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ALPHA = 0x1906;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RGB = 0x1907;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RGBA = 0x1908;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LUMINANCE = 0x1909;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LUMINANCE_ALPHA = 0x190A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNSIGNED_SHORT_4_4_4_4 = 0x8033;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNSIGNED_SHORT_5_5_5_1 = 0x8034;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNSIGNED_SHORT_5_6_5 = 0x8363;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAGMENT_SHADER = 0x8B30;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_SHADER = 0x8B31;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_VERTEX_ATTRIBS = 0x8869;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_VARYING_VECTORS = 0x8DFC;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_TEXTURE_IMAGE_UNITS = 0x8872;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SHADER_TYPE = 0x8B4F;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DELETE_STATUS = 0x8B80;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINK_STATUS = 0x8B82;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VALIDATE_STATUS = 0x8B83;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ATTACHED_SHADERS = 0x8B85;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ACTIVE_UNIFORMS = 0x8B86;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ACTIVE_ATTRIBUTES = 0x8B89;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SHADING_LANGUAGE_VERSION = 0x8B8C;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CURRENT_PROGRAM = 0x8B8D;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NEVER = 0x0200;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LESS = 0x0201;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.EQUAL = 0x0202;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LEQUAL = 0x0203;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.GREATER = 0x0204;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NOTEQUAL = 0x0205;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.GEQUAL = 0x0206;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ALWAYS = 0x0207;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.KEEP = 0x1E00;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.REPLACE = 0x1E01;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INCR = 0x1E02;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DECR = 0x1E03;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INVERT = 0x150A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INCR_WRAP = 0x8507;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DECR_WRAP = 0x8508;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VENDOR = 0x1F00;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERER = 0x1F01;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERSION = 0x1F02;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NEAREST = 0x2600;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINEAR = 0x2601;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NEAREST_MIPMAP_NEAREST = 0x2700;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINEAR_MIPMAP_NEAREST = 0x2701;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NEAREST_MIPMAP_LINEAR = 0x2702;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LINEAR_MIPMAP_LINEAR = 0x2703;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_MAG_FILTER = 0x2800;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_MIN_FILTER = 0x2801;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_WRAP_S = 0x2802;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_WRAP_T = 0x2803;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_2D = 0x0DE1;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE = 0x1702;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP = 0x8513;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_BINDING_CUBE_MAP = 0x8514;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE0 = 0x84C0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE1 = 0x84C1;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE2 = 0x84C2;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE3 = 0x84C3;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE4 = 0x84C4;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE5 = 0x84C5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE6 = 0x84C6;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE7 = 0x84C7;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE8 = 0x84C8;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE9 = 0x84C9;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE10 = 0x84CA;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE11 = 0x84CB;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE12 = 0x84CC;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE13 = 0x84CD;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE14 = 0x84CE;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE15 = 0x84CF;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE16 = 0x84D0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE17 = 0x84D1;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE18 = 0x84D2;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE19 = 0x84D3;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE20 = 0x84D4;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE21 = 0x84D5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE22 = 0x84D6;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE23 = 0x84D7;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE24 = 0x84D8;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE25 = 0x84D9;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE26 = 0x84DA;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE27 = 0x84DB;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE28 = 0x84DC;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE29 = 0x84DD;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE30 = 0x84DE;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE31 = 0x84DF;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.ACTIVE_TEXTURE = 0x84E0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.REPEAT = 0x2901;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CLAMP_TO_EDGE = 0x812F;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MIRRORED_REPEAT = 0x8370;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT_VEC2 = 0x8B50;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT_VEC3 = 0x8B51;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT_VEC4 = 0x8B52;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INT_VEC2 = 0x8B53;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INT_VEC3 = 0x8B54;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INT_VEC4 = 0x8B55;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BOOL = 0x8B56;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BOOL_VEC2 = 0x8B57;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BOOL_VEC3 = 0x8B58;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BOOL_VEC4 = 0x8B59;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT_MAT2 = 0x8B5A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT_MAT3 = 0x8B5B;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FLOAT_MAT4 = 0x8B5C;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLER_2D = 0x8B5E;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.SAMPLER_CUBE = 0x8B60;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.COMPILE_STATUS = 0x8B81;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LOW_FLOAT = 0x8DF0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MEDIUM_FLOAT = 0x8DF1;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.HIGH_FLOAT = 0x8DF2;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.LOW_INT = 0x8DF3;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MEDIUM_INT = 0x8DF4;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.HIGH_INT = 0x8DF5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER = 0x8D40;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER = 0x8D41;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RGBA4 = 0x8056;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RGB5_A1 = 0x8057;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RGB565 = 0x8D62;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_COMPONENT16 = 0x81A5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_INDEX = 0x1901;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_INDEX8 = 0x8D48;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_STENCIL = 0x84F9;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_WIDTH = 0x8D42;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_HEIGHT = 0x8D43;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_RED_SIZE = 0x8D50;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_GREEN_SIZE = 0x8D51;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_BLUE_SIZE = 0x8D52;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_ALPHA_SIZE = 0x8D53;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_DEPTH_SIZE = 0x8D54;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_STENCIL_SIZE = 0x8D55;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.COLOR_ATTACHMENT0 = 0x8CE0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_ATTACHMENT = 0x8D00;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.STENCIL_ATTACHMENT = 0x8D20;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.DEPTH_STENCIL_ATTACHMENT = 0x821A;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.NONE = 0;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_COMPLETE = 0x8CD5;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAMEBUFFER_BINDING = 0x8CA6;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.RENDERBUFFER_BINDING = 0x8CA7;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_RENDERBUFFER_SIZE = 0x84E8;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNPACK_FLIP_Y_WEBGL = 0x9240;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.CONTEXT_LOST_WEBGL = 0x9242;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+
+
+/**
+ * @const
+ * @type {number}
+ */
+goog.webgl.BROWSER_DEFAULT_WEBGL = 0x9244;
+
+
+/**
+ * From the OES_texture_half_float extension.
+ * http://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/
+ * @const
+ * @type {number}
+ */
+goog.webgl.HALF_FLOAT_OES = 0x8D61;
+
+
+/**
+ * From the OES_standard_derivatives extension.
+ * http://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
+ * @const
+ * @type {number}
+ */
+goog.webgl.FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
+
+
+/**
+ * From the OES_vertex_array_object extension.
+ * http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
+ * @const
+ * @type {number}
+ */
+goog.webgl.VERTEX_ARRAY_BINDING_OES = 0x85B5;
+
+
+/**
+ * From the WEBGL_debug_renderer_info extension.
+ * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNMASKED_VENDOR_WEBGL = 0x9245;
+
+
+/**
+ * From the WEBGL_debug_renderer_info extension.
+ * http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/
+ * @const
+ * @type {number}
+ */
+goog.webgl.UNMASKED_RENDERER_WEBGL = 0x9246;
+
+
+/**
+ * From the WEBGL_compressed_texture_s3tc extension.
+ * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+ * @const
+ * @type {number}
+ */
+goog.webgl.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
+
+
+/**
+ * From the WEBGL_compressed_texture_s3tc extension.
+ * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+ * @const
+ * @type {number}
+ */
+goog.webgl.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
+
+
+/**
+ * From the WEBGL_compressed_texture_s3tc extension.
+ * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+ * @const
+ * @type {number}
+ */
+goog.webgl.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
+
+
+/**
+ * From the WEBGL_compressed_texture_s3tc extension.
+ * http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+ * @const
+ * @type {number}
+ */
+goog.webgl.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
+
+
+/**
+ * From the EXT_texture_filter_anisotropic extension.
+ * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
+ * @const
+ * @type {number}
+ */
+goog.webgl.TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+
+
+/**
+ * From the EXT_texture_filter_anisotropic extension.
+ * http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
+ * @const
+ * @type {number}
+ */
+goog.webgl.MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+
+goog.provide('ol.webgl.Fragment');
+goog.provide('ol.webgl.Shader');
+goog.provide('ol.webgl.Vertex');
+goog.provide('ol.webgl.shader');
+
+goog.require('goog.webgl');
+goog.require('ol.functions');
+goog.require('ol.webgl');
+
+
+/**
+ * @constructor
+ * @param {string} source Source.
+ * @struct
+ */
+ol.webgl.Shader = function(source) {
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.source_ = source;
+
+};
+
+
+/**
+ * @return {number} Type.
+ */
+ol.webgl.Shader.prototype.getType = goog.abstractMethod;
+
+
+/**
+ * @return {string} Source.
+ */
+ol.webgl.Shader.prototype.getSource = function() {
+ return this.source_;
+};
+
+
+/**
+ * @return {boolean} Is animated?
+ */
+ol.webgl.Shader.prototype.isAnimated = ol.functions.FALSE;
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.Shader}
+ * @param {string} source Source.
+ * @struct
+ */
+ol.webgl.shader.Fragment = function(source) {
+ ol.webgl.Shader.call(this, source);
+};
+ol.inherits(ol.webgl.shader.Fragment, ol.webgl.Shader);
+
+
+/**
+ * @inheritDoc
+ */
+ol.webgl.shader.Fragment.prototype.getType = function() {
+ return goog.webgl.FRAGMENT_SHADER;
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.Shader}
+ * @param {string} source Source.
+ * @struct
+ */
+ol.webgl.shader.Vertex = function(source) {
+ ol.webgl.Shader.call(this, source);
+};
+ol.inherits(ol.webgl.shader.Vertex, ol.webgl.Shader);
+
+
+/**
+ * @inheritDoc
+ */
+ol.webgl.shader.Vertex.prototype.getType = function() {
+ return goog.webgl.VERTEX_SHADER;
+};
+
+// This file is automatically generated, do not edit
+goog.provide('ol.render.webgl.imagereplay.shader.Default');
+goog.provide('ol.render.webgl.imagereplay.shader.Default.Locations');
+goog.provide('ol.render.webgl.imagereplay.shader.DefaultFragment');
+goog.provide('ol.render.webgl.imagereplay.shader.DefaultVertex');
+
+goog.require('ol.webgl.shader');
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.shader.Fragment}
+ * @struct
+ */
+ol.render.webgl.imagereplay.shader.DefaultFragment = function() {
+ ol.webgl.shader.Fragment.call(this, ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE);
+};
+ol.inherits(ol.render.webgl.imagereplay.shader.DefaultFragment, ol.webgl.shader.Fragment);
+goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultFragment);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.webgl.imagereplay.shader.DefaultFragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\nvarying float v_opacity;\n\nuniform float u_opacity;\nuniform sampler2D u_image;\n\nvoid main(void) {\n vec4 texColor = texture2D(u_image, v_texCoord);\n gl_FragColor.rgb = texColor.rgb;\n float alpha = texColor.a * v_opacity * u_opacity;\n if (alpha == 0.0) {\n discard;\n }\n gl_FragColor.a = alpha;\n}\n';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.webgl.imagereplay.shader.DefaultFragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;varying float b;uniform float k;uniform sampler2D l;void main(void){vec4 texColor=texture2D(l,a);gl_FragColor.rgb=texColor.rgb;float alpha=texColor.a*b*k;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.webgl.imagereplay.shader.DefaultFragment.SOURCE = goog.DEBUG ?
+ ol.render.webgl.imagereplay.shader.DefaultFragment.DEBUG_SOURCE :
+ ol.render.webgl.imagereplay.shader.DefaultFragment.OPTIMIZED_SOURCE;
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.shader.Vertex}
+ * @struct
+ */
+ol.render.webgl.imagereplay.shader.DefaultVertex = function() {
+ ol.webgl.shader.Vertex.call(this, ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE);
+};
+ol.inherits(ol.render.webgl.imagereplay.shader.DefaultVertex, ol.webgl.shader.Vertex);
+goog.addSingletonGetter(ol.render.webgl.imagereplay.shader.DefaultVertex);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.webgl.imagereplay.shader.DefaultVertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\nvarying float v_opacity;\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\nattribute vec2 a_offsets;\nattribute float a_opacity;\nattribute float a_rotateWithView;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix;\n if (a_rotateWithView == 1.0) {\n offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n }\n vec4 offsets = offsetMatrix * vec4(a_offsets, 0., 0.);\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + offsets;\n v_texCoord = a_texCoord;\n v_opacity = a_opacity;\n}\n\n\n';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.webgl.imagereplay.shader.DefaultVertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying float b;attribute vec2 c;attribute vec2 d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;void main(void){mat4 offsetMatrix=i;if(g==1.0){offsetMatrix=i*j;}vec4 offsets=offsetMatrix*vec4(e,0.,0.);gl_Position=h*vec4(c,0.,1.)+offsets;a=d;b=f;}';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.render.webgl.imagereplay.shader.DefaultVertex.SOURCE = goog.DEBUG ?
+ ol.render.webgl.imagereplay.shader.DefaultVertex.DEBUG_SOURCE :
+ ol.render.webgl.imagereplay.shader.DefaultVertex.OPTIMIZED_SOURCE;
+
+
+/**
+ * @constructor
+ * @param {WebGLRenderingContext} gl GL.
+ * @param {WebGLProgram} program Program.
+ * @struct
+ */
+ol.render.webgl.imagereplay.shader.Default.Locations = function(gl, program) {
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_image = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_image' : 'l');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_offsetRotateMatrix = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_offsetRotateMatrix' : 'j');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_offsetScaleMatrix = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_offsetScaleMatrix' : 'i');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_opacity = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_opacity' : 'k');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_projectionMatrix = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_projectionMatrix' : 'h');
+
+ /**
+ * @type {number}
+ */
+ this.a_offsets = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_offsets' : 'e');
+
+ /**
+ * @type {number}
+ */
+ this.a_opacity = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_opacity' : 'f');
+
+ /**
+ * @type {number}
+ */
+ this.a_position = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_position' : 'c');
+
+ /**
+ * @type {number}
+ */
+ this.a_rotateWithView = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_rotateWithView' : 'g');
+
+ /**
+ * @type {number}
+ */
+ this.a_texCoord = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_texCoord' : 'd');
+};
+
+goog.provide('ol.webgl.Buffer');
+
+goog.require('goog.webgl');
+goog.require('ol');
+
+
+/**
+ * @enum {number}
+ */
+ol.webgl.BufferUsage = {
+ STATIC_DRAW: goog.webgl.STATIC_DRAW,
+ STREAM_DRAW: goog.webgl.STREAM_DRAW,
+ DYNAMIC_DRAW: goog.webgl.DYNAMIC_DRAW
+};
+
+
+/**
+ * @constructor
+ * @param {Array.<number>=} opt_arr Array.
+ * @param {number=} opt_usage Usage.
+ * @struct
+ */
+ol.webgl.Buffer = function(opt_arr, opt_usage) {
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.arr_ = opt_arr !== undefined ? opt_arr : [];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.usage_ = opt_usage !== undefined ?
+ opt_usage : ol.webgl.BufferUsage.STATIC_DRAW;
+
+};
+
+
+/**
+ * @return {Array.<number>} Array.
+ */
+ol.webgl.Buffer.prototype.getArray = function() {
+ return this.arr_;
+};
+
+
+/**
+ * @return {number} Usage.
+ */
+ol.webgl.Buffer.prototype.getUsage = function() {
+ return this.usage_;
+};
+
+goog.provide('ol.webgl.Context');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.Disposable');
+goog.require('ol.array');
+goog.require('ol.events');
+goog.require('ol.object');
+goog.require('ol.webgl.Buffer');
+goog.require('ol.webgl.WebGLContextEventType');
+
+
+/**
+ * @classdesc
+ * A WebGL context for accessing low-level WebGL capabilities.
+ *
+ * @constructor
+ * @extends {ol.Disposable}
+ * @param {HTMLCanvasElement} canvas Canvas.
+ * @param {WebGLRenderingContext} gl GL.
+ */
+ol.webgl.Context = function(canvas, gl) {
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = canvas;
+
+ /**
+ * @private
+ * @type {WebGLRenderingContext}
+ */
+ this.gl_ = gl;
+
+ /**
+ * @private
+ * @type {Object.<string, ol.WebglBufferCacheEntry>}
+ */
+ this.bufferCache_ = {};
+
+ /**
+ * @private
+ * @type {Object.<string, WebGLShader>}
+ */
+ this.shaderCache_ = {};
+
+ /**
+ * @private
+ * @type {Object.<string, WebGLProgram>}
+ */
+ this.programCache_ = {};
+
+ /**
+ * @private
+ * @type {WebGLProgram}
+ */
+ this.currentProgram_ = null;
+
+ /**
+ * @private
+ * @type {WebGLFramebuffer}
+ */
+ this.hitDetectionFramebuffer_ = null;
+
+ /**
+ * @private
+ * @type {WebGLTexture}
+ */
+ this.hitDetectionTexture_ = null;
+
+ /**
+ * @private
+ * @type {WebGLRenderbuffer}
+ */
+ this.hitDetectionRenderbuffer_ = null;
+
+ /**
+ * @type {boolean}
+ */
+ this.hasOESElementIndexUint = ol.array.includes(
+ ol.WEBGL_EXTENSIONS, 'OES_element_index_uint');
+
+ // use the OES_element_index_uint extension if available
+ if (this.hasOESElementIndexUint) {
+ var ext = gl.getExtension('OES_element_index_uint');
+ goog.asserts.assert(ext,
+ 'Failed to get extension "OES_element_index_uint"');
+ }
+
+ ol.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST,
+ this.handleWebGLContextLost, this);
+ ol.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED,
+ this.handleWebGLContextRestored, this);
+
+};
+ol.inherits(ol.webgl.Context, ol.Disposable);
+
+
+/**
+ * Just bind the buffer if it's in the cache. Otherwise create
+ * the WebGL buffer, bind it, populate it, and add an entry to
+ * the cache.
+ * @param {number} target Target.
+ * @param {ol.webgl.Buffer} buf Buffer.
+ */
+ol.webgl.Context.prototype.bindBuffer = function(target, buf) {
+ var gl = this.getGL();
+ var arr = buf.getArray();
+ var bufferKey = String(goog.getUid(buf));
+ if (bufferKey in this.bufferCache_) {
+ var bufferCacheEntry = this.bufferCache_[bufferKey];
+ gl.bindBuffer(target, bufferCacheEntry.buffer);
+ } else {
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(target, buffer);
+ goog.asserts.assert(target == goog.webgl.ARRAY_BUFFER ||
+ target == goog.webgl.ELEMENT_ARRAY_BUFFER,
+ 'target is supposed to be an ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER');
+ var /** @type {ArrayBufferView} */ arrayBuffer;
+ if (target == goog.webgl.ARRAY_BUFFER) {
+ arrayBuffer = new Float32Array(arr);
+ } else if (target == goog.webgl.ELEMENT_ARRAY_BUFFER) {
+ arrayBuffer = this.hasOESElementIndexUint ?
+ new Uint32Array(arr) : new Uint16Array(arr);
+ } else {
+ goog.asserts.fail();
+ }
+ gl.bufferData(target, arrayBuffer, buf.getUsage());
+ this.bufferCache_[bufferKey] = {
+ buf: buf,
+ buffer: buffer
+ };
+ }
+};
+
+
+/**
+ * @param {ol.webgl.Buffer} buf Buffer.
+ */
+ol.webgl.Context.prototype.deleteBuffer = function(buf) {
+ var gl = this.getGL();
+ var bufferKey = String(goog.getUid(buf));
+ goog.asserts.assert(bufferKey in this.bufferCache_,
+ 'attempted to delete uncached buffer');
+ var bufferCacheEntry = this.bufferCache_[bufferKey];
+ if (!gl.isContextLost()) {
+ gl.deleteBuffer(bufferCacheEntry.buffer);
+ }
+ delete this.bufferCache_[bufferKey];
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.webgl.Context.prototype.disposeInternal = function() {
+ ol.events.unlistenAll(this.canvas_);
+ var gl = this.getGL();
+ if (!gl.isContextLost()) {
+ var key;
+ for (key in this.bufferCache_) {
+ gl.deleteBuffer(this.bufferCache_[key].buffer);
+ }
+ for (key in this.programCache_) {
+ gl.deleteProgram(this.programCache_[key]);
+ }
+ for (key in this.shaderCache_) {
+ gl.deleteShader(this.shaderCache_[key]);
+ }
+ // delete objects for hit-detection
+ gl.deleteFramebuffer(this.hitDetectionFramebuffer_);
+ gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_);
+ gl.deleteTexture(this.hitDetectionTexture_);
+ }
+};
+
+
+/**
+ * @return {HTMLCanvasElement} Canvas.
+ */
+ol.webgl.Context.prototype.getCanvas = function() {
+ return this.canvas_;
+};
+
+
+/**
+ * Get the WebGL rendering context
+ * @return {WebGLRenderingContext} The rendering context.
+ * @api
+ */
+ol.webgl.Context.prototype.getGL = function() {
+ return this.gl_;
+};
+
+
+/**
+ * Get the frame buffer for hit detection.
+ * @return {WebGLFramebuffer} The hit detection frame buffer.
+ */
+ol.webgl.Context.prototype.getHitDetectionFramebuffer = function() {
+ if (!this.hitDetectionFramebuffer_) {
+ this.initHitDetectionFramebuffer_();
+ }
+ return this.hitDetectionFramebuffer_;
+};
+
+
+/**
+ * Get shader from the cache if it's in the cache. Otherwise, create
+ * the WebGL shader, compile it, and add entry to cache.
+ * @param {ol.webgl.Shader} shaderObject Shader object.
+ * @return {WebGLShader} Shader.
+ */
+ol.webgl.Context.prototype.getShader = function(shaderObject) {
+ var shaderKey = String(goog.getUid(shaderObject));
+ if (shaderKey in this.shaderCache_) {
+ return this.shaderCache_[shaderKey];
+ } else {
+ var gl = this.getGL();
+ var shader = gl.createShader(shaderObject.getType());
+ gl.shaderSource(shader, shaderObject.getSource());
+ gl.compileShader(shader);
+ goog.asserts.assert(
+ gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) ||
+ gl.isContextLost(),
+ gl.getShaderInfoLog(shader) || 'illegal state, shader not compiled or context lost');
+ this.shaderCache_[shaderKey] = shader;
+ return shader;
+ }
+};
+
+
+/**
+ * Get the program from the cache if it's in the cache. Otherwise create
+ * the WebGL program, attach the shaders to it, and add an entry to the
+ * cache.
+ * @param {ol.webgl.shader.Fragment} fragmentShaderObject Fragment shader.
+ * @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader.
+ * @return {WebGLProgram} Program.
+ */
+ol.webgl.Context.prototype.getProgram = function(
+ fragmentShaderObject, vertexShaderObject) {
+ var programKey =
+ goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject);
+ if (programKey in this.programCache_) {
+ return this.programCache_[programKey];
+ } else {
+ var gl = this.getGL();
+ var program = gl.createProgram();
+ gl.attachShader(program, this.getShader(fragmentShaderObject));
+ gl.attachShader(program, this.getShader(vertexShaderObject));
+ gl.linkProgram(program);
+ goog.asserts.assert(
+ gl.getProgramParameter(program, goog.webgl.LINK_STATUS) ||
+ gl.isContextLost(),
+ gl.getProgramInfoLog(program) || 'illegal state, shader not linked or context lost');
+ this.programCache_[programKey] = program;
+ return program;
+ }
+};
+
+
+/**
+ * FIXME empy description for jsdoc
+ */
+ol.webgl.Context.prototype.handleWebGLContextLost = function() {
+ ol.object.clear(this.bufferCache_);
+ ol.object.clear(this.shaderCache_);
+ ol.object.clear(this.programCache_);
+ this.currentProgram_ = null;
+ this.hitDetectionFramebuffer_ = null;
+ this.hitDetectionTexture_ = null;
+ this.hitDetectionRenderbuffer_ = null;
+};
+
+
+/**
+ * FIXME empy description for jsdoc
+ */
+ol.webgl.Context.prototype.handleWebGLContextRestored = function() {
+};
+
+
+/**
+ * Creates a 1x1 pixel framebuffer for the hit-detection.
+ * @private
+ */
+ol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() {
+ var gl = this.gl_;
+ var framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+
+ var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1);
+ var renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1);
+ gl.framebufferTexture2D(
+ gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,
+ gl.RENDERBUFFER, renderbuffer);
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+ this.hitDetectionFramebuffer_ = framebuffer;
+ this.hitDetectionTexture_ = texture;
+ this.hitDetectionRenderbuffer_ = renderbuffer;
+};
+
+
+/**
+ * Use a program. If the program is already in use, this will return `false`.
+ * @param {WebGLProgram} program Program.
+ * @return {boolean} Changed.
+ * @api
+ */
+ol.webgl.Context.prototype.useProgram = function(program) {
+ if (program == this.currentProgram_) {
+ return false;
+ } else {
+ var gl = this.getGL();
+ gl.useProgram(program);
+ this.currentProgram_ = program;
+ return true;
+ }
+};
+
+
+/**
+ * @param {WebGLRenderingContext} gl WebGL rendering context.
+ * @param {number=} opt_wrapS wrapS.
+ * @param {number=} opt_wrapT wrapT.
+ * @return {WebGLTexture} The texture.
+ * @private
+ */
+ol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) {
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+
+ if (opt_wrapS !== undefined) {
+ gl.texParameteri(
+ goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S, opt_wrapS);
+ }
+ if (opt_wrapT !== undefined) {
+ gl.texParameteri(
+ goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T, opt_wrapT);
+ }
+
+ return texture;
+};
+
+
+/**
+ * @param {WebGLRenderingContext} gl WebGL rendering context.
+ * @param {number} width Width.
+ * @param {number} height Height.
+ * @param {number=} opt_wrapS wrapS.
+ * @param {number=} opt_wrapT wrapT.
+ * @return {WebGLTexture} The texture.
+ */
+ol.webgl.Context.createEmptyTexture = function(
+ gl, width, height, opt_wrapS, opt_wrapT) {
+ var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);
+ gl.texImage2D(
+ gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ null);
+
+ return texture;
+};
+
+
+/**
+ * @param {WebGLRenderingContext} gl WebGL rendering context.
+ * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image.
+ * @param {number=} opt_wrapS wrapS.
+ * @param {number=} opt_wrapT wrapT.
+ * @return {WebGLTexture} The texture.
+ */
+ol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) {
+ var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);
+ gl.texImage2D(
+ gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+
+ return texture;
+};
+
+goog.provide('ol.render.webgl.ImageReplay');
+goog.provide('ol.render.webgl.ReplayGroup');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.render.IReplayGroup');
+goog.require('ol.render.VectorContext');
+goog.require('ol.render.webgl.imagereplay.shader.Default');
+goog.require('ol.render.webgl.imagereplay.shader.Default.Locations');
+goog.require('ol.render.webgl.imagereplay.shader.DefaultFragment');
+goog.require('ol.render.webgl.imagereplay.shader.DefaultVertex');
+goog.require('ol.vec.Mat4');
+goog.require('ol.webgl.Buffer');
+goog.require('ol.webgl.Context');
+
+
+/**
+ * @constructor
+ * @extends {ol.render.VectorContext}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Max extent.
+ * @protected
+ * @struct
+ */
+ol.render.webgl.ImageReplay = function(tolerance, maxExtent) {
+ ol.render.VectorContext.call(this);
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.anchorX_ = undefined;
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.anchorY_ = undefined;
+
+ /**
+ * The origin of the coordinate system for the point coordinates sent to
+ * the GPU. To eliminate jitter caused by precision problems in the GPU
+ * we use the "Rendering Relative to Eye" technique described in the "3D
+ * Engine Design for Virtual Globes" book.
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.origin_ = ol.extent.getCenter(maxExtent);
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.groupIndices_ = [];
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.hitDetectionGroupIndices_ = [];
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.height_ = undefined;
+
+ /**
+ * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}
+ * @private
+ */
+ this.images_ = [];
+
+ /**
+ * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}
+ * @private
+ */
+ this.hitDetectionImages_ = [];
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.imageHeight_ = undefined;
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.imageWidth_ = undefined;
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.indices_ = [];
+
+ /**
+ * @type {ol.webgl.Buffer}
+ * @private
+ */
+ this.indicesBuffer_ = null;
+
+ /**
+ * @private
+ * @type {ol.render.webgl.imagereplay.shader.Default.Locations}
+ */
+ this.defaultLocations_ = null;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.opacity_ = undefined;
+
+ /**
+ * @type {!goog.vec.Mat4.Number}
+ * @private
+ */
+ this.offsetRotateMatrix_ = goog.vec.Mat4.createNumberIdentity();
+
+ /**
+ * @type {!goog.vec.Mat4.Number}
+ * @private
+ */
+ this.offsetScaleMatrix_ = goog.vec.Mat4.createNumberIdentity();
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.originX_ = undefined;
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.originY_ = undefined;
+
+ /**
+ * @type {!goog.vec.Mat4.Number}
+ * @private
+ */
+ this.projectionMatrix_ = goog.vec.Mat4.createNumberIdentity();
+
+ /**
+ * @private
+ * @type {boolean|undefined}
+ */
+ this.rotateWithView_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.rotation_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.scale_ = undefined;
+
+ /**
+ * @type {Array.<WebGLTexture>}
+ * @private
+ */
+ this.textures_ = [];
+
+ /**
+ * @type {Array.<WebGLTexture>}
+ * @private
+ */
+ this.hitDetectionTextures_ = [];
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.vertices_ = [];
+
+ /**
+ * @type {ol.webgl.Buffer}
+ * @private
+ */
+ this.verticesBuffer_ = null;
+
+ /**
+ * Start index per feature (the index).
+ * @type {Array.<number>}
+ * @private
+ */
+ this.startIndices_ = [];
+
+ /**
+ * Start index per feature (the feature).
+ * @type {Array.<ol.Feature|ol.render.Feature>}
+ * @private
+ */
+ this.startIndicesFeature_ = [];
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.width_ = undefined;
+};
+ol.inherits(ol.render.webgl.ImageReplay, ol.render.VectorContext);
+
+
+/**
+ * @param {ol.webgl.Context} context WebGL context.
+ * @return {function()} Delete resources function.
+ */
+ol.render.webgl.ImageReplay.prototype.getDeleteResourcesFunction = function(context) {
+ // We only delete our stuff here. The shaders and the program may
+ // be used by other ImageReplay instances (for other layers). And
+ // they will be deleted when disposing of the ol.webgl.Context
+ // object.
+ goog.asserts.assert(this.verticesBuffer_,
+ 'verticesBuffer must not be null');
+ goog.asserts.assert(this.indicesBuffer_,
+ 'indicesBuffer must not be null');
+ var verticesBuffer = this.verticesBuffer_;
+ var indicesBuffer = this.indicesBuffer_;
+ var textures = this.textures_;
+ var hitDetectionTextures = this.hitDetectionTextures_;
+ var gl = context.getGL();
+ return function() {
+ if (!gl.isContextLost()) {
+ var i, ii;
+ for (i = 0, ii = textures.length; i < ii; ++i) {
+ gl.deleteTexture(textures[i]);
+ }
+ for (i = 0, ii = hitDetectionTextures.length; i < ii; ++i) {
+ gl.deleteTexture(hitDetectionTextures[i]);
+ }
+ }
+ context.deleteBuffer(verticesBuffer);
+ context.deleteBuffer(indicesBuffer);
+ };
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @return {number} My end.
+ * @private
+ */
+ol.render.webgl.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {
+ goog.asserts.assert(this.anchorX_ !== undefined, 'anchorX is defined');
+ goog.asserts.assert(this.anchorY_ !== undefined, 'anchorY is defined');
+ goog.asserts.assert(this.height_ !== undefined, 'height is defined');
+ goog.asserts.assert(this.imageHeight_ !== undefined,
+ 'imageHeight is defined');
+ goog.asserts.assert(this.imageWidth_ !== undefined, 'imageWidth is defined');
+ goog.asserts.assert(this.opacity_ !== undefined, 'opacity is defined');
+ goog.asserts.assert(this.originX_ !== undefined, 'originX is defined');
+ goog.asserts.assert(this.originY_ !== undefined, 'originY is defined');
+ goog.asserts.assert(this.rotateWithView_ !== undefined,
+ 'rotateWithView is defined');
+ goog.asserts.assert(this.rotation_ !== undefined, 'rotation is defined');
+ goog.asserts.assert(this.scale_ !== undefined, 'scale is defined');
+ goog.asserts.assert(this.width_ !== undefined, 'width is defined');
+ var anchorX = this.anchorX_;
+ var anchorY = this.anchorY_;
+ var height = this.height_;
+ var imageHeight = this.imageHeight_;
+ var imageWidth = this.imageWidth_;
+ var opacity = this.opacity_;
+ var originX = this.originX_;
+ var originY = this.originY_;
+ var rotateWithView = this.rotateWithView_ ? 1.0 : 0.0;
+ var rotation = this.rotation_;
+ var scale = this.scale_;
+ var width = this.width_;
+ var cos = Math.cos(rotation);
+ var sin = Math.sin(rotation);
+ var numIndices = this.indices_.length;
+ var numVertices = this.vertices_.length;
+ var i, n, offsetX, offsetY, x, y;
+ for (i = offset; i < end; i += stride) {
+ x = flatCoordinates[i] - this.origin_[0];
+ y = flatCoordinates[i + 1] - this.origin_[1];
+
+ // There are 4 vertices per [x, y] point, one for each corner of the
+ // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if
+ // WebGL supported Geometry Shaders (which can emit new vertices), but that
+ // is not currently the case.
+ //
+ // And each vertex includes 8 values: the x and y coordinates, the x and
+ // y offsets used to calculate the position of the corner, the u and
+ // v texture coordinates for the corner, the opacity, and whether the
+ // the image should be rotated with the view (rotateWithView).
+
+ n = numVertices / 8;
+
+ // bottom-left corner
+ offsetX = -scale * anchorX;
+ offsetY = -scale * (height - anchorY);
+ this.vertices_[numVertices++] = x;
+ this.vertices_[numVertices++] = y;
+ this.vertices_[numVertices++] = offsetX * cos - offsetY * sin;
+ this.vertices_[numVertices++] = offsetX * sin + offsetY * cos;
+ this.vertices_[numVertices++] = originX / imageWidth;
+ this.vertices_[numVertices++] = (originY + height) / imageHeight;
+ this.vertices_[numVertices++] = opacity;
+ this.vertices_[numVertices++] = rotateWithView;
+
+ // bottom-right corner
+ offsetX = scale * (width - anchorX);
+ offsetY = -scale * (height - anchorY);
+ this.vertices_[numVertices++] = x;
+ this.vertices_[numVertices++] = y;
+ this.vertices_[numVertices++] = offsetX * cos - offsetY * sin;
+ this.vertices_[numVertices++] = offsetX * sin + offsetY * cos;
+ this.vertices_[numVertices++] = (originX + width) / imageWidth;
+ this.vertices_[numVertices++] = (originY + height) / imageHeight;
+ this.vertices_[numVertices++] = opacity;
+ this.vertices_[numVertices++] = rotateWithView;
+
+ // top-right corner
+ offsetX = scale * (width - anchorX);
+ offsetY = scale * anchorY;
+ this.vertices_[numVertices++] = x;
+ this.vertices_[numVertices++] = y;
+ this.vertices_[numVertices++] = offsetX * cos - offsetY * sin;
+ this.vertices_[numVertices++] = offsetX * sin + offsetY * cos;
+ this.vertices_[numVertices++] = (originX + width) / imageWidth;
+ this.vertices_[numVertices++] = originY / imageHeight;
+ this.vertices_[numVertices++] = opacity;
+ this.vertices_[numVertices++] = rotateWithView;
+
+ // top-left corner
+ offsetX = -scale * anchorX;
+ offsetY = scale * anchorY;
+ this.vertices_[numVertices++] = x;
+ this.vertices_[numVertices++] = y;
+ this.vertices_[numVertices++] = offsetX * cos - offsetY * sin;
+ this.vertices_[numVertices++] = offsetX * sin + offsetY * cos;
+ this.vertices_[numVertices++] = originX / imageWidth;
+ this.vertices_[numVertices++] = originY / imageHeight;
+ this.vertices_[numVertices++] = opacity;
+ this.vertices_[numVertices++] = rotateWithView;
+
+ this.indices_[numIndices++] = n;
+ this.indices_[numIndices++] = n + 1;
+ this.indices_[numIndices++] = n + 2;
+ this.indices_[numIndices++] = n;
+ this.indices_[numIndices++] = n + 2;
+ this.indices_[numIndices++] = n + 3;
+ }
+
+ return numVertices;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) {
+ this.startIndices_.push(this.indices_.length);
+ this.startIndicesFeature_.push(feature);
+ var flatCoordinates = multiPointGeometry.getFlatCoordinates();
+ var stride = multiPointGeometry.getStride();
+ this.drawCoordinates_(
+ flatCoordinates, 0, flatCoordinates.length, stride);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) {
+ this.startIndices_.push(this.indices_.length);
+ this.startIndicesFeature_.push(feature);
+ var flatCoordinates = pointGeometry.getFlatCoordinates();
+ var stride = pointGeometry.getStride();
+ this.drawCoordinates_(
+ flatCoordinates, 0, flatCoordinates.length, stride);
+};
+
+
+/**
+ * @param {ol.webgl.Context} context Context.
+ */
+ol.render.webgl.ImageReplay.prototype.finish = function(context) {
+ var gl = context.getGL();
+
+ this.groupIndices_.push(this.indices_.length);
+ goog.asserts.assert(this.images_.length === this.groupIndices_.length,
+ 'number of images and groupIndices match');
+ this.hitDetectionGroupIndices_.push(this.indices_.length);
+ goog.asserts.assert(this.hitDetectionImages_.length ===
+ this.hitDetectionGroupIndices_.length,
+ 'number of hitDetectionImages and hitDetectionGroupIndices match');
+
+ // create, bind, and populate the vertices buffer
+ this.verticesBuffer_ = new ol.webgl.Buffer(this.vertices_);
+ context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_);
+
+ var indices = this.indices_;
+ var bits = context.hasOESElementIndexUint ? 32 : 16;
+ goog.asserts.assert(indices[indices.length - 1] < Math.pow(2, bits),
+ 'Too large element index detected [%s] (OES_element_index_uint "%s")',
+ indices[indices.length - 1], context.hasOESElementIndexUint);
+
+ // create, bind, and populate the indices buffer
+ this.indicesBuffer_ = new ol.webgl.Buffer(indices);
+ context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
+
+ // create textures
+ /** @type {Object.<string, WebGLTexture>} */
+ var texturePerImage = {};
+
+ this.createTextures_(this.textures_, this.images_, texturePerImage, gl);
+ goog.asserts.assert(this.textures_.length === this.groupIndices_.length,
+ 'number of textures and groupIndices match');
+
+ this.createTextures_(this.hitDetectionTextures_, this.hitDetectionImages_,
+ texturePerImage, gl);
+ goog.asserts.assert(this.hitDetectionTextures_.length ===
+ this.hitDetectionGroupIndices_.length,
+ 'number of hitDetectionTextures and hitDetectionGroupIndices match');
+
+ this.anchorX_ = undefined;
+ this.anchorY_ = undefined;
+ this.height_ = undefined;
+ this.images_ = null;
+ this.hitDetectionImages_ = null;
+ this.imageHeight_ = undefined;
+ this.imageWidth_ = undefined;
+ this.indices_ = null;
+ this.opacity_ = undefined;
+ this.originX_ = undefined;
+ this.originY_ = undefined;
+ this.rotateWithView_ = undefined;
+ this.rotation_ = undefined;
+ this.scale_ = undefined;
+ this.vertices_ = null;
+ this.width_ = undefined;
+};
+
+
+/**
+ * @private
+ * @param {Array.<WebGLTexture>} textures Textures.
+ * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images
+ * Images.
+ * @param {Object.<string, WebGLTexture>} texturePerImage Texture cache.
+ * @param {WebGLRenderingContext} gl Gl.
+ */
+ol.render.webgl.ImageReplay.prototype.createTextures_ = function(textures, images, texturePerImage, gl) {
+ goog.asserts.assert(textures.length === 0,
+ 'upon creation, textures is empty');
+
+ var texture, image, uid, i;
+ var ii = images.length;
+ for (i = 0; i < ii; ++i) {
+ image = images[i];
+
+ uid = goog.getUid(image).toString();
+ if (uid in texturePerImage) {
+ texture = texturePerImage[uid];
+ } else {
+ texture = ol.webgl.Context.createTexture(
+ gl, image, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE);
+ texturePerImage[uid] = texture;
+ }
+ textures[i] = texture;
+ }
+};
+
+
+/**
+ * @param {ol.webgl.Context} context Context.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} opacity Global opacity.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
+ * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
+ * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
+ * this extent are checked.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.webgl.ImageReplay.prototype.replay = function(context,
+ center, resolution, rotation, size, pixelRatio,
+ opacity, skippedFeaturesHash,
+ featureCallback, oneByOne, opt_hitExtent) {
+ var gl = context.getGL();
+
+ // bind the vertices buffer
+ goog.asserts.assert(this.verticesBuffer_,
+ 'verticesBuffer must not be null');
+ context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_);
+
+ // bind the indices buffer
+ goog.asserts.assert(this.indicesBuffer_,
+ 'indecesBuffer must not be null');
+ context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_);
+
+ // get the program
+ var fragmentShader =
+ ol.render.webgl.imagereplay.shader.DefaultFragment.getInstance();
+ var vertexShader =
+ ol.render.webgl.imagereplay.shader.DefaultVertex.getInstance();
+ var program = context.getProgram(fragmentShader, vertexShader);
+
+ // get the locations
+ var locations;
+ if (!this.defaultLocations_) {
+ locations =
+ new ol.render.webgl.imagereplay.shader.Default.Locations(gl, program);
+ this.defaultLocations_ = locations;
+ } else {
+ locations = this.defaultLocations_;
+ }
+
+ // use the program (FIXME: use the return value)
+ context.useProgram(program);
+
+ // enable the vertex attrib arrays
+ gl.enableVertexAttribArray(locations.a_position);
+ gl.vertexAttribPointer(locations.a_position, 2, goog.webgl.FLOAT,
+ false, 32, 0);
+
+ gl.enableVertexAttribArray(locations.a_offsets);
+ gl.vertexAttribPointer(locations.a_offsets, 2, goog.webgl.FLOAT,
+ false, 32, 8);
+
+ gl.enableVertexAttribArray(locations.a_texCoord);
+ gl.vertexAttribPointer(locations.a_texCoord, 2, goog.webgl.FLOAT,
+ false, 32, 16);
+
+ gl.enableVertexAttribArray(locations.a_opacity);
+ gl.vertexAttribPointer(locations.a_opacity, 1, goog.webgl.FLOAT,
+ false, 32, 24);
+
+ gl.enableVertexAttribArray(locations.a_rotateWithView);
+ gl.vertexAttribPointer(locations.a_rotateWithView, 1, goog.webgl.FLOAT,
+ false, 32, 28);
+
+ // set the "uniform" values
+ var projectionMatrix = this.projectionMatrix_;
+ ol.vec.Mat4.makeTransform2D(projectionMatrix,
+ 0.0, 0.0,
+ 2 / (resolution * size[0]),
+ 2 / (resolution * size[1]),
+ -rotation,
+ -(center[0] - this.origin_[0]), -(center[1] - this.origin_[1]));
+
+ var offsetScaleMatrix = this.offsetScaleMatrix_;
+ goog.vec.Mat4.makeScale(offsetScaleMatrix, 2 / size[0], 2 / size[1], 1);
+
+ var offsetRotateMatrix = this.offsetRotateMatrix_;
+ goog.vec.Mat4.makeIdentity(offsetRotateMatrix);
+ if (rotation !== 0) {
+ goog.vec.Mat4.rotateZ(offsetRotateMatrix, -rotation);
+ }
+
+ gl.uniformMatrix4fv(locations.u_projectionMatrix, false, projectionMatrix);
+ gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false, offsetScaleMatrix);
+ gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false,
+ offsetRotateMatrix);
+ gl.uniform1f(locations.u_opacity, opacity);
+
+ // draw!
+ var result;
+ if (featureCallback === undefined) {
+ this.drawReplay_(gl, context, skippedFeaturesHash,
+ this.textures_, this.groupIndices_);
+ } else {
+ // draw feature by feature for the hit-detection
+ result = this.drawHitDetectionReplay_(gl, context, skippedFeaturesHash,
+ featureCallback, oneByOne, opt_hitExtent);
+ }
+
+ // disable the vertex attrib arrays
+ gl.disableVertexAttribArray(locations.a_position);
+ gl.disableVertexAttribArray(locations.a_offsets);
+ gl.disableVertexAttribArray(locations.a_texCoord);
+ gl.disableVertexAttribArray(locations.a_opacity);
+ gl.disableVertexAttribArray(locations.a_rotateWithView);
+
+ return result;
+};
+
+
+/**
+ * @private
+ * @param {WebGLRenderingContext} gl gl.
+ * @param {ol.webgl.Context} context Context.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {Array.<WebGLTexture>} textures Textures.
+ * @param {Array.<number>} groupIndices Texture group indices.
+ */
+ol.render.webgl.ImageReplay.prototype.drawReplay_ = function(gl, context, skippedFeaturesHash, textures, groupIndices) {
+ goog.asserts.assert(textures.length === groupIndices.length,
+ 'number of textures and groupIndeces match');
+ var elementType = context.hasOESElementIndexUint ?
+ goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT;
+ var elementSize = context.hasOESElementIndexUint ? 4 : 2;
+
+ if (!ol.object.isEmpty(skippedFeaturesHash)) {
+ this.drawReplaySkipping_(
+ gl, skippedFeaturesHash, textures, groupIndices,
+ elementType, elementSize);
+ } else {
+ var i, ii, start;
+ for (i = 0, ii = textures.length, start = 0; i < ii; ++i) {
+ gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]);
+ var end = groupIndices[i];
+ this.drawElements_(gl, start, end, elementType, elementSize);
+ start = end;
+ }
+ }
+};
+
+
+/**
+ * Draw the replay while paying attention to skipped features.
+ *
+ * This functions creates groups of features that can be drawn to together,
+ * so that the number of `drawElements` calls is minimized.
+ *
+ * For example given the following texture groups:
+ *
+ * Group 1: A B C
+ * Group 2: D [E] F G
+ *
+ * If feature E should be skipped, the following `drawElements` calls will be
+ * made:
+ *
+ * drawElements with feature A, B and C
+ * drawElements with feature D
+ * drawElements with feature F and G
+ *
+ * @private
+ * @param {WebGLRenderingContext} gl gl.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {Array.<WebGLTexture>} textures Textures.
+ * @param {Array.<number>} groupIndices Texture group indices.
+ * @param {number} elementType Element type.
+ * @param {number} elementSize Element Size.
+ */
+ol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ = function(gl, skippedFeaturesHash, textures, groupIndices,
+ elementType, elementSize) {
+ var featureIndex = 0;
+
+ var i, ii;
+ for (i = 0, ii = textures.length; i < ii; ++i) {
+ gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]);
+ var groupStart = (i > 0) ? groupIndices[i - 1] : 0;
+ var groupEnd = groupIndices[i];
+
+ var start = groupStart;
+ var end = groupStart;
+ while (featureIndex < this.startIndices_.length &&
+ this.startIndices_[featureIndex] <= groupEnd) {
+ var feature = this.startIndicesFeature_[featureIndex];
+
+ var featureUid = goog.getUid(feature).toString();
+ if (skippedFeaturesHash[featureUid] !== undefined) {
+ // feature should be skipped
+ if (start !== end) {
+ // draw the features so far
+ this.drawElements_(gl, start, end, elementType, elementSize);
+ }
+ // continue with the next feature
+ start = (featureIndex === this.startIndices_.length - 1) ?
+ groupEnd : this.startIndices_[featureIndex + 1];
+ end = start;
+ } else {
+ // the feature is not skipped, augment the end index
+ end = (featureIndex === this.startIndices_.length - 1) ?
+ groupEnd : this.startIndices_[featureIndex + 1];
+ }
+ featureIndex++;
+ }
+
+ if (start !== end) {
+ // draw the remaining features (in case there was no skipped feature
+ // in this texture group, all features of a group are drawn together)
+ this.drawElements_(gl, start, end, elementType, elementSize);
+ }
+ }
+};
+
+
+/**
+ * @private
+ * @param {WebGLRenderingContext} gl gl.
+ * @param {number} start Start index.
+ * @param {number} end End index.
+ * @param {number} elementType Element type.
+ * @param {number} elementSize Element Size.
+ */
+ol.render.webgl.ImageReplay.prototype.drawElements_ = function(
+ gl, start, end, elementType, elementSize) {
+ var numItems = end - start;
+ var offsetInBytes = start * elementSize;
+ gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
+};
+
+
+/**
+ * @private
+ * @param {WebGLRenderingContext} gl gl.
+ * @param {ol.webgl.Context} context Context.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
+ * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
+ * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
+ * this extent are checked.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplay_ = function(gl, context, skippedFeaturesHash, featureCallback, oneByOne,
+ opt_hitExtent) {
+ if (!oneByOne) {
+ // draw all hit-detection features in "once" (by texture group)
+ return this.drawHitDetectionReplayAll_(gl, context,
+ skippedFeaturesHash, featureCallback);
+ } else {
+ // draw hit-detection features one by one
+ return this.drawHitDetectionReplayOneByOne_(gl, context,
+ skippedFeaturesHash, featureCallback, opt_hitExtent);
+ }
+};
+
+
+/**
+ * @private
+ * @param {WebGLRenderingContext} gl gl.
+ * @param {ol.webgl.Context} context Context.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayAll_ = function(gl, context, skippedFeaturesHash, featureCallback) {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ this.drawReplay_(gl, context, skippedFeaturesHash,
+ this.hitDetectionTextures_, this.hitDetectionGroupIndices_);
+
+ var result = featureCallback(null);
+ if (result) {
+ return result;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @private
+ * @param {WebGLRenderingContext} gl gl.
+ * @param {ol.webgl.Context} context Context.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
+ * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
+ * this extent are checked.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne_ = function(gl, context, skippedFeaturesHash, featureCallback,
+ opt_hitExtent) {
+ goog.asserts.assert(this.hitDetectionTextures_.length ===
+ this.hitDetectionGroupIndices_.length,
+ 'number of hitDetectionTextures and hitDetectionGroupIndices match');
+ var elementType = context.hasOESElementIndexUint ?
+ goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT;
+ var elementSize = context.hasOESElementIndexUint ? 4 : 2;
+
+ var i, groupStart, start, end, feature, featureUid;
+ var featureIndex = this.startIndices_.length - 1;
+ for (i = this.hitDetectionTextures_.length - 1; i >= 0; --i) {
+ gl.bindTexture(goog.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]);
+ groupStart = (i > 0) ? this.hitDetectionGroupIndices_[i - 1] : 0;
+ end = this.hitDetectionGroupIndices_[i];
+
+ // draw all features for this texture group
+ while (featureIndex >= 0 &&
+ this.startIndices_[featureIndex] >= groupStart) {
+ start = this.startIndices_[featureIndex];
+ feature = this.startIndicesFeature_[featureIndex];
+ featureUid = goog.getUid(feature).toString();
+
+ if (skippedFeaturesHash[featureUid] === undefined &&
+ feature.getGeometry() &&
+ (opt_hitExtent === undefined || ol.extent.intersects(
+ /** @type {Array<number>} */ (opt_hitExtent),
+ feature.getGeometry().getExtent()))) {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ this.drawElements_(gl, start, end, elementType, elementSize);
+
+ var result = featureCallback(feature);
+ if (result) {
+ return result;
+ }
+ }
+
+ end = start;
+ featureIndex--;
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.ImageReplay.prototype.setFillStrokeStyle = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) {
+ var anchor = imageStyle.getAnchor();
+ var image = imageStyle.getImage(1);
+ var imageSize = imageStyle.getImageSize();
+ var hitDetectionImage = imageStyle.getHitDetectionImage(1);
+ var hitDetectionImageSize = imageStyle.getHitDetectionImageSize();
+ var opacity = imageStyle.getOpacity();
+ var origin = imageStyle.getOrigin();
+ var rotateWithView = imageStyle.getRotateWithView();
+ var rotation = imageStyle.getRotation();
+ var size = imageStyle.getSize();
+ var scale = imageStyle.getScale();
+ goog.asserts.assert(anchor, 'imageStyle anchor is not null');
+ goog.asserts.assert(image, 'imageStyle image is not null');
+ goog.asserts.assert(imageSize,
+ 'imageStyle imageSize is not null');
+ goog.asserts.assert(hitDetectionImage,
+ 'imageStyle hitDetectionImage is not null');
+ goog.asserts.assert(hitDetectionImageSize,
+ 'imageStyle hitDetectionImageSize is not null');
+ goog.asserts.assert(opacity !== undefined, 'imageStyle opacity is defined');
+ goog.asserts.assert(origin, 'imageStyle origin is not null');
+ goog.asserts.assert(rotateWithView !== undefined,
+ 'imageStyle rotateWithView is defined');
+ goog.asserts.assert(rotation !== undefined, 'imageStyle rotation is defined');
+ goog.asserts.assert(size, 'imageStyle size is not null');
+ goog.asserts.assert(scale !== undefined, 'imageStyle scale is defined');
+
+ var currentImage;
+ if (this.images_.length === 0) {
+ this.images_.push(image);
+ } else {
+ currentImage = this.images_[this.images_.length - 1];
+ if (goog.getUid(currentImage) != goog.getUid(image)) {
+ this.groupIndices_.push(this.indices_.length);
+ goog.asserts.assert(this.groupIndices_.length === this.images_.length,
+ 'number of groupIndices and images match');
+ this.images_.push(image);
+ }
+ }
+
+ if (this.hitDetectionImages_.length === 0) {
+ this.hitDetectionImages_.push(hitDetectionImage);
+ } else {
+ currentImage =
+ this.hitDetectionImages_[this.hitDetectionImages_.length - 1];
+ if (goog.getUid(currentImage) != goog.getUid(hitDetectionImage)) {
+ this.hitDetectionGroupIndices_.push(this.indices_.length);
+ goog.asserts.assert(this.hitDetectionGroupIndices_.length ===
+ this.hitDetectionImages_.length,
+ 'number of hitDetectionGroupIndices and hitDetectionImages match');
+ this.hitDetectionImages_.push(hitDetectionImage);
+ }
+ }
+
+ this.anchorX_ = anchor[0];
+ this.anchorY_ = anchor[1];
+ this.height_ = size[1];
+ this.imageHeight_ = imageSize[1];
+ this.imageWidth_ = imageSize[0];
+ this.opacity_ = opacity;
+ this.originX_ = origin[0];
+ this.originY_ = origin[1];
+ this.rotation_ = rotation;
+ this.rotateWithView_ = rotateWithView;
+ this.scale_ = scale;
+ this.width_ = size[0];
+};
+
+
+/**
+ * @constructor
+ * @implements {ol.render.IReplayGroup}
+ * @param {number} tolerance Tolerance.
+ * @param {ol.Extent} maxExtent Max extent.
+ * @param {number=} opt_renderBuffer Render buffer.
+ * @struct
+ */
+ol.render.webgl.ReplayGroup = function(
+ tolerance, maxExtent, opt_renderBuffer) {
+
+ /**
+ * @type {ol.Extent}
+ * @private
+ */
+ this.maxExtent_ = maxExtent;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.tolerance_ = tolerance;
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.renderBuffer_ = opt_renderBuffer;
+
+ /**
+ * ImageReplay only is supported at this point.
+ * @type {Object.<ol.render.ReplayType, ol.render.webgl.ImageReplay>}
+ * @private
+ */
+ this.replays_ = {};
+
+};
+
+
+/**
+ * @param {ol.webgl.Context} context WebGL context.
+ * @return {function()} Delete resources function.
+ */
+ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = function(context) {
+ var functions = [];
+ var replayKey;
+ for (replayKey in this.replays_) {
+ functions.push(
+ this.replays_[replayKey].getDeleteResourcesFunction(context));
+ }
+ return function() {
+ var length = functions.length;
+ var result;
+ for (var i = 0; i < length; i++) {
+ result = functions[i].apply(this, arguments);
+ }
+ return result;
+ };
+};
+
+
+/**
+ * @param {ol.webgl.Context} context Context.
+ */
+ol.render.webgl.ReplayGroup.prototype.finish = function(context) {
+ var replayKey;
+ for (replayKey in this.replays_) {
+ this.replays_[replayKey].finish(context);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
+ var replay = this.replays_[replayType];
+ if (replay === undefined) {
+ var constructor = ol.render.webgl.BATCH_CONSTRUCTORS_[replayType];
+ goog.asserts.assert(constructor !== undefined,
+ replayType +
+ ' constructor missing from ol.render.webgl.BATCH_CONSTRUCTORS_');
+ replay = new constructor(this.tolerance_, this.maxExtent_);
+ this.replays_[replayType] = replay;
+ }
+ return replay;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.ReplayGroup.prototype.isEmpty = function() {
+ return ol.object.isEmpty(this.replays_);
+};
+
+
+/**
+ * @param {ol.webgl.Context} context Context.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} opacity Global opacity.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ */
+ol.render.webgl.ReplayGroup.prototype.replay = function(context,
+ center, resolution, rotation, size, pixelRatio,
+ opacity, skippedFeaturesHash) {
+ var i, ii, replay;
+ for (i = 0, ii = ol.render.REPLAY_ORDER.length; i < ii; ++i) {
+ replay = this.replays_[ol.render.REPLAY_ORDER[i]];
+ if (replay !== undefined) {
+ replay.replay(context,
+ center, resolution, rotation, size, pixelRatio,
+ opacity, skippedFeaturesHash,
+ undefined, false);
+ }
+ }
+};
+
+
+/**
+ * @private
+ * @param {ol.webgl.Context} context Context.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} opacity Global opacity.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
+ * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
+ * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
+ * this extent are checked.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context,
+ center, resolution, rotation, size, pixelRatio, opacity,
+ skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) {
+ var i, replay, result;
+ for (i = ol.render.REPLAY_ORDER.length - 1; i >= 0; --i) {
+ replay = this.replays_[ol.render.REPLAY_ORDER[i]];
+ if (replay !== undefined) {
+ result = replay.replay(context,
+ center, resolution, rotation, size, pixelRatio, opacity,
+ skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.webgl.Context} context Context.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} opacity Global opacity.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} callback Feature callback.
+ * @return {T|undefined} Callback result.
+ * @template T
+ */
+ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
+ coordinate, context, center, resolution, rotation, size, pixelRatio,
+ opacity, skippedFeaturesHash,
+ callback) {
+ var gl = context.getGL();
+ gl.bindFramebuffer(
+ gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
+
+
+ /**
+ * @type {ol.Extent}
+ */
+ var hitExtent;
+ if (this.renderBuffer_ !== undefined) {
+ // build an extent around the coordinate, so that only features that
+ // intersect this extent are checked
+ hitExtent = ol.extent.buffer(
+ ol.extent.createOrUpdateFromCoordinate(coordinate),
+ resolution * this.renderBuffer_);
+ }
+
+ return this.replayHitDetection_(context,
+ coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_,
+ pixelRatio, opacity, skippedFeaturesHash,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ var imageData = new Uint8Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
+
+ if (imageData[3] > 0) {
+ var result = callback(feature);
+ if (result) {
+ return result;
+ }
+ }
+ }, true, hitExtent);
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {ol.webgl.Context} context Context.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} opacity Global opacity.
+ * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
+ * to skip.
+ * @return {boolean} Is there a feature at the given coordinate?
+ */
+ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function(
+ coordinate, context, center, resolution, rotation, size, pixelRatio,
+ opacity, skippedFeaturesHash) {
+ var gl = context.getGL();
+ gl.bindFramebuffer(
+ gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
+
+ var hasFeature = this.replayHitDetection_(context,
+ coordinate, resolution, rotation, ol.render.webgl.HIT_DETECTION_SIZE_,
+ pixelRatio, opacity, skippedFeaturesHash,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {boolean} Is there a feature?
+ */
+ function(feature) {
+ var imageData = new Uint8Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
+ return imageData[3] > 0;
+ }, false);
+
+ return hasFeature !== undefined;
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<ol.render.ReplayType,
+ * function(new: ol.render.webgl.ImageReplay, number,
+ * ol.Extent)>}
+ */
+ol.render.webgl.BATCH_CONSTRUCTORS_ = {
+ 'Image': ol.render.webgl.ImageReplay
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<number>}
+ */
+ol.render.webgl.HIT_DETECTION_SIZE_ = [1, 1];
+
+goog.provide('ol.render.webgl.Immediate');
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.render.VectorContext');
+goog.require('ol.render.webgl.ImageReplay');
+goog.require('ol.render.webgl.ReplayGroup');
+
+
+/**
+ * @constructor
+ * @extends {ol.render.VectorContext}
+ * @param {ol.webgl.Context} context Context.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} rotation Rotation.
+ * @param {ol.Size} size Size.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} pixelRatio Pixel ratio.
+ * @struct
+ */
+ol.render.webgl.Immediate = function(context, center, resolution, rotation, size, extent, pixelRatio) {
+ ol.render.VectorContext.call(this);
+
+ /**
+ * @private
+ */
+ this.context_ = context;
+
+ /**
+ * @private
+ */
+ this.center_ = center;
+
+ /**
+ * @private
+ */
+ this.extent_ = extent;
+
+ /**
+ * @private
+ */
+ this.pixelRatio_ = pixelRatio;
+
+ /**
+ * @private
+ */
+ this.size_ = size;
+
+ /**
+ * @private
+ */
+ this.rotation_ = rotation;
+
+ /**
+ * @private
+ */
+ this.resolution_ = resolution;
+
+ /**
+ * @private
+ * @type {ol.style.Image}
+ */
+ this.imageStyle_ = null;
+
+};
+ol.inherits(ol.render.webgl.Immediate, ol.render.VectorContext);
+
+
+/**
+ * Set the rendering style. Note that since this is an immediate rendering API,
+ * any `zIndex` on the provided style will be ignored.
+ *
+ * @param {ol.style.Style} style The rendering style.
+ * @api
+ */
+ol.render.webgl.Immediate.prototype.setStyle = function(style) {
+ this.setImageStyle(style.getImage());
+};
+
+
+/**
+ * Render a geometry into the canvas. Call
+ * {@link ol.render.webgl.Immediate#setStyle} first to set the rendering style.
+ *
+ * @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.
+ * @api
+ */
+ol.render.webgl.Immediate.prototype.drawGeometry = function(geometry) {
+ var type = geometry.getType();
+ switch (type) {
+ case ol.geom.GeometryType.POINT:
+ this.drawPoint(/** @type {ol.geom.Point} */ (geometry), null);
+ break;
+ case ol.geom.GeometryType.MULTI_POINT:
+ this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry), null);
+ break;
+ case ol.geom.GeometryType.GEOMETRY_COLLECTION:
+ this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry), null);
+ break;
+ default:
+ goog.asserts.fail('Unsupported geometry type: ' + type);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) {
+ var geometry = style.getGeometryFunction()(feature);
+ if (!geometry ||
+ !ol.extent.intersects(this.extent_, geometry.getExtent())) {
+ return;
+ }
+ this.setStyle(style);
+ goog.asserts.assert(geometry, 'geometry must be truthy');
+ this.drawGeometry(geometry);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.Immediate.prototype.drawGeometryCollection = function(geometry, data) {
+ var geometries = geometry.getGeometriesArray();
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ this.drawGeometry(geometries[i]);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.Immediate.prototype.drawPoint = function(geometry, data) {
+ var context = this.context_;
+ var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
+ var replay = /** @type {ol.render.webgl.ImageReplay} */ (
+ replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
+ replay.setImageStyle(this.imageStyle_);
+ replay.drawPoint(geometry, data);
+ replay.finish(context);
+ // default colors
+ var opacity = 1;
+ var skippedFeatures = {};
+ var featureCallback;
+ var oneByOne = false;
+ replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
+ this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
+ oneByOne);
+ replay.getDeleteResourcesFunction(context)();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.Immediate.prototype.drawMultiPoint = function(geometry, data) {
+ var context = this.context_;
+ var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
+ var replay = /** @type {ol.render.webgl.ImageReplay} */ (
+ replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
+ replay.setImageStyle(this.imageStyle_);
+ replay.drawMultiPoint(geometry, data);
+ replay.finish(context);
+ var opacity = 1;
+ var skippedFeatures = {};
+ var featureCallback;
+ var oneByOne = false;
+ replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
+ this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
+ oneByOne);
+ replay.getDeleteResourcesFunction(context)();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) {
+ this.imageStyle_ = imageStyle;
+};
+
+// This file is automatically generated, do not edit
+goog.provide('ol.renderer.webgl.map.shader.Default');
+goog.provide('ol.renderer.webgl.map.shader.Default.Locations');
+goog.provide('ol.renderer.webgl.map.shader.DefaultFragment');
+goog.provide('ol.renderer.webgl.map.shader.DefaultVertex');
+
+goog.require('ol.webgl.shader');
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.shader.Fragment}
+ * @struct
+ */
+ol.renderer.webgl.map.shader.DefaultFragment = function() {
+ ol.webgl.shader.Fragment.call(this, ol.renderer.webgl.map.shader.DefaultFragment.SOURCE);
+};
+ol.inherits(ol.renderer.webgl.map.shader.DefaultFragment, ol.webgl.shader.Fragment);
+goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultFragment);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.map.shader.DefaultFragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\n\n\nuniform float u_opacity;\nuniform sampler2D u_texture;\n\nvoid main(void) {\n vec4 texColor = texture2D(u_texture, v_texCoord);\n gl_FragColor.rgb = texColor.rgb;\n gl_FragColor.a = texColor.a * u_opacity;\n}\n';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.map.shader.DefaultFragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform float f;uniform sampler2D g;void main(void){vec4 texColor=texture2D(g,a);gl_FragColor.rgb=texColor.rgb;gl_FragColor.a=texColor.a*f;}';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.map.shader.DefaultFragment.SOURCE = goog.DEBUG ?
+ ol.renderer.webgl.map.shader.DefaultFragment.DEBUG_SOURCE :
+ ol.renderer.webgl.map.shader.DefaultFragment.OPTIMIZED_SOURCE;
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.shader.Vertex}
+ * @struct
+ */
+ol.renderer.webgl.map.shader.DefaultVertex = function() {
+ ol.webgl.shader.Vertex.call(this, ol.renderer.webgl.map.shader.DefaultVertex.SOURCE);
+};
+ol.inherits(ol.renderer.webgl.map.shader.DefaultVertex, ol.webgl.shader.Vertex);
+goog.addSingletonGetter(ol.renderer.webgl.map.shader.DefaultVertex);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.map.shader.DefaultVertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\n\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\n\nuniform mat4 u_texCoordMatrix;\nuniform mat4 u_projectionMatrix;\n\nvoid main(void) {\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.);\n v_texCoord = (u_texCoordMatrix * vec4(a_texCoord, 0., 1.)).st;\n}\n\n\n';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.map.shader.DefaultVertex.OPTIMIZED_SOURCE = 'varying vec2 a;attribute vec2 b;attribute vec2 c;uniform mat4 d;uniform mat4 e;void main(void){gl_Position=e*vec4(b,0.,1.);a=(d*vec4(c,0.,1.)).st;}';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.map.shader.DefaultVertex.SOURCE = goog.DEBUG ?
+ ol.renderer.webgl.map.shader.DefaultVertex.DEBUG_SOURCE :
+ ol.renderer.webgl.map.shader.DefaultVertex.OPTIMIZED_SOURCE;
+
+
+/**
+ * @constructor
+ * @param {WebGLRenderingContext} gl GL.
+ * @param {WebGLProgram} program Program.
+ * @struct
+ */
+ol.renderer.webgl.map.shader.Default.Locations = function(gl, program) {
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_opacity = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_opacity' : 'f');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_projectionMatrix = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_projectionMatrix' : 'e');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_texCoordMatrix = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_texCoordMatrix' : 'd');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_texture = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_texture' : 'g');
+
+ /**
+ * @type {number}
+ */
+ this.a_position = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_position' : 'b');
+
+ /**
+ * @type {number}
+ */
+ this.a_texCoord = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_texCoord' : 'c');
+};
+
+goog.provide('ol.renderer.webgl.Layer');
+
+goog.require('goog.vec.Mat4');
+goog.require('goog.webgl');
+goog.require('ol.layer.Layer');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.webgl.Immediate');
+goog.require('ol.renderer.Layer');
+goog.require('ol.renderer.webgl.map.shader.Default');
+goog.require('ol.renderer.webgl.map.shader.Default.Locations');
+goog.require('ol.renderer.webgl.map.shader.DefaultFragment');
+goog.require('ol.renderer.webgl.map.shader.DefaultVertex');
+goog.require('ol.webgl.Buffer');
+goog.require('ol.webgl.Context');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.Layer}
+ * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
+ * @param {ol.layer.Layer} layer Layer.
+ */
+ol.renderer.webgl.Layer = function(mapRenderer, layer) {
+
+ ol.renderer.Layer.call(this, layer);
+
+ /**
+ * @protected
+ * @type {ol.renderer.webgl.Map}
+ */
+ this.mapRenderer = mapRenderer;
+
+ /**
+ * @private
+ * @type {ol.webgl.Buffer}
+ */
+ this.arrayBuffer_ = new ol.webgl.Buffer([
+ -1, -1, 0, 0,
+ 1, -1, 1, 0,
+ -1, 1, 0, 1,
+ 1, 1, 1, 1
+ ]);
+
+ /**
+ * @protected
+ * @type {WebGLTexture}
+ */
+ this.texture = null;
+
+ /**
+ * @protected
+ * @type {WebGLFramebuffer}
+ */
+ this.framebuffer = null;
+
+ /**
+ * @protected
+ * @type {number|undefined}
+ */
+ this.framebufferDimension = undefined;
+
+ /**
+ * @protected
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.texCoordMatrix = goog.vec.Mat4.createNumber();
+
+ /**
+ * @protected
+ * @type {!goog.vec.Mat4.Number}
+ */
+ this.projectionMatrix = goog.vec.Mat4.createNumberIdentity();
+
+ /**
+ * @private
+ * @type {ol.renderer.webgl.map.shader.Default.Locations}
+ */
+ this.defaultLocations_ = null;
+
+};
+ol.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer);
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {number} framebufferDimension Framebuffer dimension.
+ * @protected
+ */
+ol.renderer.webgl.Layer.prototype.bindFramebuffer = function(frameState, framebufferDimension) {
+
+ var gl = this.mapRenderer.getGL();
+
+ if (this.framebufferDimension === undefined ||
+ this.framebufferDimension != framebufferDimension) {
+ /**
+ * @param {WebGLRenderingContext} gl GL.
+ * @param {WebGLFramebuffer} framebuffer Framebuffer.
+ * @param {WebGLTexture} texture Texture.
+ */
+ var postRenderFunction = function(gl, framebuffer, texture) {
+ if (!gl.isContextLost()) {
+ gl.deleteFramebuffer(framebuffer);
+ gl.deleteTexture(texture);
+ }
+ }.bind(null, gl, this.framebuffer, this.texture);
+
+ frameState.postRenderFunctions.push(
+ /** @type {ol.PostRenderFunction} */ (postRenderFunction)
+ );
+
+ var texture = ol.webgl.Context.createEmptyTexture(
+ gl, framebufferDimension, framebufferDimension);
+
+ var framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, framebuffer);
+ gl.framebufferTexture2D(goog.webgl.FRAMEBUFFER,
+ goog.webgl.COLOR_ATTACHMENT0, goog.webgl.TEXTURE_2D, texture, 0);
+
+ this.texture = texture;
+ this.framebuffer = framebuffer;
+ this.framebufferDimension = framebufferDimension;
+
+ } else {
+ gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, this.framebuffer);
+ }
+
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @param {ol.webgl.Context} context Context.
+ */
+ol.renderer.webgl.Layer.prototype.composeFrame = function(frameState, layerState, context) {
+
+ this.dispatchComposeEvent_(
+ ol.render.EventType.PRECOMPOSE, context, frameState);
+
+ context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.arrayBuffer_);
+
+ var gl = context.getGL();
+
+ var fragmentShader =
+ ol.renderer.webgl.map.shader.DefaultFragment.getInstance();
+ var vertexShader = ol.renderer.webgl.map.shader.DefaultVertex.getInstance();
+
+ var program = context.getProgram(fragmentShader, vertexShader);
+
+ var locations;
+ if (!this.defaultLocations_) {
+ locations =
+ new ol.renderer.webgl.map.shader.Default.Locations(gl, program);
+ this.defaultLocations_ = locations;
+ } else {
+ locations = this.defaultLocations_;
+ }
+
+ if (context.useProgram(program)) {
+ gl.enableVertexAttribArray(locations.a_position);
+ gl.vertexAttribPointer(
+ locations.a_position, 2, goog.webgl.FLOAT, false, 16, 0);
+ gl.enableVertexAttribArray(locations.a_texCoord);
+ gl.vertexAttribPointer(
+ locations.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8);
+ gl.uniform1i(locations.u_texture, 0);
+ }
+
+ gl.uniformMatrix4fv(
+ locations.u_texCoordMatrix, false, this.getTexCoordMatrix());
+ gl.uniformMatrix4fv(locations.u_projectionMatrix, false,
+ this.getProjectionMatrix());
+ gl.uniform1f(locations.u_opacity, layerState.opacity);
+ gl.bindTexture(goog.webgl.TEXTURE_2D, this.getTexture());
+ gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
+
+ this.dispatchComposeEvent_(
+ ol.render.EventType.POSTCOMPOSE, context, frameState);
+
+};
+
+
+/**
+ * @param {ol.render.EventType} type Event type.
+ * @param {ol.webgl.Context} context WebGL context.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState) {
+ var layer = this.getLayer();
+ if (layer.hasListener(type)) {
+ var viewState = frameState.viewState;
+ var resolution = viewState.resolution;
+ var pixelRatio = frameState.pixelRatio;
+ var extent = frameState.extent;
+ var center = viewState.center;
+ var rotation = viewState.rotation;
+ var size = frameState.size;
+
+ var render = new ol.render.webgl.Immediate(
+ context, center, resolution, rotation, size, extent, pixelRatio);
+ var composeEvent = new ol.render.Event(
+ type, layer, render, frameState, null, context);
+ layer.dispatchEvent(composeEvent);
+ }
+};
+
+
+/**
+ * @return {!goog.vec.Mat4.Number} Matrix.
+ */
+ol.renderer.webgl.Layer.prototype.getTexCoordMatrix = function() {
+ return this.texCoordMatrix;
+};
+
+
+/**
+ * @return {WebGLTexture} Texture.
+ */
+ol.renderer.webgl.Layer.prototype.getTexture = function() {
+ return this.texture;
+};
+
+
+/**
+ * @return {!goog.vec.Mat4.Number} Matrix.
+ */
+ol.renderer.webgl.Layer.prototype.getProjectionMatrix = function() {
+ return this.projectionMatrix;
+};
+
+
+/**
+ * Handle webglcontextlost.
+ */
+ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() {
+ this.texture = null;
+ this.framebuffer = null;
+ this.framebufferDimension = undefined;
+};
+
+
+/**
+ * @param {olx.FrameState} frameState Frame state.
+ * @param {ol.LayerState} layerState Layer state.
+ * @param {ol.webgl.Context} context Context.
+ * @return {boolean} whether composeFrame should be called.
+ */
+ol.renderer.webgl.Layer.prototype.prepareFrame = goog.abstractMethod;
+
+goog.provide('ol.renderer.webgl.ImageLayer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('goog.webgl');
+goog.require('ol.ImageBase');
+goog.require('ol.ViewHint');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.functions');
+goog.require('ol.layer.Image');
+goog.require('ol.proj');
+goog.require('ol.renderer.webgl.Layer');
+goog.require('ol.source.ImageVector');
+goog.require('ol.vec.Mat4');
+goog.require('ol.webgl.Context');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.webgl.Layer}
+ * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
+ * @param {ol.layer.Image} imageLayer Tile layer.
+ */
+ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) {
+
+ ol.renderer.webgl.Layer.call(this, mapRenderer, imageLayer);
+
+ /**
+ * The last rendered image.
+ * @private
+ * @type {?ol.ImageBase}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.hitCanvasContext_ = null;
+
+ /**
+ * @private
+ * @type {?goog.vec.Mat4.Number}
+ */
+ this.hitTransformationMatrix_ = null;
+
+};
+ol.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer);
+
+
+/**
+ * @param {ol.ImageBase} image Image.
+ * @private
+ * @return {WebGLTexture} Texture.
+ */
+ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) {
+
+ // We meet the conditions to work with non-power of two textures.
+ // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support
+ // http://learningwebgl.com/blog/?p=2101
+
+ var imageElement = image.getImage();
+ var gl = this.mapRenderer.getGL();
+
+ return ol.webgl.Context.createTexture(
+ gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ var layer = this.getLayer();
+ var source = layer.getSource();
+ var resolution = frameState.viewState.resolution;
+ var rotation = frameState.viewState.rotation;
+ var skippedFeatureUids = frameState.skippedFeatureUids;
+ return source.forEachFeatureAtCoordinate(
+ coordinate, resolution, rotation, skippedFeatureUids,
+
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ return callback.call(thisArg, feature, layer);
+ });
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.ImageLayer.prototype.prepareFrame = function(frameState, layerState, context) {
+
+ var gl = this.mapRenderer.getGL();
+
+ var pixelRatio = frameState.pixelRatio;
+ var viewState = frameState.viewState;
+ var viewCenter = viewState.center;
+ var viewResolution = viewState.resolution;
+ var viewRotation = viewState.rotation;
+
+ var image = this.image_;
+ var texture = this.texture;
+ var imageLayer = this.getLayer();
+ goog.asserts.assertInstanceof(imageLayer, ol.layer.Image,
+ 'layer is an instance of ol.layer.Image');
+ var imageSource = imageLayer.getSource();
+
+ var hints = frameState.viewHints;
+
+ var renderedExtent = frameState.extent;
+ if (layerState.extent !== undefined) {
+ renderedExtent = ol.extent.getIntersection(
+ renderedExtent, layerState.extent);
+ }
+ if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] &&
+ !ol.extent.isEmpty(renderedExtent)) {
+ var projection = viewState.projection;
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ var sourceProjection = imageSource.getProjection();
+ if (sourceProjection) {
+ goog.asserts.assert(ol.proj.equivalent(projection, sourceProjection),
+ 'projection and sourceProjection are equivalent');
+ projection = sourceProjection;
+ }
+ }
+ var image_ = imageSource.getImage(renderedExtent, viewResolution,
+ pixelRatio, projection);
+ if (image_) {
+ var loaded = this.loadImage(image_);
+ if (loaded) {
+ image = image_;
+ texture = this.createTexture_(image_);
+ if (this.texture) {
+ /**
+ * @param {WebGLRenderingContext} gl GL.
+ * @param {WebGLTexture} texture Texture.
+ */
+ var postRenderFunction = function(gl, texture) {
+ if (!gl.isContextLost()) {
+ gl.deleteTexture(texture);
+ }
+ }.bind(null, gl, this.texture);
+ frameState.postRenderFunctions.push(
+ /** @type {ol.PostRenderFunction} */ (postRenderFunction)
+ );
+ }
+ }
+ }
+ }
+
+ if (image) {
+ goog.asserts.assert(texture, 'texture is truthy');
+
+ var canvas = this.mapRenderer.getContext().getCanvas();
+
+ this.updateProjectionMatrix_(canvas.width, canvas.height,
+ pixelRatio, viewCenter, viewResolution, viewRotation,
+ image.getExtent());
+ this.hitTransformationMatrix_ = null;
+
+ // Translate and scale to flip the Y coord.
+ var texCoordMatrix = this.texCoordMatrix;
+ goog.vec.Mat4.makeIdentity(texCoordMatrix);
+ goog.vec.Mat4.scale(texCoordMatrix, 1, -1, 1);
+ goog.vec.Mat4.translate(texCoordMatrix, 0, -1, 0);
+
+ this.image_ = image;
+ this.texture = texture;
+
+ this.updateAttributions(frameState.attributions, image.getAttributions());
+ this.updateLogos(frameState, imageSource);
+ }
+
+ return true;
+};
+
+
+/**
+ * @param {number} canvasWidth Canvas width.
+ * @param {number} canvasHeight Canvas height.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.Coordinate} viewCenter View center.
+ * @param {number} viewResolution View resolution.
+ * @param {number} viewRotation View rotation.
+ * @param {ol.Extent} imageExtent Image extent.
+ * @private
+ */
+ol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = function(canvasWidth, canvasHeight, pixelRatio,
+ viewCenter, viewResolution, viewRotation, imageExtent) {
+
+ var canvasExtentWidth = canvasWidth * viewResolution;
+ var canvasExtentHeight = canvasHeight * viewResolution;
+
+ var projectionMatrix = this.projectionMatrix;
+ goog.vec.Mat4.makeIdentity(projectionMatrix);
+ goog.vec.Mat4.scale(projectionMatrix,
+ pixelRatio * 2 / canvasExtentWidth,
+ pixelRatio * 2 / canvasExtentHeight, 1);
+ goog.vec.Mat4.rotateZ(projectionMatrix, -viewRotation);
+ goog.vec.Mat4.translate(projectionMatrix,
+ imageExtent[0] - viewCenter[0],
+ imageExtent[1] - viewCenter[1],
+ 0);
+ goog.vec.Mat4.scale(projectionMatrix,
+ (imageExtent[2] - imageExtent[0]) / 2,
+ (imageExtent[3] - imageExtent[1]) / 2,
+ 1);
+ goog.vec.Mat4.translate(projectionMatrix, 1, 1, 0);
+
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = function(coordinate, frameState) {
+ var hasFeature = this.forEachFeatureAtCoordinate(
+ coordinate, frameState, ol.functions.TRUE, this);
+ return hasFeature !== undefined;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
+ if (!this.image_ || !this.image_.getImage()) {
+ return undefined;
+ }
+
+ if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
+ // for ImageVector sources use the original hit-detection logic,
+ // so that for example also transparent polygons are detected
+ var coordinate = pixel.slice();
+ ol.vec.Mat4.multVec2(
+ frameState.pixelToCoordinateMatrix, coordinate, coordinate);
+ var hasFeature = this.forEachFeatureAtCoordinate(
+ coordinate, frameState, ol.functions.TRUE, this);
+
+ if (hasFeature) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+ } else {
+ var imageSize =
+ [this.image_.getImage().width, this.image_.getImage().height];
+
+ if (!this.hitTransformationMatrix_) {
+ this.hitTransformationMatrix_ = this.getHitTransformationMatrix_(
+ frameState.size, imageSize);
+ }
+
+ var pixelOnFrameBuffer = [0, 0];
+ ol.vec.Mat4.multVec2(
+ this.hitTransformationMatrix_, pixel, pixelOnFrameBuffer);
+
+ if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] ||
+ pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) {
+ // outside the image, no need to check
+ return undefined;
+ }
+
+ if (!this.hitCanvasContext_) {
+ this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);
+ }
+
+ this.hitCanvasContext_.clearRect(0, 0, 1, 1);
+ this.hitCanvasContext_.drawImage(this.image_.getImage(),
+ pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1);
+
+ var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;
+ if (imageData[3] > 0) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+ }
+};
+
+
+/**
+ * The transformation matrix to get the pixel on the image for a
+ * pixel on the map.
+ * @param {ol.Size} mapSize The map size.
+ * @param {ol.Size} imageSize The image size.
+ * @return {goog.vec.Mat4.Number} The transformation matrix.
+ * @private
+ */
+ol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ = function(mapSize, imageSize) {
+ // the first matrix takes a map pixel, flips the y-axis and scales to
+ // a range between -1 ... 1
+ var mapCoordMatrix = goog.vec.Mat4.createNumber();
+ goog.vec.Mat4.makeIdentity(mapCoordMatrix);
+ goog.vec.Mat4.translate(mapCoordMatrix, -1, -1, 0);
+ goog.vec.Mat4.scale(mapCoordMatrix, 2 / mapSize[0], 2 / mapSize[1], 1);
+ goog.vec.Mat4.translate(mapCoordMatrix, 0, mapSize[1], 0);
+ goog.vec.Mat4.scale(mapCoordMatrix, 1, -1, 1);
+
+ // the second matrix is the inverse of the projection matrix used in the
+ // shader for drawing
+ var projectionMatrixInv = goog.vec.Mat4.createNumber();
+ goog.vec.Mat4.invert(this.projectionMatrix, projectionMatrixInv);
+
+ // the third matrix scales to the image dimensions and flips the y-axis again
+ var imageCoordMatrix = goog.vec.Mat4.createNumber();
+ goog.vec.Mat4.makeIdentity(imageCoordMatrix);
+ goog.vec.Mat4.translate(imageCoordMatrix, 0, imageSize[1], 0);
+ goog.vec.Mat4.scale(imageCoordMatrix, 1, -1, 1);
+ goog.vec.Mat4.scale(imageCoordMatrix, imageSize[0] / 2, imageSize[1] / 2, 1);
+ goog.vec.Mat4.translate(imageCoordMatrix, 1, 1, 0);
+
+ var transformMatrix = goog.vec.Mat4.createNumber();
+ goog.vec.Mat4.multMat(
+ imageCoordMatrix, projectionMatrixInv, transformMatrix);
+ goog.vec.Mat4.multMat(
+ transformMatrix, mapCoordMatrix, transformMatrix);
+
+ return transformMatrix;
+};
+
+// This file is automatically generated, do not edit
+goog.provide('ol.renderer.webgl.tilelayer.shader');
+goog.provide('ol.renderer.webgl.tilelayer.shader.Locations');
+goog.provide('ol.renderer.webgl.tilelayer.shader.Fragment');
+goog.provide('ol.renderer.webgl.tilelayer.shader.Vertex');
+
+goog.require('ol.webgl.shader');
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.shader.Fragment}
+ * @struct
+ */
+ol.renderer.webgl.tilelayer.shader.Fragment = function() {
+ ol.webgl.shader.Fragment.call(this, ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE);
+};
+ol.inherits(ol.renderer.webgl.tilelayer.shader.Fragment, ol.webgl.shader.Fragment);
+goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Fragment);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.tilelayer.shader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\n\n\nuniform sampler2D u_texture;\n\nvoid main(void) {\n gl_FragColor = texture2D(u_texture, v_texCoord);\n}\n';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.tilelayer.shader.Fragment.SOURCE = goog.DEBUG ?
+ ol.renderer.webgl.tilelayer.shader.Fragment.DEBUG_SOURCE :
+ ol.renderer.webgl.tilelayer.shader.Fragment.OPTIMIZED_SOURCE;
+
+
+/**
+ * @constructor
+ * @extends {ol.webgl.shader.Vertex}
+ * @struct
+ */
+ol.renderer.webgl.tilelayer.shader.Vertex = function() {
+ ol.webgl.shader.Vertex.call(this, ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE);
+};
+ol.inherits(ol.renderer.webgl.tilelayer.shader.Vertex, ol.webgl.shader.Vertex);
+goog.addSingletonGetter(ol.renderer.webgl.tilelayer.shader.Vertex);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.tilelayer.shader.Vertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\n\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\nuniform vec4 u_tileOffset;\n\nvoid main(void) {\n gl_Position = vec4(a_position * u_tileOffset.xy + u_tileOffset.zw, 0., 1.);\n v_texCoord = a_texCoord;\n}\n\n\n';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.tilelayer.shader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;attribute vec2 b;attribute vec2 c;uniform vec4 d;void main(void){gl_Position=vec4(b*d.xy+d.zw,0.,1.);a=c;}';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.renderer.webgl.tilelayer.shader.Vertex.SOURCE = goog.DEBUG ?
+ ol.renderer.webgl.tilelayer.shader.Vertex.DEBUG_SOURCE :
+ ol.renderer.webgl.tilelayer.shader.Vertex.OPTIMIZED_SOURCE;
+
+
+/**
+ * @constructor
+ * @param {WebGLRenderingContext} gl GL.
+ * @param {WebGLProgram} program Program.
+ * @struct
+ */
+ol.renderer.webgl.tilelayer.shader.Locations = function(gl, program) {
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_texture = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_texture' : 'e');
+
+ /**
+ * @type {WebGLUniformLocation}
+ */
+ this.u_tileOffset = gl.getUniformLocation(
+ program, goog.DEBUG ? 'u_tileOffset' : 'd');
+
+ /**
+ * @type {number}
+ */
+ this.a_position = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_position' : 'b');
+
+ /**
+ * @type {number}
+ */
+ this.a_texCoord = gl.getAttribLocation(
+ program, goog.DEBUG ? 'a_texCoord' : 'c');
+};
+
+// FIXME large resolutions lead to too large framebuffers :-(
+// FIXME animated shaders! check in redraw
+
+goog.provide('ol.renderer.webgl.TileLayer');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('goog.vec.Vec4');
+goog.require('goog.webgl');
+goog.require('ol.TileRange');
+goog.require('ol.TileState');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.layer.Tile');
+goog.require('ol.math');
+goog.require('ol.renderer.webgl.Layer');
+goog.require('ol.renderer.webgl.tilelayer.shader.Fragment');
+goog.require('ol.renderer.webgl.tilelayer.shader.Locations');
+goog.require('ol.renderer.webgl.tilelayer.shader.Vertex');
+goog.require('ol.size');
+goog.require('ol.vec.Mat4');
+goog.require('ol.webgl.Buffer');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.webgl.Layer}
+ * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
+ * @param {ol.layer.Tile} tileLayer Tile layer.
+ */
+ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {
+
+ ol.renderer.webgl.Layer.call(this, mapRenderer, tileLayer);
+
+ /**
+ * @private
+ * @type {ol.webgl.shader.Fragment}
+ */
+ this.fragmentShader_ =
+ ol.renderer.webgl.tilelayer.shader.Fragment.getInstance();
+
+ /**
+ * @private
+ * @type {ol.webgl.shader.Vertex}
+ */
+ this.vertexShader_ = ol.renderer.webgl.tilelayer.shader.Vertex.getInstance();
+
+ /**
+ * @private
+ * @type {ol.renderer.webgl.tilelayer.shader.Locations}
+ */
+ this.locations_ = null;
+
+ /**
+ * @private
+ * @type {ol.webgl.Buffer}
+ */
+ this.renderArrayBuffer_ = new ol.webgl.Buffer([
+ 0, 0, 0, 1,
+ 1, 0, 1, 1,
+ 0, 1, 0, 0,
+ 1, 1, 1, 0
+ ]);
+
+ /**
+ * @private
+ * @type {ol.TileRange}
+ */
+ this.renderedTileRange_ = null;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.renderedFramebufferExtent_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = -1;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.tmpSize_ = [0, 0];
+
+};
+ol.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {
+ var context = this.mapRenderer.getContext();
+ context.deleteBuffer(this.renderArrayBuffer_);
+ ol.renderer.webgl.Layer.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * Create a function that adds loaded tiles to the tile lookup.
+ * @param {ol.source.Tile} source Tile source.
+ * @param {ol.proj.Projection} projection Projection of the tiles.
+ * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded
+ * tiles by zoom level.
+ * @return {function(number, ol.TileRange):boolean} A function that can be
+ * called with a zoom level and a tile range to add loaded tiles to the
+ * lookup.
+ * @protected
+ */
+ol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder = function(source, projection, tiles) {
+ var mapRenderer = this.mapRenderer;
+
+ return (
+ /**
+ * @param {number} zoom Zoom level.
+ * @param {ol.TileRange} tileRange Tile range.
+ * @return {boolean} The tile range is fully loaded.
+ */
+ function(zoom, tileRange) {
+ function callback(tile) {
+ var loaded = mapRenderer.isTileTextureLoaded(tile);
+ if (loaded) {
+ if (!tiles[zoom]) {
+ tiles[zoom] = {};
+ }
+ tiles[zoom][tile.tileCoord.toString()] = tile;
+ }
+ return loaded;
+ }
+ return source.forEachLoadedTile(projection, zoom, tileRange, callback);
+ });
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() {
+ ol.renderer.webgl.Layer.prototype.handleWebGLContextLost.call(this);
+ this.locations_ = null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.TileLayer.prototype.prepareFrame = function(frameState, layerState, context) {
+
+ var mapRenderer = this.mapRenderer;
+ var gl = context.getGL();
+
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+
+ var tileLayer = this.getLayer();
+ goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile,
+ 'layer is an instance of ol.layer.Tile');
+ var tileSource = tileLayer.getSource();
+ var tileGrid = tileSource.getTileGridForProjection(projection);
+ var z = tileGrid.getZForResolution(viewState.resolution);
+ var tileResolution = tileGrid.getResolution(z);
+
+ var tilePixelSize =
+ tileSource.getTilePixelSize(z, frameState.pixelRatio, projection);
+ var pixelRatio = tilePixelSize[0] /
+ ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0];
+ var tilePixelResolution = tileResolution / pixelRatio;
+ var tileGutter = tileSource.getGutter(projection);
+
+ var center = viewState.center;
+ var extent;
+ if (tileResolution == viewState.resolution) {
+ center = this.snapCenterToPixel(center, tileResolution, frameState.size);
+ extent = ol.extent.getForViewAndSize(
+ center, tileResolution, viewState.rotation, frameState.size);
+ } else {
+ extent = frameState.extent;
+ }
+ var tileRange = tileGrid.getTileRangeForExtentAndResolution(
+ extent, tileResolution);
+
+ var framebufferExtent;
+ if (this.renderedTileRange_ &&
+ this.renderedTileRange_.equals(tileRange) &&
+ this.renderedRevision_ == tileSource.getRevision()) {
+ framebufferExtent = this.renderedFramebufferExtent_;
+ } else {
+
+ var tileRangeSize = tileRange.getSize();
+
+ var maxDimension = Math.max(
+ tileRangeSize[0] * tilePixelSize[0],
+ tileRangeSize[1] * tilePixelSize[1]);
+ var framebufferDimension = ol.math.roundUpToPowerOfTwo(maxDimension);
+ var framebufferExtentDimension = tilePixelResolution * framebufferDimension;
+ var origin = tileGrid.getOrigin(z);
+ var minX = origin[0] +
+ tileRange.minX * tilePixelSize[0] * tilePixelResolution;
+ var minY = origin[1] +
+ tileRange.minY * tilePixelSize[1] * tilePixelResolution;
+ framebufferExtent = [
+ minX, minY,
+ minX + framebufferExtentDimension, minY + framebufferExtentDimension
+ ];
+
+ this.bindFramebuffer(frameState, framebufferDimension);
+ gl.viewport(0, 0, framebufferDimension, framebufferDimension);
+
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(goog.webgl.COLOR_BUFFER_BIT);
+ gl.disable(goog.webgl.BLEND);
+
+ var program = context.getProgram(this.fragmentShader_, this.vertexShader_);
+ context.useProgram(program);
+ if (!this.locations_) {
+ this.locations_ =
+ new ol.renderer.webgl.tilelayer.shader.Locations(gl, program);
+ }
+
+ context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.renderArrayBuffer_);
+ gl.enableVertexAttribArray(this.locations_.a_position);
+ gl.vertexAttribPointer(
+ this.locations_.a_position, 2, goog.webgl.FLOAT, false, 16, 0);
+ gl.enableVertexAttribArray(this.locations_.a_texCoord);
+ gl.vertexAttribPointer(
+ this.locations_.a_texCoord, 2, goog.webgl.FLOAT, false, 16, 8);
+ gl.uniform1i(this.locations_.u_texture, 0);
+
+ /**
+ * @type {Object.<number, Object.<string, ol.Tile>>}
+ */
+ var tilesToDrawByZ = {};
+ tilesToDrawByZ[z] = {};
+
+ var findLoadedTiles = this.createLoadedTileFinder(
+ tileSource, projection, tilesToDrawByZ);
+
+ var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
+ var allTilesLoaded = true;
+ var tmpExtent = ol.extent.createEmpty();
+ var tmpTileRange = new ol.TileRange(0, 0, 0, 0);
+ var childTileRange, drawable, fullyLoaded, tile, tileState;
+ var x, y, tileExtent;
+ for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
+ for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
+
+ tile = tileSource.getTile(z, x, y, pixelRatio, projection);
+ if (layerState.extent !== undefined) {
+ // ignore tiles outside layer extent
+ tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);
+ if (!ol.extent.intersects(tileExtent, layerState.extent)) {
+ continue;
+ }
+ }
+ tileState = tile.getState();
+ drawable = tileState == ol.TileState.LOADED ||
+ tileState == ol.TileState.EMPTY ||
+ tileState == ol.TileState.ERROR && !useInterimTilesOnError;
+ if (!drawable && tile.interimTile) {
+ tile = tile.interimTile;
+ }
+ goog.asserts.assert(tile);
+ tileState = tile.getState();
+ if (tileState == ol.TileState.LOADED) {
+ if (mapRenderer.isTileTextureLoaded(tile)) {
+ tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
+ continue;
+ }
+ } else if (tileState == ol.TileState.EMPTY ||
+ (tileState == ol.TileState.ERROR &&
+ !useInterimTilesOnError)) {
+ continue;
+ }
+
+ allTilesLoaded = false;
+ fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
+ tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
+ if (!fullyLoaded) {
+ childTileRange = tileGrid.getTileCoordChildTileRange(
+ tile.tileCoord, tmpTileRange, tmpExtent);
+ if (childTileRange) {
+ findLoadedTiles(z + 1, childTileRange);
+ }
+ }
+
+ }
+
+ }
+
+ /** @type {Array.<number>} */
+ var zs = Object.keys(tilesToDrawByZ).map(Number);
+ zs.sort(ol.array.numberSafeCompareFunction);
+ var u_tileOffset = goog.vec.Vec4.createFloat32();
+ var i, ii, sx, sy, tileKey, tilesToDraw, tx, ty;
+ for (i = 0, ii = zs.length; i < ii; ++i) {
+ tilesToDraw = tilesToDrawByZ[zs[i]];
+ for (tileKey in tilesToDraw) {
+ tile = tilesToDraw[tileKey];
+ tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);
+ sx = 2 * (tileExtent[2] - tileExtent[0]) /
+ framebufferExtentDimension;
+ sy = 2 * (tileExtent[3] - tileExtent[1]) /
+ framebufferExtentDimension;
+ tx = 2 * (tileExtent[0] - framebufferExtent[0]) /
+ framebufferExtentDimension - 1;
+ ty = 2 * (tileExtent[1] - framebufferExtent[1]) /
+ framebufferExtentDimension - 1;
+ goog.vec.Vec4.setFromValues(u_tileOffset, sx, sy, tx, ty);
+ gl.uniform4fv(this.locations_.u_tileOffset, u_tileOffset);
+ mapRenderer.bindTileTexture(tile, tilePixelSize,
+ tileGutter * pixelRatio, goog.webgl.LINEAR, goog.webgl.LINEAR);
+ gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
+ }
+ }
+
+ if (allTilesLoaded) {
+ this.renderedTileRange_ = tileRange;
+ this.renderedFramebufferExtent_ = framebufferExtent;
+ this.renderedRevision_ = tileSource.getRevision();
+ } else {
+ this.renderedTileRange_ = null;
+ this.renderedFramebufferExtent_ = null;
+ this.renderedRevision_ = -1;
+ frameState.animate = true;
+ }
+
+ }
+
+ this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
+ var tileTextureQueue = mapRenderer.getTileTextureQueue();
+ this.manageTilePyramid(
+ frameState, tileSource, tileGrid, pixelRatio, projection, extent, z,
+ tileLayer.getPreload(),
+ /**
+ * @param {ol.Tile} tile Tile.
+ */
+ function(tile) {
+ if (tile.getState() == ol.TileState.LOADED &&
+ !mapRenderer.isTileTextureLoaded(tile) &&
+ !tileTextureQueue.isKeyQueued(tile.getKey())) {
+ tileTextureQueue.enqueue([
+ tile,
+ tileGrid.getTileCoordCenter(tile.tileCoord),
+ tileGrid.getResolution(tile.tileCoord[0]),
+ tilePixelSize, tileGutter * pixelRatio
+ ]);
+ }
+ }, this);
+ this.scheduleExpireCache(frameState, tileSource);
+ this.updateLogos(frameState, tileSource);
+
+ var texCoordMatrix = this.texCoordMatrix;
+ goog.vec.Mat4.makeIdentity(texCoordMatrix);
+ goog.vec.Mat4.translate(texCoordMatrix,
+ (center[0] - framebufferExtent[0]) /
+ (framebufferExtent[2] - framebufferExtent[0]),
+ (center[1] - framebufferExtent[1]) /
+ (framebufferExtent[3] - framebufferExtent[1]),
+ 0);
+ if (viewState.rotation !== 0) {
+ goog.vec.Mat4.rotateZ(texCoordMatrix, viewState.rotation);
+ }
+ goog.vec.Mat4.scale(texCoordMatrix,
+ frameState.size[0] * viewState.resolution /
+ (framebufferExtent[2] - framebufferExtent[0]),
+ frameState.size[1] * viewState.resolution /
+ (framebufferExtent[3] - framebufferExtent[1]),
+ 1);
+ goog.vec.Mat4.translate(texCoordMatrix,
+ -0.5,
+ -0.5,
+ 0);
+
+ return true;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
+ if (!this.framebuffer) {
+ return undefined;
+ }
+
+ var pixelOnMapScaled = [
+ pixel[0] / frameState.size[0],
+ (frameState.size[1] - pixel[1]) / frameState.size[1]];
+
+ var pixelOnFrameBufferScaled = [0, 0];
+ ol.vec.Mat4.multVec2(
+ this.texCoordMatrix, pixelOnMapScaled, pixelOnFrameBufferScaled);
+ var pixelOnFrameBuffer = [
+ pixelOnFrameBufferScaled[0] * this.framebufferDimension,
+ pixelOnFrameBufferScaled[1] * this.framebufferDimension];
+
+ var gl = this.mapRenderer.getContext().getGL();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
+ var imageData = new Uint8Array(4);
+ gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1,
+ gl.RGBA, gl.UNSIGNED_BYTE, imageData);
+
+ if (imageData[3] > 0) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+};
+
+goog.provide('ol.renderer.webgl.VectorLayer');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.ViewHint');
+goog.require('ol.extent');
+goog.require('ol.layer.Vector');
+goog.require('ol.render.webgl.ReplayGroup');
+goog.require('ol.renderer.vector');
+goog.require('ol.renderer.webgl.Layer');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.webgl.Layer}
+ * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
+ * @param {ol.layer.Vector} vectorLayer Vector layer.
+ */
+ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) {
+
+ ol.renderer.webgl.Layer.call(this, mapRenderer, vectorLayer);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.dirty_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedResolution_ = NaN;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.renderedExtent_ = ol.extent.createEmpty();
+
+ /**
+ * @private
+ * @type {function(ol.Feature, ol.Feature): number|null}
+ */
+ this.renderedRenderOrder_ = null;
+
+ /**
+ * @private
+ * @type {ol.render.webgl.ReplayGroup}
+ */
+ this.replayGroup_ = null;
+
+ /**
+ * The last layer state.
+ * @private
+ * @type {?ol.LayerState}
+ */
+ this.layerState_ = null;
+
+};
+ol.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer);
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {
+ this.layerState_ = layerState;
+ var viewState = frameState.viewState;
+ var replayGroup = this.replayGroup_;
+ if (replayGroup && !replayGroup.isEmpty()) {
+ replayGroup.replay(context,
+ viewState.center, viewState.resolution, viewState.rotation,
+ frameState.size, frameState.pixelRatio, layerState.opacity,
+ layerState.managed ? frameState.skippedFeatureUids : {});
+ }
+
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() {
+ var replayGroup = this.replayGroup_;
+ if (replayGroup) {
+ var context = this.mapRenderer.getContext();
+ replayGroup.getDeleteResourcesFunction(context)();
+ this.replayGroup_ = null;
+ }
+ ol.renderer.webgl.Layer.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg) {
+ if (!this.replayGroup_ || !this.layerState_) {
+ return undefined;
+ } else {
+ var context = this.mapRenderer.getContext();
+ var viewState = frameState.viewState;
+ var layer = this.getLayer();
+ var layerState = this.layerState_;
+ /** @type {Object.<string, boolean>} */
+ var features = {};
+ return this.replayGroup_.forEachFeatureAtCoordinate(coordinate,
+ context, viewState.center, viewState.resolution, viewState.rotation,
+ frameState.size, frameState.pixelRatio, layerState.opacity,
+ {},
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @return {?} Callback result.
+ */
+ function(feature) {
+ goog.asserts.assert(feature !== undefined, 'received a feature');
+ var key = goog.getUid(feature).toString();
+ if (!(key in features)) {
+ features[key] = true;
+ return callback.call(thisArg, feature, layer);
+ }
+ });
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = function(coordinate, frameState) {
+ if (!this.replayGroup_ || !this.layerState_) {
+ return false;
+ } else {
+ var context = this.mapRenderer.getContext();
+ var viewState = frameState.viewState;
+ var layerState = this.layerState_;
+ return this.replayGroup_.hasFeatureAtCoordinate(coordinate,
+ context, viewState.center, viewState.resolution, viewState.rotation,
+ frameState.size, frameState.pixelRatio, layerState.opacity,
+ frameState.skippedFeatureUids);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
+ var coordinate = pixel.slice();
+ ol.vec.Mat4.multVec2(
+ frameState.pixelToCoordinateMatrix, coordinate, coordinate);
+ var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState);
+
+ if (hasFeature) {
+ return callback.call(thisArg, this.getLayer());
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * Handle changes in image style state.
+ * @param {ol.events.Event} event Image style change event.
+ * @private
+ */
+ol.renderer.webgl.VectorLayer.prototype.handleStyleImageChange_ = function(event) {
+ this.renderIfReadyAndVisible();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.VectorLayer.prototype.prepareFrame = function(frameState, layerState, context) {
+
+ var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
+ goog.asserts.assertInstanceof(vectorLayer, ol.layer.Vector,
+ 'layer is an instance of ol.layer.Vector');
+ var vectorSource = vectorLayer.getSource();
+
+ this.updateAttributions(
+ frameState.attributions, vectorSource.getAttributions());
+ this.updateLogos(frameState, vectorSource);
+
+ var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
+ var interacting = frameState.viewHints[ol.ViewHint.INTERACTING];
+ var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();
+ var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();
+
+ if (!this.dirty_ && (!updateWhileAnimating && animating) ||
+ (!updateWhileInteracting && interacting)) {
+ return true;
+ }
+
+ var frameStateExtent = frameState.extent;
+ var viewState = frameState.viewState;
+ var projection = viewState.projection;
+ var resolution = viewState.resolution;
+ var pixelRatio = frameState.pixelRatio;
+ var vectorLayerRevision = vectorLayer.getRevision();
+ var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();
+ var vectorLayerRenderOrder = vectorLayer.getRenderOrder();
+
+ if (vectorLayerRenderOrder === undefined) {
+ vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;
+ }
+
+ var extent = ol.extent.buffer(frameStateExtent,
+ vectorLayerRenderBuffer * resolution);
+
+ if (!this.dirty_ &&
+ this.renderedResolution_ == resolution &&
+ this.renderedRevision_ == vectorLayerRevision &&
+ this.renderedRenderOrder_ == vectorLayerRenderOrder &&
+ ol.extent.containsExtent(this.renderedExtent_, extent)) {
+ return true;
+ }
+
+ if (this.replayGroup_) {
+ frameState.postRenderFunctions.push(
+ this.replayGroup_.getDeleteResourcesFunction(context));
+ }
+
+ this.dirty_ = false;
+
+ var replayGroup = new ol.render.webgl.ReplayGroup(
+ ol.renderer.vector.getTolerance(resolution, pixelRatio),
+ extent, vectorLayer.getRenderBuffer());
+ vectorSource.loadFeatures(extent, resolution, projection);
+ /**
+ * @param {ol.Feature} feature Feature.
+ * @this {ol.renderer.webgl.VectorLayer}
+ */
+ var renderFeature = function(feature) {
+ var styles;
+ var styleFunction = feature.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction.call(feature, resolution);
+ } else {
+ styleFunction = vectorLayer.getStyleFunction();
+ if (styleFunction) {
+ styles = styleFunction(feature, resolution);
+ }
+ }
+ if (styles) {
+ var dirty = this.renderFeature(
+ feature, resolution, pixelRatio, styles, replayGroup);
+ this.dirty_ = this.dirty_ || dirty;
+ }
+ };
+ if (vectorLayerRenderOrder) {
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ vectorSource.forEachFeatureInExtent(extent,
+ /**
+ * @param {ol.Feature} feature Feature.
+ */
+ function(feature) {
+ features.push(feature);
+ }, this);
+ features.sort(vectorLayerRenderOrder);
+ features.forEach(renderFeature, this);
+ } else {
+ vectorSource.forEachFeatureInExtent(extent, renderFeature, this);
+ }
+ replayGroup.finish(context);
+
+ this.renderedResolution_ = resolution;
+ this.renderedRevision_ = vectorLayerRevision;
+ this.renderedRenderOrder_ = vectorLayerRenderOrder;
+ this.renderedExtent_ = extent;
+ this.replayGroup_ = replayGroup;
+
+ return true;
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {number} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
+ * styles.
+ * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group.
+ * @return {boolean} `true` if an image is loading.
+ */
+ol.renderer.webgl.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {
+ if (!styles) {
+ return false;
+ }
+ var loading = false;
+ if (Array.isArray(styles)) {
+ for (var i = 0, ii = styles.length; i < ii; ++i) {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles[i],
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleStyleImageChange_, this) || loading;
+ }
+ } else {
+ loading = ol.renderer.vector.renderFeature(
+ replayGroup, feature, styles,
+ ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
+ this.handleStyleImageChange_, this) || loading;
+ }
+ return loading;
+};
+
+// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE)
+
+goog.provide('ol.renderer.webgl.Map');
+
+goog.require('goog.asserts');
+goog.require('goog.webgl');
+goog.require('ol');
+goog.require('ol.RendererType');
+goog.require('ol.array');
+goog.require('ol.css');
+goog.require('ol.dom');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.layer.Image');
+goog.require('ol.layer.Layer');
+goog.require('ol.layer.Tile');
+goog.require('ol.layer.Vector');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.webgl.Immediate');
+goog.require('ol.renderer.Map');
+goog.require('ol.renderer.webgl.ImageLayer');
+goog.require('ol.renderer.webgl.Layer');
+goog.require('ol.renderer.webgl.TileLayer');
+goog.require('ol.renderer.webgl.VectorLayer');
+goog.require('ol.source.State');
+goog.require('ol.structs.LRUCache');
+goog.require('ol.structs.PriorityQueue');
+goog.require('ol.webgl');
+goog.require('ol.webgl.Context');
+goog.require('ol.webgl.WebGLContextEventType');
+
+
+/**
+ * @constructor
+ * @extends {ol.renderer.Map}
+ * @param {Element} container Container.
+ * @param {ol.Map} map Map.
+ */
+ol.renderer.webgl.Map = function(container, map) {
+
+ ol.renderer.Map.call(this, container, map);
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = /** @type {HTMLCanvasElement} */
+ (document.createElement('CANVAS'));
+ this.canvas_.style.width = '100%';
+ this.canvas_.style.height = '100%';
+ this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
+ container.insertBefore(this.canvas_, container.childNodes[0] || null);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.clipTileCanvasWidth_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.clipTileCanvasHeight_ = 0;
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.clipTileContext_ = ol.dom.createCanvasContext2D();
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderedVisible_ = true;
+
+ /**
+ * @private
+ * @type {WebGLRenderingContext}
+ */
+ this.gl_ = ol.webgl.getContext(this.canvas_, {
+ antialias: true,
+ depth: false,
+ failIfMajorPerformanceCaveat: true,
+ preserveDrawingBuffer: false,
+ stencil: true
+ });
+ goog.asserts.assert(this.gl_, 'got a WebGLRenderingContext');
+
+ /**
+ * @private
+ * @type {ol.webgl.Context}
+ */
+ this.context_ = new ol.webgl.Context(this.canvas_, this.gl_);
+
+ ol.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.LOST,
+ this.handleWebGLContextLost, this);
+ ol.events.listen(this.canvas_, ol.webgl.WebGLContextEventType.RESTORED,
+ this.handleWebGLContextRestored, this);
+
+ /**
+ * @private
+ * @type {ol.structs.LRUCache.<ol.WebglTextureCacheEntry|null>}
+ */
+ this.textureCache_ = new ol.structs.LRUCache();
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.focus_ = null;
+
+ /**
+ * @private
+ * @type {ol.structs.PriorityQueue.<Array>}
+ */
+ this.tileTextureQueue_ = new ol.structs.PriorityQueue(
+ /**
+ * @param {Array.<*>} element Element.
+ * @return {number} Priority.
+ * @this {ol.renderer.webgl.Map}
+ */
+ (function(element) {
+ var tileCenter = /** @type {ol.Coordinate} */ (element[1]);
+ var tileResolution = /** @type {number} */ (element[2]);
+ var deltaX = tileCenter[0] - this.focus_[0];
+ var deltaY = tileCenter[1] - this.focus_[1];
+ return 65536 * Math.log(tileResolution) +
+ Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
+ }).bind(this),
+ /**
+ * @param {Array.<*>} element Element.
+ * @return {string} Key.
+ */
+ function(element) {
+ return /** @type {ol.Tile} */ (element[0]).getKey();
+ });
+
+
+ /**
+ * @param {ol.Map} map Map.
+ * @param {?olx.FrameState} frameState Frame state.
+ * @return {boolean} false.
+ * @this {ol.renderer.webgl.Map}
+ */
+ this.loadNextTileTexture_ =
+ function(map, frameState) {
+ if (!this.tileTextureQueue_.isEmpty()) {
+ this.tileTextureQueue_.reprioritize();
+ var element = this.tileTextureQueue_.dequeue();
+ var tile = /** @type {ol.Tile} */ (element[0]);
+ var tileSize = /** @type {ol.Size} */ (element[3]);
+ var tileGutter = /** @type {number} */ (element[4]);
+ this.bindTileTexture(
+ tile, tileSize, tileGutter, goog.webgl.LINEAR, goog.webgl.LINEAR);
+ }
+ return false;
+ }.bind(this);
+
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.textureCacheFrameMarkerCount_ = 0;
+
+ this.initializeGL_();
+
+};
+ol.inherits(ol.renderer.webgl.Map, ol.renderer.Map);
+
+
+/**
+ * @param {ol.Tile} tile Tile.
+ * @param {ol.Size} tileSize Tile size.
+ * @param {number} tileGutter Tile gutter.
+ * @param {number} magFilter Mag filter.
+ * @param {number} minFilter Min filter.
+ */
+ol.renderer.webgl.Map.prototype.bindTileTexture = function(tile, tileSize, tileGutter, magFilter, minFilter) {
+ var gl = this.getGL();
+ var tileKey = tile.getKey();
+ if (this.textureCache_.containsKey(tileKey)) {
+ var textureCacheEntry = this.textureCache_.get(tileKey);
+ goog.asserts.assert(textureCacheEntry,
+ 'a texture cache entry exists for key %s', tileKey);
+ gl.bindTexture(goog.webgl.TEXTURE_2D, textureCacheEntry.texture);
+ if (textureCacheEntry.magFilter != magFilter) {
+ gl.texParameteri(
+ goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter);
+ textureCacheEntry.magFilter = magFilter;
+ }
+ if (textureCacheEntry.minFilter != minFilter) {
+ gl.texParameteri(
+ goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER, minFilter);
+ textureCacheEntry.minFilter = minFilter;
+ }
+ } else {
+ var texture = gl.createTexture();
+ gl.bindTexture(goog.webgl.TEXTURE_2D, texture);
+ if (tileGutter > 0) {
+ var clipTileCanvas = this.clipTileContext_.canvas;
+ var clipTileContext = this.clipTileContext_;
+ if (this.clipTileCanvasWidth_ !== tileSize[0] ||
+ this.clipTileCanvasHeight_ !== tileSize[1]) {
+ clipTileCanvas.width = tileSize[0];
+ clipTileCanvas.height = tileSize[1];
+ this.clipTileCanvasWidth_ = tileSize[0];
+ this.clipTileCanvasHeight_ = tileSize[1];
+ } else {
+ clipTileContext.clearRect(0, 0, tileSize[0], tileSize[1]);
+ }
+ clipTileContext.drawImage(tile.getImage(), tileGutter, tileGutter,
+ tileSize[0], tileSize[1], 0, 0, tileSize[0], tileSize[1]);
+ gl.texImage2D(goog.webgl.TEXTURE_2D, 0,
+ goog.webgl.RGBA, goog.webgl.RGBA,
+ goog.webgl.UNSIGNED_BYTE, clipTileCanvas);
+ } else {
+ gl.texImage2D(goog.webgl.TEXTURE_2D, 0,
+ goog.webgl.RGBA, goog.webgl.RGBA,
+ goog.webgl.UNSIGNED_BYTE, tile.getImage());
+ }
+ gl.texParameteri(
+ goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MAG_FILTER, magFilter);
+ gl.texParameteri(
+ goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_MIN_FILTER, minFilter);
+ gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_S,
+ goog.webgl.CLAMP_TO_EDGE);
+ gl.texParameteri(goog.webgl.TEXTURE_2D, goog.webgl.TEXTURE_WRAP_T,
+ goog.webgl.CLAMP_TO_EDGE);
+ this.textureCache_.set(tileKey, {
+ texture: texture,
+ magFilter: magFilter,
+ minFilter: minFilter
+ });
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.createLayerRenderer = function(layer) {
+ if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) {
+ return new ol.renderer.webgl.ImageLayer(this, layer);
+ } else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {
+ return new ol.renderer.webgl.TileLayer(this, layer);
+ } else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {
+ return new ol.renderer.webgl.VectorLayer(this, layer);
+ } else {
+ goog.asserts.fail('unexpected layer configuration');
+ return null;
+ }
+};
+
+
+/**
+ * @param {ol.render.EventType} type Event type.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {
+ var map = this.getMap();
+ if (map.hasListener(type)) {
+ var context = this.context_;
+
+ var extent = frameState.extent;
+ var size = frameState.size;
+ var viewState = frameState.viewState;
+ var pixelRatio = frameState.pixelRatio;
+
+ var resolution = viewState.resolution;
+ var center = viewState.center;
+ var rotation = viewState.rotation;
+
+ var vectorContext = new ol.render.webgl.Immediate(context,
+ center, resolution, rotation, size, extent, pixelRatio);
+ var composeEvent = new ol.render.Event(type, map, vectorContext,
+ frameState, null, context);
+ map.dispatchEvent(composeEvent);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.disposeInternal = function() {
+ var gl = this.getGL();
+ if (!gl.isContextLost()) {
+ this.textureCache_.forEach(
+ /**
+ * @param {?ol.WebglTextureCacheEntry} textureCacheEntry
+ * Texture cache entry.
+ */
+ function(textureCacheEntry) {
+ if (textureCacheEntry) {
+ gl.deleteTexture(textureCacheEntry.texture);
+ }
+ });
+ }
+ this.context_.dispose();
+ ol.renderer.Map.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @param {ol.Map} map Map.
+ * @param {olx.FrameState} frameState Frame state.
+ * @private
+ */
+ol.renderer.webgl.Map.prototype.expireCache_ = function(map, frameState) {
+ var gl = this.getGL();
+ var textureCacheEntry;
+ while (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ >
+ ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) {
+ textureCacheEntry = this.textureCache_.peekLast();
+ if (!textureCacheEntry) {
+ if (+this.textureCache_.peekLastKey() == frameState.index) {
+ break;
+ } else {
+ --this.textureCacheFrameMarkerCount_;
+ }
+ } else {
+ gl.deleteTexture(textureCacheEntry.texture);
+ }
+ this.textureCache_.pop();
+ }
+};
+
+
+/**
+ * @return {ol.webgl.Context} The context.
+ */
+ol.renderer.webgl.Map.prototype.getContext = function() {
+ return this.context_;
+};
+
+
+/**
+ * @return {WebGLRenderingContext} GL.
+ */
+ol.renderer.webgl.Map.prototype.getGL = function() {
+ return this.gl_;
+};
+
+
+/**
+ * @return {ol.structs.PriorityQueue.<Array>} Tile texture queue.
+ */
+ol.renderer.webgl.Map.prototype.getTileTextureQueue = function() {
+ return this.tileTextureQueue_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.getType = function() {
+ return ol.RendererType.WEBGL;
+};
+
+
+/**
+ * @param {ol.events.Event} event Event.
+ * @protected
+ */
+ol.renderer.webgl.Map.prototype.handleWebGLContextLost = function(event) {
+ event.preventDefault();
+ this.textureCache_.clear();
+ this.textureCacheFrameMarkerCount_ = 0;
+
+ var renderers = this.getLayerRenderers();
+ for (var id in renderers) {
+ var renderer = /** @type {ol.renderer.webgl.Layer} */ (renderers[id]);
+ renderer.handleWebGLContextLost();
+ }
+};
+
+
+/**
+ * @protected
+ */
+ol.renderer.webgl.Map.prototype.handleWebGLContextRestored = function() {
+ this.initializeGL_();
+ this.getMap().render();
+};
+
+
+/**
+ * @private
+ */
+ol.renderer.webgl.Map.prototype.initializeGL_ = function() {
+ var gl = this.gl_;
+ gl.activeTexture(goog.webgl.TEXTURE0);
+ gl.blendFuncSeparate(
+ goog.webgl.SRC_ALPHA, goog.webgl.ONE_MINUS_SRC_ALPHA,
+ goog.webgl.ONE, goog.webgl.ONE_MINUS_SRC_ALPHA);
+ gl.disable(goog.webgl.CULL_FACE);
+ gl.disable(goog.webgl.DEPTH_TEST);
+ gl.disable(goog.webgl.SCISSOR_TEST);
+ gl.disable(goog.webgl.STENCIL_TEST);
+};
+
+
+/**
+ * @param {ol.Tile} tile Tile.
+ * @return {boolean} Is tile texture loaded.
+ */
+ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {
+ return this.textureCache_.containsKey(tile.getKey());
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
+
+ var context = this.getContext();
+ var gl = this.getGL();
+
+ if (gl.isContextLost()) {
+ return false;
+ }
+
+ if (!frameState) {
+ if (this.renderedVisible_) {
+ this.canvas_.style.display = 'none';
+ this.renderedVisible_ = false;
+ }
+ return false;
+ }
+
+ this.focus_ = frameState.focus;
+
+ this.textureCache_.set((-frameState.index).toString(), null);
+ ++this.textureCacheFrameMarkerCount_;
+
+ this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
+
+ /** @type {Array.<ol.LayerState>} */
+ var layerStatesToDraw = [];
+ var layerStatesArray = frameState.layerStatesArray;
+ ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
+
+ var viewResolution = frameState.viewState.resolution;
+ var i, ii, layerRenderer, layerState;
+ for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
+ layerState = layerStatesArray[i];
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
+ layerState.sourceState == ol.source.State.READY) {
+ layerRenderer = this.getLayerRenderer(layerState.layer);
+ goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer,
+ 'renderer is an instance of ol.renderer.webgl.Layer');
+ if (layerRenderer.prepareFrame(frameState, layerState, context)) {
+ layerStatesToDraw.push(layerState);
+ }
+ }
+ }
+
+ var width = frameState.size[0] * frameState.pixelRatio;
+ var height = frameState.size[1] * frameState.pixelRatio;
+ if (this.canvas_.width != width || this.canvas_.height != height) {
+ this.canvas_.width = width;
+ this.canvas_.height = height;
+ }
+
+ gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, null);
+
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(goog.webgl.COLOR_BUFFER_BIT);
+ gl.enable(goog.webgl.BLEND);
+ gl.viewport(0, 0, this.canvas_.width, this.canvas_.height);
+
+ for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) {
+ layerState = layerStatesToDraw[i];
+ layerRenderer = this.getLayerRenderer(layerState.layer);
+ goog.asserts.assertInstanceof(layerRenderer, ol.renderer.webgl.Layer,
+ 'renderer is an instance of ol.renderer.webgl.Layer');
+ layerRenderer.composeFrame(frameState, layerState, context);
+ }
+
+ if (!this.renderedVisible_) {
+ this.canvas_.style.display = '';
+ this.renderedVisible_ = true;
+ }
+
+ this.calculateMatrices2D(frameState);
+
+ if (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ >
+ ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) {
+ frameState.postRenderFunctions.push(
+ /** @type {ol.PostRenderFunction} */ (this.expireCache_.bind(this))
+ );
+ }
+
+ if (!this.tileTextureQueue_.isEmpty()) {
+ frameState.postRenderFunctions.push(this.loadNextTileTexture_);
+ frameState.animate = true;
+ }
+
+ this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState);
+
+ this.scheduleRemoveUnusedLayerRenderers(frameState);
+ this.scheduleExpireIconCache(frameState);
+
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, callback, thisArg,
+ layerFilter, thisArg2) {
+ var result;
+
+ if (this.getGL().isContextLost()) {
+ return false;
+ }
+
+ var viewState = frameState.viewState;
+
+ var layerStates = frameState.layerStatesArray;
+ var numLayers = layerStates.length;
+ var i;
+ for (i = numLayers - 1; i >= 0; --i) {
+ var layerState = layerStates[i];
+ var layer = layerState.layer;
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
+ layerFilter.call(thisArg2, layer)) {
+ var layerRenderer = this.getLayerRenderer(layer);
+ result = layerRenderer.forEachFeatureAtCoordinate(
+ coordinate, frameState, callback, thisArg);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate = function(coordinate, frameState, layerFilter, thisArg) {
+ var hasFeature = false;
+
+ if (this.getGL().isContextLost()) {
+ return false;
+ }
+
+ var viewState = frameState.viewState;
+
+ var layerStates = frameState.layerStatesArray;
+ var numLayers = layerStates.length;
+ var i;
+ for (i = numLayers - 1; i >= 0; --i) {
+ var layerState = layerStates[i];
+ var layer = layerState.layer;
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
+ layerFilter.call(thisArg, layer)) {
+ var layerRenderer = this.getLayerRenderer(layer);
+ hasFeature =
+ layerRenderer.hasFeatureAtCoordinate(coordinate, frameState);
+ if (hasFeature) {
+ return true;
+ }
+ }
+ }
+ return hasFeature;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.renderer.webgl.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
+ layerFilter, thisArg2) {
+ if (this.getGL().isContextLost()) {
+ return false;
+ }
+
+ var viewState = frameState.viewState;
+ var result;
+
+ var layerStates = frameState.layerStatesArray;
+ var numLayers = layerStates.length;
+ var i;
+ for (i = numLayers - 1; i >= 0; --i) {
+ var layerState = layerStates[i];
+ var layer = layerState.layer;
+ if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
+ layerFilter.call(thisArg, layer)) {
+ var layerRenderer = this.getLayerRenderer(layer);
+ result = layerRenderer.forEachLayerAtPixel(
+ pixel, frameState, callback, thisArg);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return undefined;
+};
+
+// FIXME recheck layer/map projection compatibility when projection changes
+// FIXME layer renderers should skip when they can't reproject
+// FIXME add tilt and height?
+
+goog.provide('ol.Map');
+goog.provide('ol.MapProperty');
+
+goog.require('goog.asserts');
+goog.require('goog.async.nextTick');
+goog.require('goog.vec.Mat4');
+goog.require('ol.Collection');
+goog.require('ol.CollectionEventType');
+goog.require('ol.MapBrowserEvent');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.MapBrowserEventHandler');
+goog.require('ol.MapEvent');
+goog.require('ol.MapEventType');
+goog.require('ol.Object');
+goog.require('ol.ObjectEvent');
+goog.require('ol.ObjectEventType');
+goog.require('ol.RendererType');
+goog.require('ol.TileQueue');
+goog.require('ol.View');
+goog.require('ol.ViewHint');
+goog.require('ol.array');
+goog.require('ol.control');
+goog.require('ol.dom');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.functions');
+goog.require('ol.has');
+goog.require('ol.interaction');
+goog.require('ol.layer.Base');
+goog.require('ol.layer.Group');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.proj.common');
+goog.require('ol.renderer.Map');
+goog.require('ol.renderer.canvas.Map');
+goog.require('ol.renderer.dom.Map');
+goog.require('ol.renderer.webgl.Map');
+goog.require('ol.size');
+goog.require('ol.structs.PriorityQueue');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.OL3_URL = 'http://openlayers.org/';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.OL3_LOGO_URL = 'data:image/png;base64,' +
+ 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBI' +
+ 'WXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAA' +
+ 'AhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszW' +
+ 'WMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvY' +
+ 'asvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvX' +
+ 'H1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1Vk' +
+ 'bMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW' +
+ '2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLP' +
+ 'VcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqT' +
+ 'acrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaar' +
+ 'ldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+Hi' +
+ 'zeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDn' +
+ 'BAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSF' +
+ 'hYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJ' +
+ 'REFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxC' +
+ 'Brb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe' +
+ '0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8' +
+ 'a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7a' +
+ 'hgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCn' +
+ 'B3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDg' +
+ 'q82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC';
+
+
+/**
+ * @type {Array.<ol.RendererType>}
+ * @const
+ */
+ol.DEFAULT_RENDERER_TYPES = [
+ ol.RendererType.CANVAS,
+ ol.RendererType.WEBGL,
+ ol.RendererType.DOM
+];
+
+
+/**
+ * @enum {string}
+ */
+ol.MapProperty = {
+ LAYERGROUP: 'layergroup',
+ SIZE: 'size',
+ TARGET: 'target',
+ VIEW: 'view'
+};
+
+
+/**
+ * @classdesc
+ * The map is the core component of OpenLayers. For a map to render, a view,
+ * one or more layers, and a target container are needed:
+ *
+ * var map = new ol.Map({
+ * view: new ol.View({
+ * center: [0, 0],
+ * zoom: 1
+ * }),
+ * layers: [
+ * new ol.layer.Tile({
+ * source: new ol.source.OSM()
+ * })
+ * ],
+ * target: 'map'
+ * });
+ *
+ * The above snippet creates a map using a {@link ol.layer.Tile} to display
+ * {@link ol.source.OSM} OSM data and render it to a DOM element with the
+ * id `map`.
+ *
+ * The constructor places a viewport container (with CSS class name
+ * `ol-viewport`) in the target element (see `getViewport()`), and then two
+ * further elements within the viewport: one with CSS class name
+ * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with
+ * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent`
+ * option of {@link ol.Overlay} for the difference). The map itself is placed in
+ * a further element within the viewport, either DOM or Canvas, depending on the
+ * renderer.
+ *
+ * Layers are stored as a `ol.Collection` in layerGroups. A top-level group is
+ * provided by the library. This is what is accessed by `getLayerGroup` and
+ * `setLayerGroup`. Layers entered in the options are added to this group, and
+ * `addLayer` and `removeLayer` change the layer collection in the group.
+ * `getLayers` is a convenience function for `getLayerGroup().getLayers()`.
+ * Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers
+ * entered in the options or added with `addLayer` can be groups, which can
+ * contain further groups, and so on.
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {olx.MapOptions} options Map options.
+ * @fires ol.MapBrowserEvent
+ * @fires ol.MapEvent
+ * @fires ol.render.Event#postcompose
+ * @fires ol.render.Event#precompose
+ * @api stable
+ */
+ol.Map = function(options) {
+
+ ol.Object.call(this);
+
+ var optionsInternal = ol.Map.createOptionsInternal(options);
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.loadTilesWhileAnimating_ =
+ options.loadTilesWhileAnimating !== undefined ?
+ options.loadTilesWhileAnimating : false;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.loadTilesWhileInteracting_ =
+ options.loadTilesWhileInteracting !== undefined ?
+ options.loadTilesWhileInteracting : false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.pixelRatio_ = options.pixelRatio !== undefined ?
+ options.pixelRatio : ol.has.DEVICE_PIXEL_RATIO;
+
+ /**
+ * @private
+ * @type {Object.<string, string>}
+ */
+ this.logos_ = optionsInternal.logos;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.animationDelayKey_;
+
+ /**
+ * @private
+ */
+ this.animationDelay_ = function() {
+ this.animationDelayKey_ = undefined;
+ this.renderFrame_.call(this, Date.now());
+ }.bind(this);
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @private
+ * @type {goog.vec.Mat4.Number}
+ */
+ this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber();
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.frameIndex_ = 0;
+
+ /**
+ * @private
+ * @type {?olx.FrameState}
+ */
+ this.frameState_ = null;
+
+ /**
+ * The extent at the previous 'moveend' event.
+ * @private
+ * @type {ol.Extent}
+ */
+ this.previousExtent_ = ol.extent.createEmpty();
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.viewPropertyListenerKey_ = null;
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.layerGroupPropertyListenerKeys_ = null;
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.viewport_ = document.createElement('DIV');
+ this.viewport_.className = 'ol-viewport' + (ol.has.TOUCH ? ' ol-touch' : '');
+ this.viewport_.style.position = 'relative';
+ this.viewport_.style.overflow = 'hidden';
+ this.viewport_.style.width = '100%';
+ this.viewport_.style.height = '100%';
+ // prevent page zoom on IE >= 10 browsers
+ this.viewport_.style.msTouchAction = 'none';
+ this.viewport_.style.touchAction = 'none';
+
+ /**
+ * @private
+ * @type {!Element}
+ */
+ this.overlayContainer_ = document.createElement('DIV');
+ this.overlayContainer_.className = 'ol-overlaycontainer';
+ this.viewport_.appendChild(this.overlayContainer_);
+
+ /**
+ * @private
+ * @type {!Element}
+ */
+ this.overlayContainerStopEvent_ = document.createElement('DIV');
+ this.overlayContainerStopEvent_.className = 'ol-overlaycontainer-stopevent';
+ var overlayEvents = [
+ ol.events.EventType.CLICK,
+ ol.events.EventType.DBLCLICK,
+ ol.events.EventType.MOUSEDOWN,
+ ol.events.EventType.TOUCHSTART,
+ ol.events.EventType.MSPOINTERDOWN,
+ ol.MapBrowserEvent.EventType.POINTERDOWN,
+ ol.events.EventType.MOUSEWHEEL,
+ ol.events.EventType.WHEEL
+ ];
+ for (var i = 0, ii = overlayEvents.length; i < ii; ++i) {
+ ol.events.listen(this.overlayContainerStopEvent_, overlayEvents[i],
+ ol.events.Event.stopPropagation);
+ }
+ this.viewport_.appendChild(this.overlayContainerStopEvent_);
+
+ /**
+ * @private
+ * @type {ol.MapBrowserEventHandler}
+ */
+ this.mapBrowserEventHandler_ = new ol.MapBrowserEventHandler(this);
+ for (var key in ol.MapBrowserEvent.EventType) {
+ ol.events.listen(this.mapBrowserEventHandler_, ol.MapBrowserEvent.EventType[key],
+ this.handleMapBrowserEvent, this);
+ }
+
+ /**
+ * @private
+ * @type {Element|Document}
+ */
+ this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget;
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.keyHandlerKeys_ = null;
+
+ ol.events.listen(this.viewport_, ol.events.EventType.WHEEL,
+ this.handleBrowserEvent, this);
+ ol.events.listen(this.viewport_, ol.events.EventType.MOUSEWHEEL,
+ this.handleBrowserEvent, this);
+
+ /**
+ * @type {ol.Collection.<ol.control.Control>}
+ * @private
+ */
+ this.controls_ = optionsInternal.controls;
+
+ /**
+ * @type {ol.Collection.<ol.interaction.Interaction>}
+ * @private
+ */
+ this.interactions_ = optionsInternal.interactions;
+
+ /**
+ * @type {ol.Collection.<ol.Overlay>}
+ * @private
+ */
+ this.overlays_ = optionsInternal.overlays;
+
+ /**
+ * A lookup of overlays by id.
+ * @private
+ * @type {Object.<string, ol.Overlay>}
+ */
+ this.overlayIdIndex_ = {};
+
+ /**
+ * @type {ol.renderer.Map}
+ * @private
+ */
+ this.renderer_ = new optionsInternal.rendererConstructor(this.viewport_, this);
+
+ /**
+ * @type {function(Event)|undefined}
+ * @private
+ */
+ this.handleResize_;
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.focus_ = null;
+
+ /**
+ * @private
+ * @type {Array.<ol.PreRenderFunction>}
+ */
+ this.preRenderFunctions_ = [];
+
+ /**
+ * @private
+ * @type {Array.<ol.PostRenderFunction>}
+ */
+ this.postRenderFunctions_ = [];
+
+ /**
+ * @private
+ * @type {ol.TileQueue}
+ */
+ this.tileQueue_ = new ol.TileQueue(
+ this.getTilePriority.bind(this),
+ this.handleTileChange_.bind(this));
+
+ /**
+ * Uids of features to skip at rendering time.
+ * @type {Object.<string, boolean>}
+ * @private
+ */
+ this.skippedFeatureUids_ = {};
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.MapProperty.LAYERGROUP),
+ this.handleLayerGroupChanged_, this);
+ ol.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.VIEW),
+ this.handleViewChanged_, this);
+ ol.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.SIZE),
+ this.handleSizeChanged_, this);
+ ol.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.TARGET),
+ this.handleTargetChanged_, this);
+
+ // setProperties will trigger the rendering of the map if the map
+ // is "defined" already.
+ this.setProperties(optionsInternal.values);
+
+ this.controls_.forEach(
+ /**
+ * @param {ol.control.Control} control Control.
+ * @this {ol.Map}
+ */
+ function(control) {
+ control.setMap(this);
+ }, this);
+
+ ol.events.listen(this.controls_, ol.CollectionEventType.ADD,
+ /**
+ * @param {ol.CollectionEvent} event Collection event.
+ */
+ function(event) {
+ event.element.setMap(this);
+ }, this);
+
+ ol.events.listen(this.controls_, ol.CollectionEventType.REMOVE,
+ /**
+ * @param {ol.CollectionEvent} event Collection event.
+ */
+ function(event) {
+ event.element.setMap(null);
+ }, this);
+
+ this.interactions_.forEach(
+ /**
+ * @param {ol.interaction.Interaction} interaction Interaction.
+ * @this {ol.Map}
+ */
+ function(interaction) {
+ interaction.setMap(this);
+ }, this);
+
+ ol.events.listen(this.interactions_, ol.CollectionEventType.ADD,
+ /**
+ * @param {ol.CollectionEvent} event Collection event.
+ */
+ function(event) {
+ event.element.setMap(this);
+ }, this);
+
+ ol.events.listen(this.interactions_, ol.CollectionEventType.REMOVE,
+ /**
+ * @param {ol.CollectionEvent} event Collection event.
+ */
+ function(event) {
+ event.element.setMap(null);
+ }, this);
+
+ this.overlays_.forEach(this.addOverlayInternal_, this);
+
+ ol.events.listen(this.overlays_, ol.CollectionEventType.ADD,
+ /**
+ * @param {ol.CollectionEvent} event Collection event.
+ */
+ function(event) {
+ this.addOverlayInternal_(/** @type {ol.Overlay} */ (event.element));
+ }, this);
+
+ ol.events.listen(this.overlays_, ol.CollectionEventType.REMOVE,
+ /**
+ * @param {ol.CollectionEvent} event Collection event.
+ */
+ function(event) {
+ var id = event.element.getId();
+ if (id !== undefined) {
+ delete this.overlayIdIndex_[id.toString()];
+ }
+ event.element.setMap(null);
+ }, this);
+
+};
+ol.inherits(ol.Map, ol.Object);
+
+
+/**
+ * Add the given control to the map.
+ * @param {ol.control.Control} control Control.
+ * @api stable
+ */
+ol.Map.prototype.addControl = function(control) {
+ var controls = this.getControls();
+ goog.asserts.assert(controls !== undefined, 'controls should be defined');
+ controls.push(control);
+};
+
+
+/**
+ * Add the given interaction to the map.
+ * @param {ol.interaction.Interaction} interaction Interaction to add.
+ * @api stable
+ */
+ol.Map.prototype.addInteraction = function(interaction) {
+ var interactions = this.getInteractions();
+ goog.asserts.assert(interactions !== undefined,
+ 'interactions should be defined');
+ interactions.push(interaction);
+};
+
+
+/**
+ * Adds the given layer to the top of this map. If you want to add a layer
+ * elsewhere in the stack, use `getLayers()` and the methods available on
+ * {@link ol.Collection}.
+ * @param {ol.layer.Base} layer Layer.
+ * @api stable
+ */
+ol.Map.prototype.addLayer = function(layer) {
+ var layers = this.getLayerGroup().getLayers();
+ layers.push(layer);
+};
+
+
+/**
+ * Add the given overlay to the map.
+ * @param {ol.Overlay} overlay Overlay.
+ * @api stable
+ */
+ol.Map.prototype.addOverlay = function(overlay) {
+ var overlays = this.getOverlays();
+ goog.asserts.assert(overlays !== undefined, 'overlays should be defined');
+ overlays.push(overlay);
+};
+
+
+/**
+ * This deals with map's overlay collection changes.
+ * @param {ol.Overlay} overlay Overlay.
+ * @private
+ */
+ol.Map.prototype.addOverlayInternal_ = function(overlay) {
+ var id = overlay.getId();
+ if (id !== undefined) {
+ this.overlayIdIndex_[id.toString()] = overlay;
+ }
+ overlay.setMap(this);
+};
+
+
+/**
+ * Add functions to be called before rendering. This can be used for attaching
+ * animations before updating the map's view. The {@link ol.animation}
+ * namespace provides several static methods for creating prerender functions.
+ * @param {...ol.PreRenderFunction} var_args Any number of pre-render functions.
+ * @api
+ */
+ol.Map.prototype.beforeRender = function(var_args) {
+ this.render();
+ Array.prototype.push.apply(this.preRenderFunctions_, arguments);
+};
+
+
+/**
+ * @param {ol.PreRenderFunction} preRenderFunction Pre-render function.
+ * @return {boolean} Whether the preRenderFunction has been found and removed.
+ */
+ol.Map.prototype.removePreRenderFunction = function(preRenderFunction) {
+ return ol.array.remove(this.preRenderFunctions_, preRenderFunction);
+};
+
+
+/**
+ *
+ * @inheritDoc
+ */
+ol.Map.prototype.disposeInternal = function() {
+ this.mapBrowserEventHandler_.dispose();
+ this.renderer_.dispose();
+ ol.events.unlisten(this.viewport_, ol.events.EventType.WHEEL,
+ this.handleBrowserEvent, this);
+ ol.events.unlisten(this.viewport_, ol.events.EventType.MOUSEWHEEL,
+ this.handleBrowserEvent, this);
+ if (this.handleResize_ !== undefined) {
+ ol.global.removeEventListener(ol.events.EventType.RESIZE,
+ this.handleResize_, false);
+ this.handleResize_ = undefined;
+ }
+ if (this.animationDelayKey_) {
+ ol.global.cancelAnimationFrame(this.animationDelayKey_);
+ this.animationDelayKey_ = undefined;
+ }
+ this.setTarget(null);
+ ol.Object.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * Detect features that intersect a pixel on the viewport, and execute a
+ * callback with each intersecting feature. Layers included in the detection can
+ * be configured through `opt_layerFilter`.
+ * @param {ol.Pixel} pixel Pixel.
+ * @param {function(this: S, (ol.Feature|ol.render.Feature),
+ * ol.layer.Layer): T} callback Feature callback. The callback will be
+ * called with two arguments. The first argument is one
+ * {@link ol.Feature feature} or
+ * {@link ol.render.Feature render feature} at the pixel, the second is
+ * the {@link ol.layer.Layer layer} of the feature and will be null for
+ * unmanaged layers. To stop detection, callback functions can return a
+ * truthy value.
+ * @param {S=} opt_this Value to use as `this` when executing `callback`.
+ * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
+ * filter function. The filter function will receive one argument, the
+ * {@link ol.layer.Layer layer-candidate} and it should return a boolean
+ * value. Only layers which are visible and for which this function returns
+ * `true` will be tested for features. By default, all visible layers will
+ * be tested.
+ * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
+ * @return {T|undefined} Callback result, i.e. the return value of last
+ * callback execution, or the first truthy callback return value.
+ * @template S,T,U
+ * @api stable
+ */
+ol.Map.prototype.forEachFeatureAtPixel = function(pixel, callback, opt_this, opt_layerFilter, opt_this2) {
+ if (!this.frameState_) {
+ return;
+ }
+ var coordinate = this.getCoordinateFromPixel(pixel);
+ var thisArg = opt_this !== undefined ? opt_this : null;
+ var layerFilter = opt_layerFilter !== undefined ?
+ opt_layerFilter : ol.functions.TRUE;
+ var thisArg2 = opt_this2 !== undefined ? opt_this2 : null;
+ return this.renderer_.forEachFeatureAtCoordinate(
+ coordinate, this.frameState_, callback, thisArg,
+ layerFilter, thisArg2);
+};
+
+
+/**
+ * Detect layers that have a color value at a pixel on the viewport, and
+ * execute a callback with each matching layer. Layers included in the
+ * detection can be configured through `opt_layerFilter`.
+ * @param {ol.Pixel} pixel Pixel.
+ * @param {function(this: S, ol.layer.Layer): T} callback Layer
+ * callback. Will receive one argument, the {@link ol.layer.Layer layer}
+ * that contains the color pixel. To stop detection, callback functions can
+ * return a truthy value.
+ * @param {S=} opt_this Value to use as `this` when executing `callback`.
+ * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
+ * filter function. The filter function will receive one argument, the
+ * {@link ol.layer.Layer layer-candidate} and it should return a boolean
+ * value. Only layers which are visible and for which this function returns
+ * `true` will be tested for features. By default, all visible layers will
+ * be tested.
+ * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
+ * @return {T|undefined} Callback result, i.e. the return value of last
+ * callback execution, or the first truthy callback return value.
+ * @template S,T,U
+ * @api stable
+ */
+ol.Map.prototype.forEachLayerAtPixel = function(pixel, callback, opt_this, opt_layerFilter, opt_this2) {
+ if (!this.frameState_) {
+ return;
+ }
+ var thisArg = opt_this !== undefined ? opt_this : null;
+ var layerFilter = opt_layerFilter !== undefined ?
+ opt_layerFilter : ol.functions.TRUE;
+ var thisArg2 = opt_this2 !== undefined ? opt_this2 : null;
+ return this.renderer_.forEachLayerAtPixel(
+ pixel, this.frameState_, callback, thisArg,
+ layerFilter, thisArg2);
+};
+
+
+/**
+ * Detect if features intersect a pixel on the viewport. Layers included in the
+ * detection can be configured through `opt_layerFilter`.
+ * @param {ol.Pixel} pixel Pixel.
+ * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
+ * filter function. The filter function will receive one argument, the
+ * {@link ol.layer.Layer layer-candidate} and it should return a boolean
+ * value. Only layers which are visible and for which this function returns
+ * `true` will be tested for features. By default, all visible layers will
+ * be tested.
+ * @param {U=} opt_this Value to use as `this` when executing `layerFilter`.
+ * @return {boolean} Is there a feature at the given pixel?
+ * @template U
+ * @api
+ */
+ol.Map.prototype.hasFeatureAtPixel = function(pixel, opt_layerFilter, opt_this) {
+ if (!this.frameState_) {
+ return false;
+ }
+ var coordinate = this.getCoordinateFromPixel(pixel);
+ var layerFilter = opt_layerFilter !== undefined ?
+ opt_layerFilter : ol.functions.TRUE;
+ var thisArg = opt_this !== undefined ? opt_this : null;
+ return this.renderer_.hasFeatureAtCoordinate(
+ coordinate, this.frameState_, layerFilter, thisArg);
+};
+
+
+/**
+ * Returns the geographical coordinate for a browser event.
+ * @param {Event} event Event.
+ * @return {ol.Coordinate} Coordinate.
+ * @api stable
+ */
+ol.Map.prototype.getEventCoordinate = function(event) {
+ return this.getCoordinateFromPixel(this.getEventPixel(event));
+};
+
+
+/**
+ * Returns the map pixel position for a browser event relative to the viewport.
+ * @param {Event} event Event.
+ * @return {ol.Pixel} Pixel.
+ * @api stable
+ */
+ol.Map.prototype.getEventPixel = function(event) {
+ var viewportPosition = this.viewport_.getBoundingClientRect();
+ var eventPosition = event.changedTouches ? event.changedTouches[0] : event;
+ return [
+ eventPosition.clientX - viewportPosition.left,
+ eventPosition.clientY - viewportPosition.top
+ ];
+};
+
+
+/**
+ * Get the target in which this map is rendered.
+ * Note that this returns what is entered as an option or in setTarget:
+ * if that was an element, it returns an element; if a string, it returns that.
+ * @return {Element|string|undefined} The Element or id of the Element that the
+ * map is rendered in.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.getTarget = function() {
+ return /** @type {Element|string|undefined} */ (
+ this.get(ol.MapProperty.TARGET));
+};
+
+
+/**
+ * Get the DOM element into which this map is rendered. In contrast to
+ * `getTarget` this method always return an `Element`, or `null` if the
+ * map has no target.
+ * @return {Element} The element that the map is rendered in.
+ * @api
+ */
+ol.Map.prototype.getTargetElement = function() {
+ var target = this.getTarget();
+ if (target !== undefined) {
+ return typeof target === 'string' ?
+ document.getElementById(target) :
+ target;
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * Get the coordinate for a given pixel. This returns a coordinate in the
+ * map view projection.
+ * @param {ol.Pixel} pixel Pixel position in the map viewport.
+ * @return {ol.Coordinate} The coordinate for the pixel position.
+ * @api stable
+ */
+ol.Map.prototype.getCoordinateFromPixel = function(pixel) {
+ var frameState = this.frameState_;
+ if (!frameState) {
+ return null;
+ } else {
+ var vec2 = pixel.slice();
+ return ol.vec.Mat4.multVec2(frameState.pixelToCoordinateMatrix, vec2, vec2);
+ }
+};
+
+
+/**
+ * Get the map controls. Modifying this collection changes the controls
+ * associated with the map.
+ * @return {ol.Collection.<ol.control.Control>} Controls.
+ * @api stable
+ */
+ol.Map.prototype.getControls = function() {
+ return this.controls_;
+};
+
+
+/**
+ * Get the map overlays. Modifying this collection changes the overlays
+ * associated with the map.
+ * @return {ol.Collection.<ol.Overlay>} Overlays.
+ * @api stable
+ */
+ol.Map.prototype.getOverlays = function() {
+ return this.overlays_;
+};
+
+
+/**
+ * Get an overlay by its identifier (the value returned by overlay.getId()).
+ * Note that the index treats string and numeric identifiers as the same. So
+ * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`.
+ * @param {string|number} id Overlay identifier.
+ * @return {ol.Overlay} Overlay.
+ * @api
+ */
+ol.Map.prototype.getOverlayById = function(id) {
+ var overlay = this.overlayIdIndex_[id.toString()];
+ return overlay !== undefined ? overlay : null;
+};
+
+
+/**
+ * Get the map interactions. Modifying this collection changes the interactions
+ * associated with the map.
+ *
+ * Interactions are used for e.g. pan, zoom and rotate.
+ * @return {ol.Collection.<ol.interaction.Interaction>} Interactions.
+ * @api stable
+ */
+ol.Map.prototype.getInteractions = function() {
+ return this.interactions_;
+};
+
+
+/**
+ * Get the layergroup associated with this map.
+ * @return {ol.layer.Group} A layer group containing the layers in this map.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.getLayerGroup = function() {
+ return /** @type {ol.layer.Group} */ (this.get(ol.MapProperty.LAYERGROUP));
+};
+
+
+/**
+ * Get the collection of layers associated with this map.
+ * @return {!ol.Collection.<ol.layer.Base>} Layers.
+ * @api stable
+ */
+ol.Map.prototype.getLayers = function() {
+ var layers = this.getLayerGroup().getLayers();
+ return layers;
+};
+
+
+/**
+ * Get the pixel for a coordinate. This takes a coordinate in the map view
+ * projection and returns the corresponding pixel.
+ * @param {ol.Coordinate} coordinate A map coordinate.
+ * @return {ol.Pixel} A pixel position in the map viewport.
+ * @api stable
+ */
+ol.Map.prototype.getPixelFromCoordinate = function(coordinate) {
+ var frameState = this.frameState_;
+ if (!frameState) {
+ return null;
+ } else {
+ var vec2 = coordinate.slice(0, 2);
+ return ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, vec2, vec2);
+ }
+};
+
+
+/**
+ * Get the map renderer.
+ * @return {ol.renderer.Map} Renderer
+ */
+ol.Map.prototype.getRenderer = function() {
+ return this.renderer_;
+};
+
+
+/**
+ * Get the size of this map.
+ * @return {ol.Size|undefined} The size in pixels of the map in the DOM.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.getSize = function() {
+ return /** @type {ol.Size|undefined} */ (this.get(ol.MapProperty.SIZE));
+};
+
+
+/**
+ * Get the view associated with this map. A view manages properties such as
+ * center and resolution.
+ * @return {ol.View} The view that controls this map.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.getView = function() {
+ return /** @type {ol.View} */ (this.get(ol.MapProperty.VIEW));
+};
+
+
+/**
+ * Get the element that serves as the map viewport.
+ * @return {Element} Viewport.
+ * @api stable
+ */
+ol.Map.prototype.getViewport = function() {
+ return this.viewport_;
+};
+
+
+/**
+ * Get the element that serves as the container for overlays. Elements added to
+ * this container will let mousedown and touchstart events through to the map,
+ * so clicks and gestures on an overlay will trigger {@link ol.MapBrowserEvent}
+ * events.
+ * @return {!Element} The map's overlay container.
+ */
+ol.Map.prototype.getOverlayContainer = function() {
+ return this.overlayContainer_;
+};
+
+
+/**
+ * Get the element that serves as a container for overlays that don't allow
+ * event propagation. Elements added to this container won't let mousedown and
+ * touchstart events through to the map, so clicks and gestures on an overlay
+ * don't trigger any {@link ol.MapBrowserEvent}.
+ * @return {!Element} The map's overlay container that stops events.
+ */
+ol.Map.prototype.getOverlayContainerStopEvent = function() {
+ return this.overlayContainerStopEvent_;
+};
+
+
+/**
+ * @param {ol.Tile} tile Tile.
+ * @param {string} tileSourceKey Tile source key.
+ * @param {ol.Coordinate} tileCenter Tile center.
+ * @param {number} tileResolution Tile resolution.
+ * @return {number} Tile priority.
+ */
+ol.Map.prototype.getTilePriority = function(tile, tileSourceKey, tileCenter, tileResolution) {
+ // Filter out tiles at higher zoom levels than the current zoom level, or that
+ // are outside the visible extent.
+ var frameState = this.frameState_;
+ if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {
+ return ol.structs.PriorityQueue.DROP;
+ }
+ var coordKey = tile.tileCoord.toString();
+ if (!frameState.wantedTiles[tileSourceKey][coordKey]) {
+ return ol.structs.PriorityQueue.DROP;
+ }
+ // Prioritize the highest zoom level tiles closest to the focus.
+ // Tiles at higher zoom levels are prioritized using Math.log(tileResolution).
+ // Within a zoom level, tiles are prioritized by the distance in pixels
+ // between the center of the tile and the focus. The factor of 65536 means
+ // that the prioritization should behave as desired for tiles up to
+ // 65536 * Math.log(2) = 45426 pixels from the focus.
+ var deltaX = tileCenter[0] - frameState.focus[0];
+ var deltaY = tileCenter[1] - frameState.focus[1];
+ return 65536 * Math.log(tileResolution) +
+ Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
+};
+
+
+/**
+ * @param {Event} browserEvent Browser event.
+ * @param {string=} opt_type Type.
+ */
+ol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) {
+ var type = opt_type || browserEvent.type;
+ var mapBrowserEvent = new ol.MapBrowserEvent(type, this, browserEvent);
+ this.handleMapBrowserEvent(mapBrowserEvent);
+};
+
+
+/**
+ * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.
+ */
+ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {
+ if (!this.frameState_) {
+ // With no view defined, we cannot translate pixels into geographical
+ // coordinates so interactions cannot be used.
+ return;
+ }
+ this.focus_ = mapBrowserEvent.coordinate;
+ mapBrowserEvent.frameState = this.frameState_;
+ var interactions = this.getInteractions();
+ goog.asserts.assert(interactions !== undefined,
+ 'interactions should be defined');
+ var interactionsArray = interactions.getArray();
+ var i;
+ if (this.dispatchEvent(mapBrowserEvent) !== false) {
+ for (i = interactionsArray.length - 1; i >= 0; i--) {
+ var interaction = interactionsArray[i];
+ if (!interaction.getActive()) {
+ continue;
+ }
+ var cont = interaction.handleEvent(mapBrowserEvent);
+ if (!cont) {
+ break;
+ }
+ }
+ }
+};
+
+
+/**
+ * @protected
+ */
+ol.Map.prototype.handlePostRender = function() {
+
+ var frameState = this.frameState_;
+
+ // Manage the tile queue
+ // Image loads are expensive and a limited resource, so try to use them
+ // efficiently:
+ // * When the view is static we allow a large number of parallel tile loads
+ // to complete the frame as quickly as possible.
+ // * When animating or interacting, image loads can cause janks, so we reduce
+ // the maximum number of loads per frame and limit the number of parallel
+ // tile loads to remain reactive to view changes and to reduce the chance of
+ // loading tiles that will quickly disappear from view.
+ var tileQueue = this.tileQueue_;
+ if (!tileQueue.isEmpty()) {
+ var maxTotalLoading = 16;
+ var maxNewLoads = maxTotalLoading;
+ if (frameState) {
+ var hints = frameState.viewHints;
+ if (hints[ol.ViewHint.ANIMATING]) {
+ maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0;
+ maxNewLoads = 2;
+ }
+ if (hints[ol.ViewHint.INTERACTING]) {
+ maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0;
+ maxNewLoads = 2;
+ }
+ }
+ if (tileQueue.getTilesLoading() < maxTotalLoading) {
+ tileQueue.reprioritize(); // FIXME only call if view has changed
+ tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);
+ }
+ }
+
+ var postRenderFunctions = this.postRenderFunctions_;
+ var i, ii;
+ for (i = 0, ii = postRenderFunctions.length; i < ii; ++i) {
+ postRenderFunctions[i](this, frameState);
+ }
+ postRenderFunctions.length = 0;
+};
+
+
+/**
+ * @private
+ */
+ol.Map.prototype.handleSizeChanged_ = function() {
+ this.render();
+};
+
+
+/**
+ * @private
+ */
+ol.Map.prototype.handleTargetChanged_ = function() {
+ // target may be undefined, null, a string or an Element.
+ // If it's a string we convert it to an Element before proceeding.
+ // If it's not now an Element we remove the viewport from the DOM.
+ // If it's an Element we append the viewport element to it.
+
+ var targetElement;
+ if (this.getTarget()) {
+ targetElement = this.getTargetElement();
+ goog.asserts.assert(targetElement !== null,
+ 'expects a non-null value for targetElement');
+ }
+
+ if (this.keyHandlerKeys_) {
+ for (var i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
+ ol.events.unlistenByKey(this.keyHandlerKeys_[i]);
+ }
+ this.keyHandlerKeys_ = null;
+ }
+
+ if (!targetElement) {
+ ol.dom.removeNode(this.viewport_);
+ if (this.handleResize_ !== undefined) {
+ ol.global.removeEventListener(ol.events.EventType.RESIZE,
+ this.handleResize_, false);
+ this.handleResize_ = undefined;
+ }
+ } else {
+ targetElement.appendChild(this.viewport_);
+
+ var keyboardEventTarget = !this.keyboardEventTarget_ ?
+ targetElement : this.keyboardEventTarget_;
+ this.keyHandlerKeys_ = [
+ ol.events.listen(keyboardEventTarget, ol.events.EventType.KEYDOWN,
+ this.handleBrowserEvent, this),
+ ol.events.listen(keyboardEventTarget, ol.events.EventType.KEYPRESS,
+ this.handleBrowserEvent, this)
+ ];
+
+ if (!this.handleResize_) {
+ this.handleResize_ = this.updateSize.bind(this);
+ ol.global.addEventListener(ol.events.EventType.RESIZE,
+ this.handleResize_, false);
+ }
+ }
+
+ this.updateSize();
+ // updateSize calls setSize, so no need to call this.render
+ // ourselves here.
+};
+
+
+/**
+ * @private
+ */
+ol.Map.prototype.handleTileChange_ = function() {
+ this.render();
+};
+
+
+/**
+ * @private
+ */
+ol.Map.prototype.handleViewPropertyChanged_ = function() {
+ this.render();
+};
+
+
+/**
+ * @private
+ */
+ol.Map.prototype.handleViewChanged_ = function() {
+ if (this.viewPropertyListenerKey_) {
+ ol.events.unlistenByKey(this.viewPropertyListenerKey_);
+ this.viewPropertyListenerKey_ = null;
+ }
+ var view = this.getView();
+ if (view) {
+ this.viewPropertyListenerKey_ = ol.events.listen(
+ view, ol.ObjectEventType.PROPERTYCHANGE,
+ this.handleViewPropertyChanged_, this);
+ }
+ this.render();
+};
+
+
+/**
+ * @param {ol.events.Event} event Event.
+ * @private
+ */
+ol.Map.prototype.handleLayerGroupMemberChanged_ = function(event) {
+ goog.asserts.assertInstanceof(event, ol.events.Event,
+ 'event should be an Event');
+ this.render();
+};
+
+
+/**
+ * @param {ol.ObjectEvent} event Event.
+ * @private
+ */
+ol.Map.prototype.handleLayerGroupPropertyChanged_ = function(event) {
+ goog.asserts.assertInstanceof(event, ol.ObjectEvent,
+ 'event should be an ol.ObjectEvent');
+ this.render();
+};
+
+
+/**
+ * @private
+ */
+ol.Map.prototype.handleLayerGroupChanged_ = function() {
+ if (this.layerGroupPropertyListenerKeys_) {
+ this.layerGroupPropertyListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.layerGroupPropertyListenerKeys_ = null;
+ }
+ var layerGroup = this.getLayerGroup();
+ if (layerGroup) {
+ this.layerGroupPropertyListenerKeys_ = [
+ ol.events.listen(
+ layerGroup, ol.ObjectEventType.PROPERTYCHANGE,
+ this.handleLayerGroupPropertyChanged_, this),
+ ol.events.listen(
+ layerGroup, ol.events.EventType.CHANGE,
+ this.handleLayerGroupMemberChanged_, this)
+ ];
+ }
+ this.render();
+};
+
+
+/**
+ * @return {boolean} Is rendered.
+ */
+ol.Map.prototype.isRendered = function() {
+ return !!this.frameState_;
+};
+
+
+/**
+ * Requests an immediate render in a synchronous manner.
+ * @api stable
+ */
+ol.Map.prototype.renderSync = function() {
+ if (this.animationDelayKey_) {
+ ol.global.cancelAnimationFrame(this.animationDelayKey_);
+ }
+ this.animationDelay_();
+};
+
+
+/**
+ * Request a map rendering (at the next animation frame).
+ * @api stable
+ */
+ol.Map.prototype.render = function() {
+ if (this.animationDelayKey_ === undefined) {
+ this.animationDelayKey_ = ol.global.requestAnimationFrame(
+ this.animationDelay_);
+ }
+};
+
+
+/**
+ * Remove the given control from the map.
+ * @param {ol.control.Control} control Control.
+ * @return {ol.control.Control|undefined} The removed control (or undefined
+ * if the control was not found).
+ * @api stable
+ */
+ol.Map.prototype.removeControl = function(control) {
+ var controls = this.getControls();
+ goog.asserts.assert(controls !== undefined, 'controls should be defined');
+ return controls.remove(control);
+};
+
+
+/**
+ * Remove the given interaction from the map.
+ * @param {ol.interaction.Interaction} interaction Interaction to remove.
+ * @return {ol.interaction.Interaction|undefined} The removed interaction (or
+ * undefined if the interaction was not found).
+ * @api stable
+ */
+ol.Map.prototype.removeInteraction = function(interaction) {
+ var interactions = this.getInteractions();
+ goog.asserts.assert(interactions !== undefined,
+ 'interactions should be defined');
+ return interactions.remove(interaction);
+};
+
+
+/**
+ * Removes the given layer from the map.
+ * @param {ol.layer.Base} layer Layer.
+ * @return {ol.layer.Base|undefined} The removed layer (or undefined if the
+ * layer was not found).
+ * @api stable
+ */
+ol.Map.prototype.removeLayer = function(layer) {
+ var layers = this.getLayerGroup().getLayers();
+ return layers.remove(layer);
+};
+
+
+/**
+ * Remove the given overlay from the map.
+ * @param {ol.Overlay} overlay Overlay.
+ * @return {ol.Overlay|undefined} The removed overlay (or undefined
+ * if the overlay was not found).
+ * @api stable
+ */
+ol.Map.prototype.removeOverlay = function(overlay) {
+ var overlays = this.getOverlays();
+ goog.asserts.assert(overlays !== undefined, 'overlays should be defined');
+ return overlays.remove(overlay);
+};
+
+
+/**
+ * @param {number} time Time.
+ * @private
+ */
+ol.Map.prototype.renderFrame_ = function(time) {
+
+ var i, ii, viewState;
+
+ var size = this.getSize();
+ var view = this.getView();
+ var extent = ol.extent.createEmpty();
+ /** @type {?olx.FrameState} */
+ var frameState = null;
+ if (size !== undefined && ol.size.hasArea(size) && view && view.isDef()) {
+ var viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);
+ var layerStatesArray = this.getLayerGroup().getLayerStatesArray();
+ var layerStates = {};
+ for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
+ layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];
+ }
+ viewState = view.getState();
+ frameState = /** @type {olx.FrameState} */ ({
+ animate: false,
+ attributions: {},
+ coordinateToPixelMatrix: this.coordinateToPixelMatrix_,
+ extent: extent,
+ focus: !this.focus_ ? viewState.center : this.focus_,
+ index: this.frameIndex_++,
+ layerStates: layerStates,
+ layerStatesArray: layerStatesArray,
+ logos: ol.object.assign({}, this.logos_),
+ pixelRatio: this.pixelRatio_,
+ pixelToCoordinateMatrix: this.pixelToCoordinateMatrix_,
+ postRenderFunctions: [],
+ size: size,
+ skippedFeatureUids: this.skippedFeatureUids_,
+ tileQueue: this.tileQueue_,
+ time: time,
+ usedTiles: {},
+ viewState: viewState,
+ viewHints: viewHints,
+ wantedTiles: {}
+ });
+ }
+
+ if (frameState) {
+ var preRenderFunctions = this.preRenderFunctions_;
+ var n = 0, preRenderFunction;
+ for (i = 0, ii = preRenderFunctions.length; i < ii; ++i) {
+ preRenderFunction = preRenderFunctions[i];
+ if (preRenderFunction(this, frameState)) {
+ preRenderFunctions[n++] = preRenderFunction;
+ }
+ }
+ preRenderFunctions.length = n;
+
+ frameState.extent = ol.extent.getForViewAndSize(viewState.center,
+ viewState.resolution, viewState.rotation, frameState.size, extent);
+ }
+
+ this.frameState_ = frameState;
+ this.renderer_.renderFrame(frameState);
+
+ if (frameState) {
+ if (frameState.animate) {
+ this.render();
+ }
+ Array.prototype.push.apply(
+ this.postRenderFunctions_, frameState.postRenderFunctions);
+
+ var idle = this.preRenderFunctions_.length === 0 &&
+ !frameState.viewHints[ol.ViewHint.ANIMATING] &&
+ !frameState.viewHints[ol.ViewHint.INTERACTING] &&
+ !ol.extent.equals(frameState.extent, this.previousExtent_);
+
+ if (idle) {
+ this.dispatchEvent(
+ new ol.MapEvent(ol.MapEventType.MOVEEND, this, frameState));
+ ol.extent.clone(frameState.extent, this.previousExtent_);
+ }
+ }
+
+ this.dispatchEvent(
+ new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState));
+
+ goog.async.nextTick(this.handlePostRender, this);
+
+};
+
+
+/**
+ * Sets the layergroup of this map.
+ * @param {ol.layer.Group} layerGroup A layer group containing the layers in
+ * this map.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.setLayerGroup = function(layerGroup) {
+ this.set(ol.MapProperty.LAYERGROUP, layerGroup);
+};
+
+
+/**
+ * Set the size of this map.
+ * @param {ol.Size|undefined} size The size in pixels of the map in the DOM.
+ * @observable
+ * @api
+ */
+ol.Map.prototype.setSize = function(size) {
+ this.set(ol.MapProperty.SIZE, size);
+};
+
+
+/**
+ * Set the target element to render this map into.
+ * @param {Element|string|undefined} target The Element or id of the Element
+ * that the map is rendered in.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.setTarget = function(target) {
+ this.set(ol.MapProperty.TARGET, target);
+};
+
+
+/**
+ * Set the view for this map.
+ * @param {ol.View} view The view that controls this map.
+ * @observable
+ * @api stable
+ */
+ol.Map.prototype.setView = function(view) {
+ this.set(ol.MapProperty.VIEW, view);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ */
+ol.Map.prototype.skipFeature = function(feature) {
+ var featureUid = goog.getUid(feature).toString();
+ this.skippedFeatureUids_[featureUid] = true;
+ this.render();
+};
+
+
+/**
+ * Force a recalculation of the map viewport size. This should be called when
+ * third-party code changes the size of the map viewport.
+ * @api stable
+ */
+ol.Map.prototype.updateSize = function() {
+ var targetElement = this.getTargetElement();
+
+ if (!targetElement) {
+ this.setSize(undefined);
+ } else {
+ var computedStyle = ol.global.getComputedStyle(targetElement);
+ this.setSize([
+ targetElement.offsetWidth -
+ parseFloat(computedStyle['borderLeftWidth']) -
+ parseFloat(computedStyle['paddingLeft']) -
+ parseFloat(computedStyle['paddingRight']) -
+ parseFloat(computedStyle['borderRightWidth']),
+ targetElement.offsetHeight -
+ parseFloat(computedStyle['borderTopWidth']) -
+ parseFloat(computedStyle['paddingTop']) -
+ parseFloat(computedStyle['paddingBottom']) -
+ parseFloat(computedStyle['borderBottomWidth'])
+ ]);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ */
+ol.Map.prototype.unskipFeature = function(feature) {
+ var featureUid = goog.getUid(feature).toString();
+ delete this.skippedFeatureUids_[featureUid];
+ this.render();
+};
+
+
+/**
+ * @param {olx.MapOptions} options Map options.
+ * @return {ol.MapOptionsInternal} Internal map options.
+ */
+ol.Map.createOptionsInternal = function(options) {
+
+ /**
+ * @type {Element|Document}
+ */
+ var keyboardEventTarget = null;
+ if (options.keyboardEventTarget !== undefined) {
+ keyboardEventTarget = typeof options.keyboardEventTarget === 'string' ?
+ document.getElementById(options.keyboardEventTarget) :
+ options.keyboardEventTarget;
+ }
+
+ /**
+ * @type {Object.<string, *>}
+ */
+ var values = {};
+
+ var logos = {};
+ if (options.logo === undefined ||
+ (typeof options.logo === 'boolean' && options.logo)) {
+ logos[ol.OL3_LOGO_URL] = ol.OL3_URL;
+ } else {
+ var logo = options.logo;
+ if (typeof logo === 'string') {
+ logos[logo] = '';
+ } else if (logo instanceof HTMLElement) {
+ logos[goog.getUid(logo).toString()] = logo;
+ } else if (goog.isObject(logo)) {
+ goog.asserts.assertString(logo.href, 'logo.href should be a string');
+ goog.asserts.assertString(logo.src, 'logo.src should be a string');
+ logos[logo.src] = logo.href;
+ }
+ }
+
+ var layerGroup = (options.layers instanceof ol.layer.Group) ?
+ options.layers : new ol.layer.Group({layers: options.layers});
+ values[ol.MapProperty.LAYERGROUP] = layerGroup;
+
+ values[ol.MapProperty.TARGET] = options.target;
+
+ values[ol.MapProperty.VIEW] = options.view !== undefined ?
+ options.view : new ol.View();
+
+ /**
+ * @type {function(new: ol.renderer.Map, Element, ol.Map)}
+ */
+ var rendererConstructor = ol.renderer.Map;
+
+ /**
+ * @type {Array.<ol.RendererType>}
+ */
+ var rendererTypes;
+ if (options.renderer !== undefined) {
+ if (Array.isArray(options.renderer)) {
+ rendererTypes = options.renderer;
+ } else if (typeof options.renderer === 'string') {
+ rendererTypes = [options.renderer];
+ } else {
+ goog.asserts.fail('Incorrect format for renderer option');
+ }
+ } else {
+ rendererTypes = ol.DEFAULT_RENDERER_TYPES;
+ }
+
+ var i, ii;
+ for (i = 0, ii = rendererTypes.length; i < ii; ++i) {
+ /** @type {ol.RendererType} */
+ var rendererType = rendererTypes[i];
+ if (ol.ENABLE_CANVAS && rendererType == ol.RendererType.CANVAS) {
+ if (ol.has.CANVAS) {
+ rendererConstructor = ol.renderer.canvas.Map;
+ break;
+ }
+ } else if (ol.ENABLE_DOM && rendererType == ol.RendererType.DOM) {
+ if (ol.has.DOM) {
+ rendererConstructor = ol.renderer.dom.Map;
+ break;
+ }
+ } else if (ol.ENABLE_WEBGL && rendererType == ol.RendererType.WEBGL) {
+ if (ol.has.WEBGL) {
+ rendererConstructor = ol.renderer.webgl.Map;
+ break;
+ }
+ }
+ }
+
+ var controls;
+ if (options.controls !== undefined) {
+ if (Array.isArray(options.controls)) {
+ controls = new ol.Collection(options.controls.slice());
+ } else {
+ goog.asserts.assertInstanceof(options.controls, ol.Collection,
+ 'options.controls should be an ol.Collection');
+ controls = options.controls;
+ }
+ } else {
+ controls = ol.control.defaults();
+ }
+
+ var interactions;
+ if (options.interactions !== undefined) {
+ if (Array.isArray(options.interactions)) {
+ interactions = new ol.Collection(options.interactions.slice());
+ } else {
+ goog.asserts.assertInstanceof(options.interactions, ol.Collection,
+ 'options.interactions should be an ol.Collection');
+ interactions = options.interactions;
+ }
+ } else {
+ interactions = ol.interaction.defaults();
+ }
+
+ var overlays;
+ if (options.overlays !== undefined) {
+ if (Array.isArray(options.overlays)) {
+ overlays = new ol.Collection(options.overlays.slice());
+ } else {
+ goog.asserts.assertInstanceof(options.overlays, ol.Collection,
+ 'options.overlays should be an ol.Collection');
+ overlays = options.overlays;
+ }
+ } else {
+ overlays = new ol.Collection();
+ }
+
+ return {
+ controls: controls,
+ interactions: interactions,
+ keyboardEventTarget: keyboardEventTarget,
+ logos: logos,
+ overlays: overlays,
+ rendererConstructor: rendererConstructor,
+ values: values
+ };
+
+};
+
+
+ol.proj.common.add();
+
+goog.provide('ol.Overlay');
+goog.provide('ol.OverlayPositioning');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.Map');
+goog.require('ol.MapEventType');
+goog.require('ol.Object');
+goog.require('ol.animation');
+goog.require('ol.dom');
+goog.require('ol.extent');
+
+
+/**
+ * @enum {string}
+ */
+ol.OverlayProperty = {
+ ELEMENT: 'element',
+ MAP: 'map',
+ OFFSET: 'offset',
+ POSITION: 'position',
+ POSITIONING: 'positioning'
+};
+
+
+/**
+ * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`,
+ * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`,
+ * `'top-center'`, `'top-right'`
+ * @enum {string}
+ */
+ol.OverlayPositioning = {
+ BOTTOM_LEFT: 'bottom-left',
+ BOTTOM_CENTER: 'bottom-center',
+ BOTTOM_RIGHT: 'bottom-right',
+ CENTER_LEFT: 'center-left',
+ CENTER_CENTER: 'center-center',
+ CENTER_RIGHT: 'center-right',
+ TOP_LEFT: 'top-left',
+ TOP_CENTER: 'top-center',
+ TOP_RIGHT: 'top-right'
+};
+
+
+/**
+ * @classdesc
+ * An element to be displayed over the map and attached to a single map
+ * location. Like {@link ol.control.Control}, Overlays are visible widgets.
+ * Unlike Controls, they are not in a fixed position on the screen, but are tied
+ * to a geographical coordinate, so panning the map will move an Overlay but not
+ * a Control.
+ *
+ * Example:
+ *
+ * var popup = new ol.Overlay({
+ * element: document.getElementById('popup')
+ * });
+ * popup.setPosition(coordinate);
+ * map.addOverlay(popup);
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {olx.OverlayOptions} options Overlay options.
+ * @api stable
+ */
+ol.Overlay = function(options) {
+
+ ol.Object.call(this);
+
+ /**
+ * @private
+ * @type {number|string|undefined}
+ */
+ this.id_ = options.id;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.insertFirst_ = options.insertFirst !== undefined ?
+ options.insertFirst : true;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true;
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.element_ = document.createElement('DIV');
+ this.element_.className = 'ol-overlay-container';
+ this.element_.style.position = 'absolute';
+
+ /**
+ * @protected
+ * @type {boolean}
+ */
+ this.autoPan = options.autoPan !== undefined ? options.autoPan : false;
+
+ /**
+ * @private
+ * @type {olx.animation.PanOptions}
+ */
+ this.autoPanAnimation_ = options.autoPanAnimation !== undefined ?
+ options.autoPanAnimation : /** @type {olx.animation.PanOptions} */ ({});
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.autoPanMargin_ = options.autoPanMargin !== undefined ?
+ options.autoPanMargin : 20;
+
+ /**
+ * @private
+ * @type {{bottom_: string,
+ * left_: string,
+ * right_: string,
+ * top_: string,
+ * visible: boolean}}
+ */
+ this.rendered_ = {
+ bottom_: '',
+ left_: '',
+ right_: '',
+ top_: '',
+ visible: true
+ };
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.mapPostrenderListenerKey_ = null;
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT),
+ this.handleElementChanged, this);
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.OverlayProperty.MAP),
+ this.handleMapChanged, this);
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.OverlayProperty.OFFSET),
+ this.handleOffsetChanged, this);
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITION),
+ this.handlePositionChanged, this);
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.OverlayProperty.POSITIONING),
+ this.handlePositioningChanged, this);
+
+ if (options.element !== undefined) {
+ this.setElement(options.element);
+ }
+
+ this.setOffset(options.offset !== undefined ? options.offset : [0, 0]);
+
+ this.setPositioning(options.positioning !== undefined ?
+ /** @type {ol.OverlayPositioning} */ (options.positioning) :
+ ol.OverlayPositioning.TOP_LEFT);
+
+ if (options.position !== undefined) {
+ this.setPosition(options.position);
+ }
+
+};
+ol.inherits(ol.Overlay, ol.Object);
+
+
+/**
+ * Get the DOM element of this overlay.
+ * @return {Element|undefined} The Element containing the overlay.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.getElement = function() {
+ return /** @type {Element|undefined} */ (
+ this.get(ol.OverlayProperty.ELEMENT));
+};
+
+
+/**
+ * Get the overlay identifier which is set on constructor.
+ * @return {number|string|undefined} Id.
+ * @api
+ */
+ol.Overlay.prototype.getId = function() {
+ return this.id_;
+};
+
+
+/**
+ * Get the map associated with this overlay.
+ * @return {ol.Map|undefined} The map that the overlay is part of.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.getMap = function() {
+ return /** @type {ol.Map|undefined} */ (
+ this.get(ol.OverlayProperty.MAP));
+};
+
+
+/**
+ * Get the offset of this overlay.
+ * @return {Array.<number>} The offset.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.getOffset = function() {
+ return /** @type {Array.<number>} */ (
+ this.get(ol.OverlayProperty.OFFSET));
+};
+
+
+/**
+ * Get the current position of this overlay.
+ * @return {ol.Coordinate|undefined} The spatial point that the overlay is
+ * anchored at.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.getPosition = function() {
+ return /** @type {ol.Coordinate|undefined} */ (
+ this.get(ol.OverlayProperty.POSITION));
+};
+
+
+/**
+ * Get the current positioning of this overlay.
+ * @return {ol.OverlayPositioning} How the overlay is positioned
+ * relative to its point on the map.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.getPositioning = function() {
+ return /** @type {ol.OverlayPositioning} */ (
+ this.get(ol.OverlayProperty.POSITIONING));
+};
+
+
+/**
+ * @protected
+ */
+ol.Overlay.prototype.handleElementChanged = function() {
+ ol.dom.removeChildren(this.element_);
+ var element = this.getElement();
+ if (element) {
+ this.element_.appendChild(element);
+ }
+};
+
+
+/**
+ * @protected
+ */
+ol.Overlay.prototype.handleMapChanged = function() {
+ if (this.mapPostrenderListenerKey_) {
+ ol.dom.removeNode(this.element_);
+ ol.events.unlistenByKey(this.mapPostrenderListenerKey_);
+ this.mapPostrenderListenerKey_ = null;
+ }
+ var map = this.getMap();
+ if (map) {
+ this.mapPostrenderListenerKey_ = ol.events.listen(map,
+ ol.MapEventType.POSTRENDER, this.render, this);
+ this.updatePixelPosition();
+ var container = this.stopEvent_ ?
+ map.getOverlayContainerStopEvent() : map.getOverlayContainer();
+ if (this.insertFirst_) {
+ container.insertBefore(this.element_, container.childNodes[0] || null);
+ } else {
+ container.appendChild(this.element_);
+ }
+ }
+};
+
+
+/**
+ * @protected
+ */
+ol.Overlay.prototype.render = function() {
+ this.updatePixelPosition();
+};
+
+
+/**
+ * @protected
+ */
+ol.Overlay.prototype.handleOffsetChanged = function() {
+ this.updatePixelPosition();
+};
+
+
+/**
+ * @protected
+ */
+ol.Overlay.prototype.handlePositionChanged = function() {
+ this.updatePixelPosition();
+ if (this.get(ol.OverlayProperty.POSITION) !== undefined && this.autoPan) {
+ this.panIntoView_();
+ }
+};
+
+
+/**
+ * @protected
+ */
+ol.Overlay.prototype.handlePositioningChanged = function() {
+ this.updatePixelPosition();
+};
+
+
+/**
+ * Set the DOM element to be associated with this overlay.
+ * @param {Element|undefined} element The Element containing the overlay.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.setElement = function(element) {
+ this.set(ol.OverlayProperty.ELEMENT, element);
+};
+
+
+/**
+ * Set the map to be associated with this overlay.
+ * @param {ol.Map|undefined} map The map that the overlay is part of.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.setMap = function(map) {
+ this.set(ol.OverlayProperty.MAP, map);
+};
+
+
+/**
+ * Set the offset for this overlay.
+ * @param {Array.<number>} offset Offset.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.setOffset = function(offset) {
+ this.set(ol.OverlayProperty.OFFSET, offset);
+};
+
+
+/**
+ * Set the position for this overlay. If the position is `undefined` the
+ * overlay is hidden.
+ * @param {ol.Coordinate|undefined} position The spatial point that the overlay
+ * is anchored at.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.setPosition = function(position) {
+ this.set(ol.OverlayProperty.POSITION, position);
+};
+
+
+/**
+ * Pan the map so that the overlay is entirely visible in the current viewport
+ * (if necessary).
+ * @private
+ */
+ol.Overlay.prototype.panIntoView_ = function() {
+ goog.asserts.assert(this.autoPan, 'this.autoPan should be true');
+ var map = this.getMap();
+
+ if (map === undefined || !map.getTargetElement()) {
+ return;
+ }
+
+ var mapRect = this.getRect_(map.getTargetElement(), map.getSize());
+ var element = this.getElement();
+ goog.asserts.assert(element, 'element should be defined');
+ var overlayRect = this.getRect_(element,
+ [ol.dom.outerWidth(element), ol.dom.outerHeight(element)]);
+
+ var margin = this.autoPanMargin_;
+ if (!ol.extent.containsExtent(mapRect, overlayRect)) {
+ // the overlay is not completely inside the viewport, so pan the map
+ var offsetLeft = overlayRect[0] - mapRect[0];
+ var offsetRight = mapRect[2] - overlayRect[2];
+ var offsetTop = overlayRect[1] - mapRect[1];
+ var offsetBottom = mapRect[3] - overlayRect[3];
+
+ var delta = [0, 0];
+ if (offsetLeft < 0) {
+ // move map to the left
+ delta[0] = offsetLeft - margin;
+ } else if (offsetRight < 0) {
+ // move map to the right
+ delta[0] = Math.abs(offsetRight) + margin;
+ }
+ if (offsetTop < 0) {
+ // move map up
+ delta[1] = offsetTop - margin;
+ } else if (offsetBottom < 0) {
+ // move map down
+ delta[1] = Math.abs(offsetBottom) + margin;
+ }
+
+ if (delta[0] !== 0 || delta[1] !== 0) {
+ var center = map.getView().getCenter();
+ goog.asserts.assert(center !== undefined, 'center should be defined');
+ var centerPx = map.getPixelFromCoordinate(center);
+ var newCenterPx = [
+ centerPx[0] + delta[0],
+ centerPx[1] + delta[1]
+ ];
+
+ if (this.autoPanAnimation_) {
+ this.autoPanAnimation_.source = center;
+ map.beforeRender(ol.animation.pan(this.autoPanAnimation_));
+ }
+ map.getView().setCenter(map.getCoordinateFromPixel(newCenterPx));
+ }
+ }
+};
+
+
+/**
+ * Get the extent of an element relative to the document
+ * @param {Element|undefined} element The element.
+ * @param {ol.Size|undefined} size The size of the element.
+ * @return {ol.Extent} The extent.
+ * @private
+ */
+ol.Overlay.prototype.getRect_ = function(element, size) {
+ goog.asserts.assert(element, 'element should be defined');
+ goog.asserts.assert(size !== undefined, 'size should be defined');
+
+ var box = element.getBoundingClientRect();
+ var offsetX = box.left + ol.global.pageXOffset;
+ var offsetY = box.top + ol.global.pageYOffset;
+ return [
+ offsetX,
+ offsetY,
+ offsetX + size[0],
+ offsetY + size[1]
+ ];
+};
+
+
+/**
+ * Set the positioning for this overlay.
+ * @param {ol.OverlayPositioning} positioning how the overlay is
+ * positioned relative to its point on the map.
+ * @observable
+ * @api stable
+ */
+ol.Overlay.prototype.setPositioning = function(positioning) {
+ this.set(ol.OverlayProperty.POSITIONING, positioning);
+};
+
+
+/**
+ * Modify the visibility of the element.
+ * @param {boolean} visible Element visibility.
+ * @protected
+ */
+ol.Overlay.prototype.setVisible = function(visible) {
+ if (this.rendered_.visible !== visible) {
+ this.element_.style.display = visible ? '' : 'none';
+ this.rendered_.visible = visible;
+ }
+};
+
+
+/**
+ * Update pixel position.
+ * @protected
+ */
+ol.Overlay.prototype.updatePixelPosition = function() {
+ var map = this.getMap();
+ var position = this.getPosition();
+ if (map === undefined || !map.isRendered() || position === undefined) {
+ this.setVisible(false);
+ return;
+ }
+
+ var pixel = map.getPixelFromCoordinate(position);
+ var mapSize = map.getSize();
+ this.updateRenderedPosition(pixel, mapSize);
+};
+
+
+/**
+ * @param {ol.Pixel} pixel The pixel location.
+ * @param {ol.Size|undefined} mapSize The map size.
+ * @protected
+ */
+ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) {
+ goog.asserts.assert(pixel, 'pixel should not be null');
+ goog.asserts.assert(mapSize !== undefined, 'mapSize should be defined');
+ var style = this.element_.style;
+ var offset = this.getOffset();
+ goog.asserts.assert(Array.isArray(offset), 'offset should be an array');
+
+ var positioning = this.getPositioning();
+ goog.asserts.assert(positioning !== undefined,
+ 'positioning should be defined');
+
+ var offsetX = offset[0];
+ var offsetY = offset[1];
+ if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT ||
+ positioning == ol.OverlayPositioning.CENTER_RIGHT ||
+ positioning == ol.OverlayPositioning.TOP_RIGHT) {
+ if (this.rendered_.left_ !== '') {
+ this.rendered_.left_ = style.left = '';
+ }
+ var right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
+ if (this.rendered_.right_ != right) {
+ this.rendered_.right_ = style.right = right;
+ }
+ } else {
+ if (this.rendered_.right_ !== '') {
+ this.rendered_.right_ = style.right = '';
+ }
+ if (positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
+ positioning == ol.OverlayPositioning.CENTER_CENTER ||
+ positioning == ol.OverlayPositioning.TOP_CENTER) {
+ offsetX -= this.element_.offsetWidth / 2;
+ }
+ var left = Math.round(pixel[0] + offsetX) + 'px';
+ if (this.rendered_.left_ != left) {
+ this.rendered_.left_ = style.left = left;
+ }
+ }
+ if (positioning == ol.OverlayPositioning.BOTTOM_LEFT ||
+ positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
+ positioning == ol.OverlayPositioning.BOTTOM_RIGHT) {
+ if (this.rendered_.top_ !== '') {
+ this.rendered_.top_ = style.top = '';
+ }
+ var bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
+ if (this.rendered_.bottom_ != bottom) {
+ this.rendered_.bottom_ = style.bottom = bottom;
+ }
+ } else {
+ if (this.rendered_.bottom_ !== '') {
+ this.rendered_.bottom_ = style.bottom = '';
+ }
+ if (positioning == ol.OverlayPositioning.CENTER_LEFT ||
+ positioning == ol.OverlayPositioning.CENTER_CENTER ||
+ positioning == ol.OverlayPositioning.CENTER_RIGHT) {
+ offsetY -= this.element_.offsetHeight / 2;
+ }
+ var top = Math.round(pixel[1] + offsetY) + 'px';
+ if (this.rendered_.top_ != top) {
+ this.rendered_.top_ = style.top = top;
+ }
+ }
+
+ this.setVisible(true);
+};
+
+goog.provide('ol.control.OverviewMap');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.Collection');
+goog.require('ol.Map');
+goog.require('ol.MapEventType');
+goog.require('ol.Object');
+goog.require('ol.ObjectEventType');
+goog.require('ol.Overlay');
+goog.require('ol.OverlayPositioning');
+goog.require('ol.View');
+goog.require('ol.ViewProperty');
+goog.require('ol.control.Control');
+goog.require('ol.coordinate');
+goog.require('ol.css');
+goog.require('ol.dom');
+goog.require('ol.extent');
+
+
+/**
+ * Create a new control with a map acting as an overview map for an other
+ * defined map.
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options.
+ * @api
+ */
+ol.control.OverviewMap = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.collapsible_ = options.collapsible !== undefined ?
+ options.collapsible : true;
+
+ if (!this.collapsible_) {
+ this.collapsed_ = false;
+ }
+
+ var className = options.className !== undefined ? options.className : 'ol-overviewmap';
+
+ var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Overview map';
+
+ var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\u00AB';
+
+ if (typeof collapseLabel === 'string') {
+ /**
+ * @private
+ * @type {Node}
+ */
+ this.collapseLabel_ = document.createElement('span');
+ this.collapseLabel_.textContent = collapseLabel;
+ } else {
+ this.collapseLabel_ = collapseLabel;
+ }
+
+ var label = options.label !== undefined ? options.label : '\u00BB';
+
+
+ if (typeof label === 'string') {
+ /**
+ * @private
+ * @type {Node}
+ */
+ this.label_ = document.createElement('span');
+ this.label_.textContent = label;
+ } else {
+ this.label_ = label;
+ }
+
+ var activeLabel = (this.collapsible_ && !this.collapsed_) ?
+ this.collapseLabel_ : this.label_;
+ var button = document.createElement('button');
+ button.setAttribute('type', 'button');
+ button.title = tipLabel;
+ button.appendChild(activeLabel);
+
+ ol.events.listen(button, ol.events.EventType.CLICK,
+ this.handleClick_, this);
+
+ var ovmapDiv = document.createElement('DIV');
+ ovmapDiv.className = 'ol-overviewmap-map';
+
+ /**
+ * @type {ol.Map}
+ * @private
+ */
+ this.ovmap_ = new ol.Map({
+ controls: new ol.Collection(),
+ interactions: new ol.Collection(),
+ target: ovmapDiv,
+ view: options.view
+ });
+ var ovmap = this.ovmap_;
+
+ if (options.layers) {
+ options.layers.forEach(
+ /**
+ * @param {ol.layer.Layer} layer Layer.
+ */
+ function(layer) {
+ ovmap.addLayer(layer);
+ }, this);
+ }
+
+ var box = document.createElement('DIV');
+ box.className = 'ol-overviewmap-box';
+ box.style.boxSizing = 'border-box';
+
+ /**
+ * @type {ol.Overlay}
+ * @private
+ */
+ this.boxOverlay_ = new ol.Overlay({
+ position: [0, 0],
+ positioning: ol.OverlayPositioning.BOTTOM_LEFT,
+ element: box
+ });
+ this.ovmap_.addOverlay(this.boxOverlay_);
+
+ var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
+ ol.css.CLASS_CONTROL +
+ (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +
+ (this.collapsible_ ? '' : ' ol-uncollapsible');
+ var element = document.createElement('div');
+ element.className = cssClasses;
+ element.appendChild(ovmapDiv);
+ element.appendChild(button);
+
+ var render = options.render ? options.render : ol.control.OverviewMap.render;
+
+ ol.control.Control.call(this, {
+ element: element,
+ render: render,
+ target: options.target
+ });
+};
+ol.inherits(ol.control.OverviewMap, ol.control.Control);
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.control.OverviewMap.prototype.setMap = function(map) {
+ var oldMap = this.getMap();
+ if (map === oldMap) {
+ return;
+ }
+ if (oldMap) {
+ var oldView = oldMap.getView();
+ if (oldView) {
+ this.unbindView_(oldView);
+ }
+ }
+ ol.control.Control.prototype.setMap.call(this, map);
+
+ if (map) {
+ this.listenerKeys.push(ol.events.listen(
+ map, ol.ObjectEventType.PROPERTYCHANGE,
+ this.handleMapPropertyChange_, this));
+
+ // TODO: to really support map switching, this would need to be reworked
+ if (this.ovmap_.getLayers().getLength() === 0) {
+ this.ovmap_.setLayerGroup(map.getLayerGroup());
+ }
+
+ var view = map.getView();
+ if (view) {
+ this.bindView_(view);
+ if (view.isDef()) {
+ this.ovmap_.updateSize();
+ this.resetExtent_();
+ }
+ }
+ }
+};
+
+
+/**
+ * Handle map property changes. This only deals with changes to the map's view.
+ * @param {ol.ObjectEvent} event The propertychange event.
+ * @private
+ */
+ol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) {
+ if (event.key === ol.MapProperty.VIEW) {
+ var oldView = /** @type {ol.View} */ (event.oldValue);
+ if (oldView) {
+ this.unbindView_(oldView);
+ }
+ var newView = this.getMap().getView();
+ this.bindView_(newView);
+ }
+};
+
+
+/**
+ * Register listeners for view property changes.
+ * @param {ol.View} view The view.
+ * @private
+ */
+ol.control.OverviewMap.prototype.bindView_ = function(view) {
+ ol.events.listen(view,
+ ol.Object.getChangeEventType(ol.ViewProperty.ROTATION),
+ this.handleRotationChanged_, this);
+};
+
+
+/**
+ * Unregister listeners for view property changes.
+ * @param {ol.View} view The view.
+ * @private
+ */
+ol.control.OverviewMap.prototype.unbindView_ = function(view) {
+ ol.events.unlisten(view,
+ ol.Object.getChangeEventType(ol.ViewProperty.ROTATION),
+ this.handleRotationChanged_, this);
+};
+
+
+/**
+ * Handle rotation changes to the main map.
+ * TODO: This should rotate the extent rectrangle instead of the
+ * overview map's view.
+ * @private
+ */
+ol.control.OverviewMap.prototype.handleRotationChanged_ = function() {
+ this.ovmap_.getView().setRotation(this.getMap().getView().getRotation());
+};
+
+
+/**
+ * Update the overview map element.
+ * @param {ol.MapEvent} mapEvent Map event.
+ * @this {ol.control.OverviewMap}
+ * @api
+ */
+ol.control.OverviewMap.render = function(mapEvent) {
+ this.validateExtent_();
+ this.updateBox_();
+};
+
+
+/**
+ * Reset the overview map extent if the box size (width or
+ * height) is less than the size of the overview map size times minRatio
+ * or is greater than the size of the overview size times maxRatio.
+ *
+ * If the map extent was not reset, the box size can fits in the defined
+ * ratio sizes. This method then checks if is contained inside the overview
+ * map current extent. If not, recenter the overview map to the current
+ * main map center location.
+ * @private
+ */
+ol.control.OverviewMap.prototype.validateExtent_ = function() {
+ var map = this.getMap();
+ var ovmap = this.ovmap_;
+
+ if (!map.isRendered() || !ovmap.isRendered()) {
+ return;
+ }
+
+ var mapSize = map.getSize();
+ goog.asserts.assertArray(mapSize, 'mapSize should be an array');
+
+ var view = map.getView();
+ goog.asserts.assert(view, 'view should be defined');
+ var extent = view.calculateExtent(mapSize);
+
+ var ovmapSize = ovmap.getSize();
+ goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array');
+
+ var ovview = ovmap.getView();
+ goog.asserts.assert(ovview, 'ovview should be defined');
+ var ovextent = ovview.calculateExtent(ovmapSize);
+
+ var topLeftPixel =
+ ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent));
+ var bottomRightPixel =
+ ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent));
+
+ var boxWidth = Math.abs(topLeftPixel[0] - bottomRightPixel[0]);
+ var boxHeight = Math.abs(topLeftPixel[1] - bottomRightPixel[1]);
+
+ var ovmapWidth = ovmapSize[0];
+ var ovmapHeight = ovmapSize[1];
+
+ if (boxWidth < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO ||
+ boxHeight < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO ||
+ boxWidth > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO ||
+ boxHeight > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) {
+ this.resetExtent_();
+ } else if (!ol.extent.containsExtent(ovextent, extent)) {
+ this.recenter_();
+ }
+};
+
+
+/**
+ * Reset the overview map extent to half calculated min and max ratio times
+ * the extent of the main map.
+ * @private
+ */
+ol.control.OverviewMap.prototype.resetExtent_ = function() {
+ if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) {
+ return;
+ }
+
+ var map = this.getMap();
+ var ovmap = this.ovmap_;
+
+ var mapSize = map.getSize();
+ goog.asserts.assertArray(mapSize, 'mapSize should be an array');
+
+ var view = map.getView();
+ goog.asserts.assert(view, 'view should be defined');
+ var extent = view.calculateExtent(mapSize);
+
+ var ovmapSize = ovmap.getSize();
+ goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array');
+
+ var ovview = ovmap.getView();
+ goog.asserts.assert(ovview, 'ovview should be defined');
+
+ // get how many times the current map overview could hold different
+ // box sizes using the min and max ratio, pick the step in the middle used
+ // to calculate the extent from the main map to set it to the overview map,
+ var steps = Math.log(
+ ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2;
+ var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO);
+ ol.extent.scaleFromCenter(extent, ratio);
+ ovview.fit(extent, ovmapSize);
+};
+
+
+/**
+ * Set the center of the overview map to the map center without changing its
+ * resolution.
+ * @private
+ */
+ol.control.OverviewMap.prototype.recenter_ = function() {
+ var map = this.getMap();
+ var ovmap = this.ovmap_;
+
+ var view = map.getView();
+ goog.asserts.assert(view, 'view should be defined');
+
+ var ovview = ovmap.getView();
+ goog.asserts.assert(ovview, 'ovview should be defined');
+
+ ovview.setCenter(view.getCenter());
+};
+
+
+/**
+ * Update the box using the main map extent
+ * @private
+ */
+ol.control.OverviewMap.prototype.updateBox_ = function() {
+ var map = this.getMap();
+ var ovmap = this.ovmap_;
+
+ if (!map.isRendered() || !ovmap.isRendered()) {
+ return;
+ }
+
+ var mapSize = map.getSize();
+ goog.asserts.assertArray(mapSize, 'mapSize should be an array');
+
+ var view = map.getView();
+ goog.asserts.assert(view, 'view should be defined');
+
+ var ovview = ovmap.getView();
+ goog.asserts.assert(ovview, 'ovview should be defined');
+
+ var ovmapSize = ovmap.getSize();
+ goog.asserts.assertArray(ovmapSize, 'ovmapSize should be an array');
+
+ var rotation = view.getRotation();
+ goog.asserts.assert(rotation !== undefined, 'rotation should be defined');
+
+ var overlay = this.boxOverlay_;
+ var box = this.boxOverlay_.getElement();
+ var extent = view.calculateExtent(mapSize);
+ var ovresolution = ovview.getResolution();
+ var bottomLeft = ol.extent.getBottomLeft(extent);
+ var topRight = ol.extent.getTopRight(extent);
+
+ // set position using bottom left coordinates
+ var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft);
+ overlay.setPosition(rotateBottomLeft);
+
+ // set box size calculated from map extent size and overview map resolution
+ if (box) {
+ box.style.width = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution) + 'px';
+ box.style.height = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution) + 'px';
+ }
+};
+
+
+/**
+ * @param {number} rotation Target rotation.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor.
+ * @private
+ */
+ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function(
+ rotation, coordinate) {
+ var coordinateRotate;
+
+ var map = this.getMap();
+ var view = map.getView();
+ goog.asserts.assert(view, 'view should be defined');
+
+ var currentCenter = view.getCenter();
+
+ if (currentCenter) {
+ coordinateRotate = [
+ coordinate[0] - currentCenter[0],
+ coordinate[1] - currentCenter[1]
+ ];
+ ol.coordinate.rotate(coordinateRotate, rotation);
+ ol.coordinate.add(coordinateRotate, currentCenter);
+ }
+ return coordinateRotate;
+};
+
+
+/**
+ * @param {Event} event The event to handle
+ * @private
+ */
+ol.control.OverviewMap.prototype.handleClick_ = function(event) {
+ event.preventDefault();
+ this.handleToggle_();
+};
+
+
+/**
+ * @private
+ */
+ol.control.OverviewMap.prototype.handleToggle_ = function() {
+ this.element.classList.toggle('ol-collapsed');
+ if (this.collapsed_) {
+ ol.dom.replaceNode(this.collapseLabel_, this.label_);
+ } else {
+ ol.dom.replaceNode(this.label_, this.collapseLabel_);
+ }
+ this.collapsed_ = !this.collapsed_;
+
+ // manage overview map if it had not been rendered before and control
+ // is expanded
+ var ovmap = this.ovmap_;
+ if (!this.collapsed_ && !ovmap.isRendered()) {
+ ovmap.updateSize();
+ this.resetExtent_();
+ ol.events.listenOnce(ovmap, ol.MapEventType.POSTRENDER,
+ function(event) {
+ this.updateBox_();
+ },
+ this);
+ }
+};
+
+
+/**
+ * Return `true` if the overview map is collapsible, `false` otherwise.
+ * @return {boolean} True if the widget is collapsible.
+ * @api stable
+ */
+ol.control.OverviewMap.prototype.getCollapsible = function() {
+ return this.collapsible_;
+};
+
+
+/**
+ * Set whether the overview map should be collapsible.
+ * @param {boolean} collapsible True if the widget is collapsible.
+ * @api stable
+ */
+ol.control.OverviewMap.prototype.setCollapsible = function(collapsible) {
+ if (this.collapsible_ === collapsible) {
+ return;
+ }
+ this.collapsible_ = collapsible;
+ this.element.classList.toggle('ol-uncollapsible');
+ if (!collapsible && this.collapsed_) {
+ this.handleToggle_();
+ }
+};
+
+
+/**
+ * Collapse or expand the overview map according to the passed parameter. Will
+ * not do anything if the overview map isn't collapsible or if the current
+ * collapsed state is already the one requested.
+ * @param {boolean} collapsed True if the widget is collapsed.
+ * @api stable
+ */
+ol.control.OverviewMap.prototype.setCollapsed = function(collapsed) {
+ if (!this.collapsible_ || this.collapsed_ === collapsed) {
+ return;
+ }
+ this.handleToggle_();
+};
+
+
+/**
+ * Determine if the overview map is collapsed.
+ * @return {boolean} The overview map is collapsed.
+ * @api stable
+ */
+ol.control.OverviewMap.prototype.getCollapsed = function() {
+ return this.collapsed_;
+};
+
+
+/**
+ * Return the overview map.
+ * @return {ol.Map} Overview map.
+ * @api
+ */
+ol.control.OverviewMap.prototype.getOverviewMap = function() {
+ return this.ovmap_;
+};
+
+goog.provide('ol.control.ScaleLine');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol');
+goog.require('ol.Object');
+goog.require('ol.control.Control');
+goog.require('ol.css');
+goog.require('ol.proj.METERS_PER_UNIT');
+goog.require('ol.proj.Units');
+
+
+/**
+ * @enum {string}
+ */
+ol.control.ScaleLineProperty = {
+ UNITS: 'units'
+};
+
+
+/**
+ * Units for the scale line. Supported values are `'degrees'`, `'imperial'`,
+ * `'nautical'`, `'metric'`, `'us'`.
+ * @enum {string}
+ */
+ol.control.ScaleLineUnits = {
+ DEGREES: 'degrees',
+ IMPERIAL: 'imperial',
+ NAUTICAL: 'nautical',
+ METRIC: 'metric',
+ US: 'us'
+};
+
+
+/**
+ * @classdesc
+ * A control displaying rough x-axis distances, calculated for the center of the
+ * viewport.
+ * No scale line will be shown when the x-axis distance cannot be calculated in
+ * the view projection (e.g. at or beyond the poles in EPSG:4326).
+ * By default the scale line will show in the bottom left portion of the map,
+ * but this can be changed by using the css selector `.ol-scale-line`.
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.ScaleLineOptions=} opt_options Scale line options.
+ * @api stable
+ */
+ol.control.ScaleLine = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ var className = options.className !== undefined ? options.className : 'ol-scale-line';
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.innerElement_ = document.createElement('DIV');
+ this.innerElement_.className = className + '-inner';
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.element_ = document.createElement('DIV');
+ this.element_.className = className + ' ' + ol.css.CLASS_UNSELECTABLE;
+ this.element_.appendChild(this.innerElement_);
+
+ /**
+ * @private
+ * @type {?olx.ViewState}
+ */
+ this.viewState_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderedVisible_ = false;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.renderedWidth_ = undefined;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.renderedHTML_ = '';
+
+ var render = options.render ? options.render : ol.control.ScaleLine.render;
+
+ ol.control.Control.call(this, {
+ element: this.element_,
+ render: render,
+ target: options.target
+ });
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.control.ScaleLineProperty.UNITS),
+ this.handleUnitsChanged_, this);
+
+ this.setUnits(/** @type {ol.control.ScaleLineUnits} */ (options.units) ||
+ ol.control.ScaleLineUnits.METRIC);
+
+};
+ol.inherits(ol.control.ScaleLine, ol.control.Control);
+
+
+/**
+ * @const
+ * @type {Array.<number>}
+ */
+ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5];
+
+
+/**
+ * Return the units to use in the scale line.
+ * @return {ol.control.ScaleLineUnits|undefined} The units to use in the scale
+ * line.
+ * @observable
+ * @api stable
+ */
+ol.control.ScaleLine.prototype.getUnits = function() {
+ return /** @type {ol.control.ScaleLineUnits|undefined} */ (
+ this.get(ol.control.ScaleLineProperty.UNITS));
+};
+
+
+/**
+ * Update the scale line element.
+ * @param {ol.MapEvent} mapEvent Map event.
+ * @this {ol.control.ScaleLine}
+ * @api
+ */
+ol.control.ScaleLine.render = function(mapEvent) {
+ var frameState = mapEvent.frameState;
+ if (!frameState) {
+ this.viewState_ = null;
+ } else {
+ this.viewState_ = frameState.viewState;
+ }
+ this.updateElement_();
+};
+
+
+/**
+ * @private
+ */
+ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() {
+ this.updateElement_();
+};
+
+
+/**
+ * Set the units to use in the scale line.
+ * @param {ol.control.ScaleLineUnits} units The units to use in the scale line.
+ * @observable
+ * @api stable
+ */
+ol.control.ScaleLine.prototype.setUnits = function(units) {
+ this.set(ol.control.ScaleLineProperty.UNITS, units);
+};
+
+
+/**
+ * @private
+ */
+ol.control.ScaleLine.prototype.updateElement_ = function() {
+ var viewState = this.viewState_;
+
+ if (!viewState) {
+ if (this.renderedVisible_) {
+ this.element_.style.display = 'none';
+ this.renderedVisible_ = false;
+ }
+ return;
+ }
+
+ var center = viewState.center;
+ var projection = viewState.projection;
+ var metersPerUnit = projection.getMetersPerUnit();
+ var pointResolution =
+ projection.getPointResolution(viewState.resolution, center) *
+ metersPerUnit;
+
+ var nominalCount = this.minWidth_ * pointResolution;
+ var suffix = '';
+ var units = this.getUnits();
+ if (units == ol.control.ScaleLineUnits.DEGREES) {
+ var metersPerDegree = ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES];
+ pointResolution /= metersPerDegree;
+ if (nominalCount < metersPerDegree / 60) {
+ suffix = '\u2033'; // seconds
+ pointResolution *= 3600;
+ } else if (nominalCount < metersPerDegree) {
+ suffix = '\u2032'; // minutes
+ pointResolution *= 60;
+ } else {
+ suffix = '\u00b0'; // degrees
+ }
+ } else if (units == ol.control.ScaleLineUnits.IMPERIAL) {
+ if (nominalCount < 0.9144) {
+ suffix = 'in';
+ pointResolution /= 0.0254;
+ } else if (nominalCount < 1609.344) {
+ suffix = 'ft';
+ pointResolution /= 0.3048;
+ } else {
+ suffix = 'mi';
+ pointResolution /= 1609.344;
+ }
+ } else if (units == ol.control.ScaleLineUnits.NAUTICAL) {
+ pointResolution /= 1852;
+ suffix = 'nm';
+ } else if (units == ol.control.ScaleLineUnits.METRIC) {
+ if (nominalCount < 1) {
+ suffix = 'mm';
+ pointResolution *= 1000;
+ } else if (nominalCount < 1000) {
+ suffix = 'm';
+ } else {
+ suffix = 'km';
+ pointResolution /= 1000;
+ }
+ } else if (units == ol.control.ScaleLineUnits.US) {
+ if (nominalCount < 0.9144) {
+ suffix = 'in';
+ pointResolution *= 39.37;
+ } else if (nominalCount < 1609.344) {
+ suffix = 'ft';
+ pointResolution /= 0.30480061;
+ } else {
+ suffix = 'mi';
+ pointResolution /= 1609.3472;
+ }
+ } else {
+ goog.asserts.fail('Scale line element cannot be updated');
+ }
+
+ var i = 3 * Math.floor(
+ Math.log(this.minWidth_ * pointResolution) / Math.log(10));
+ var count, width;
+ while (true) {
+ count = ol.control.ScaleLine.LEADING_DIGITS[((i % 3) + 3) % 3] *
+ Math.pow(10, Math.floor(i / 3));
+ width = Math.round(count / pointResolution);
+ if (isNaN(width)) {
+ this.element_.style.display = 'none';
+ this.renderedVisible_ = false;
+ return;
+ } else if (width >= this.minWidth_) {
+ break;
+ }
+ ++i;
+ }
+
+ var html = count + ' ' + suffix;
+ if (this.renderedHTML_ != html) {
+ this.innerElement_.innerHTML = html;
+ this.renderedHTML_ = html;
+ }
+
+ if (this.renderedWidth_ != width) {
+ this.innerElement_.style.width = width + 'px';
+ this.renderedWidth_ = width;
+ }
+
+ if (!this.renderedVisible_) {
+ this.element_.style.display = '';
+ this.renderedVisible_ = true;
+ }
+
+};
+
+// FIXME should possibly show tooltip when dragging?
+
+goog.provide('ol.control.ZoomSlider');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('ol.pointer.PointerEventHandler');
+goog.require('ol.ViewHint');
+goog.require('ol.animation');
+goog.require('ol.control.Control');
+goog.require('ol.css');
+goog.require('ol.easing');
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * A slider type of control for zooming.
+ *
+ * Example:
+ *
+ * map.addControl(new ol.control.ZoomSlider());
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options.
+ * @api stable
+ */
+ol.control.ZoomSlider = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * Will hold the current resolution of the view.
+ *
+ * @type {number|undefined}
+ * @private
+ */
+ this.currentResolution_ = undefined;
+
+ /**
+ * The direction of the slider. Will be determined from actual display of the
+ * container and defaults to ol.control.ZoomSlider.direction.VERTICAL.
+ *
+ * @type {ol.control.ZoomSlider.direction}
+ * @private
+ */
+ this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.dragging_;
+
+ /**
+ * @type {!Array.<ol.EventsKey>}
+ * @private
+ */
+ this.dragListenerKeys_ = [];
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.heightLimit_ = 0;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.widthLimit_ = 0;
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.previousX_;
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.previousY_;
+
+ /**
+ * The calculated thumb size (border box plus margins). Set when initSlider_
+ * is called.
+ * @type {ol.Size}
+ * @private
+ */
+ this.thumbSize_ = null;
+
+ /**
+ * Whether the slider is initialized.
+ * @type {boolean}
+ * @private
+ */
+ this.sliderInitialized_ = false;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 200;
+
+ var className = options.className !== undefined ? options.className : 'ol-zoomslider';
+ var thumbElement = document.createElement('button');
+ thumbElement.setAttribute('type', 'button');
+ thumbElement.className = className + '-thumb ' + ol.css.CLASS_UNSELECTABLE;
+ var containerElement = document.createElement('div');
+ containerElement.className = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + ol.css.CLASS_CONTROL;
+ containerElement.appendChild(thumbElement);
+ /**
+ * @type {ol.pointer.PointerEventHandler}
+ * @private
+ */
+ this.dragger_ = new ol.pointer.PointerEventHandler(containerElement);
+
+ ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERDOWN,
+ this.handleDraggerStart_, this);
+ ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERMOVE,
+ this.handleDraggerDrag_, this);
+ ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERUP,
+ this.handleDraggerEnd_, this);
+
+ ol.events.listen(containerElement, ol.events.EventType.CLICK,
+ this.handleContainerClick_, this);
+ ol.events.listen(thumbElement, ol.events.EventType.CLICK,
+ ol.events.Event.stopPropagation);
+
+ var render = options.render ? options.render : ol.control.ZoomSlider.render;
+
+ ol.control.Control.call(this, {
+ element: containerElement,
+ render: render
+ });
+};
+ol.inherits(ol.control.ZoomSlider, ol.control.Control);
+
+
+/**
+ * @inheritDoc
+ */
+ol.control.ZoomSlider.prototype.disposeInternal = function() {
+ this.dragger_.dispose();
+ ol.control.Control.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * The enum for available directions.
+ *
+ * @enum {number}
+ */
+ol.control.ZoomSlider.direction = {
+ VERTICAL: 0,
+ HORIZONTAL: 1
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.control.ZoomSlider.prototype.setMap = function(map) {
+ ol.control.Control.prototype.setMap.call(this, map);
+ if (map) {
+ map.render();
+ }
+};
+
+
+/**
+ * Initializes the slider element. This will determine and set this controls
+ * direction_ and also constrain the dragging of the thumb to always be within
+ * the bounds of the container.
+ *
+ * @private
+ */
+ol.control.ZoomSlider.prototype.initSlider_ = function() {
+ var container = this.element;
+ var containerSize = {
+ width: container.offsetWidth, height: container.offsetHeight
+ };
+
+ var thumb = container.firstElementChild;
+ var computedStyle = ol.global.getComputedStyle(thumb);
+ var thumbWidth = thumb.offsetWidth +
+ parseFloat(computedStyle['marginRight']) +
+ parseFloat(computedStyle['marginLeft']);
+ var thumbHeight = thumb.offsetHeight +
+ parseFloat(computedStyle['marginTop']) +
+ parseFloat(computedStyle['marginBottom']);
+ this.thumbSize_ = [thumbWidth, thumbHeight];
+
+ if (containerSize.width > containerSize.height) {
+ this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL;
+ this.widthLimit_ = containerSize.width - thumbWidth;
+ } else {
+ this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
+ this.heightLimit_ = containerSize.height - thumbHeight;
+ }
+ this.sliderInitialized_ = true;
+};
+
+
+/**
+ * Update the zoomslider element.
+ * @param {ol.MapEvent} mapEvent Map event.
+ * @this {ol.control.ZoomSlider}
+ * @api
+ */
+ol.control.ZoomSlider.render = function(mapEvent) {
+ if (!mapEvent.frameState) {
+ return;
+ }
+ goog.asserts.assert(mapEvent.frameState.viewState,
+ 'viewState should be defined');
+ if (!this.sliderInitialized_) {
+ this.initSlider_();
+ }
+ var res = mapEvent.frameState.viewState.resolution;
+ if (res !== this.currentResolution_) {
+ this.currentResolution_ = res;
+ this.setThumbPosition_(res);
+ }
+};
+
+
+/**
+ * @param {Event} event The browser event to handle.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.handleContainerClick_ = function(event) {
+ var map = this.getMap();
+ var view = map.getView();
+ var currentResolution = view.getResolution();
+ goog.asserts.assert(currentResolution,
+ 'currentResolution should be defined');
+ map.beforeRender(ol.animation.zoom({
+ resolution: currentResolution,
+ duration: this.duration_,
+ easing: ol.easing.easeOut
+ }));
+ var relativePosition = this.getRelativePosition_(
+ event.offsetX - this.thumbSize_[0] / 2,
+ event.offsetY - this.thumbSize_[1] / 2);
+ var resolution = this.getResolutionForPosition_(relativePosition);
+ view.setResolution(view.constrainResolution(resolution));
+};
+
+
+/**
+ * Handle dragger start events.
+ * @param {ol.pointer.PointerEvent} event The drag event.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
+ if (!this.dragging_ &&
+ event.originalEvent.target === this.element.firstElementChild) {
+ this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1);
+ this.previousX_ = event.clientX;
+ this.previousY_ = event.clientY;
+ this.dragging_ = true;
+
+ if (this.dragListenerKeys_.length === 0) {
+ var drag = this.handleDraggerDrag_;
+ var end = this.handleDraggerEnd_;
+ this.dragListenerKeys_.push(
+ ol.events.listen(document, ol.events.EventType.MOUSEMOVE, drag, this),
+ ol.events.listen(document, ol.events.EventType.TOUCHMOVE, drag, this),
+ ol.events.listen(document, ol.pointer.EventType.POINTERMOVE, drag, this),
+ ol.events.listen(document, ol.events.EventType.MOUSEUP, end, this),
+ ol.events.listen(document, ol.events.EventType.TOUCHEND, end, this),
+ ol.events.listen(document, ol.pointer.EventType.POINTERUP, end, this)
+ );
+ }
+ }
+};
+
+
+/**
+ * Handle dragger drag events.
+ *
+ * @param {ol.pointer.PointerEvent|Event} event The drag event.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
+ if (this.dragging_) {
+ var element = this.element.firstElementChild;
+ var deltaX = event.clientX - this.previousX_ + parseInt(element.style.left, 10);
+ var deltaY = event.clientY - this.previousY_ + parseInt(element.style.top, 10);
+ var relativePosition = this.getRelativePosition_(deltaX, deltaY);
+ this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
+ this.getMap().getView().setResolution(this.currentResolution_);
+ this.setThumbPosition_(this.currentResolution_);
+ this.previousX_ = event.clientX;
+ this.previousY_ = event.clientY;
+ }
+};
+
+
+/**
+ * Handle dragger end events.
+ * @param {ol.pointer.PointerEvent|Event} event The drag event.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {
+ if (this.dragging_) {
+ var map = this.getMap();
+ var view = map.getView();
+ view.setHint(ol.ViewHint.INTERACTING, -1);
+ goog.asserts.assert(this.currentResolution_,
+ 'this.currentResolution_ should be defined');
+ map.beforeRender(ol.animation.zoom({
+ resolution: this.currentResolution_,
+ duration: this.duration_,
+ easing: ol.easing.easeOut
+ }));
+ var resolution = view.constrainResolution(this.currentResolution_);
+ view.setResolution(resolution);
+ this.dragging_ = false;
+ this.previousX_ = undefined;
+ this.previousY_ = undefined;
+ this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.dragListenerKeys_.length = 0;
+ }
+};
+
+
+/**
+ * Positions the thumb inside its container according to the given resolution.
+ *
+ * @param {number} res The res.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) {
+ var position = this.getPositionForResolution_(res);
+ var thumb = this.element.firstElementChild;
+
+ if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) {
+ thumb.style.left = this.widthLimit_ * position + 'px';
+ } else {
+ thumb.style.top = this.heightLimit_ * position + 'px';
+ }
+};
+
+
+/**
+ * Calculates the relative position of the thumb given x and y offsets. The
+ * relative position scales from 0 to 1. The x and y offsets are assumed to be
+ * in pixel units within the dragger limits.
+ *
+ * @param {number} x Pixel position relative to the left of the slider.
+ * @param {number} y Pixel position relative to the top of the slider.
+ * @return {number} The relative position of the thumb.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) {
+ var amount;
+ if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) {
+ amount = x / this.widthLimit_;
+ } else {
+ amount = y / this.heightLimit_;
+ }
+ return ol.math.clamp(amount, 0, 1);
+};
+
+
+/**
+ * Calculates the corresponding resolution of the thumb given its relative
+ * position (where 0 is the minimum and 1 is the maximum).
+ *
+ * @param {number} position The relative position of the thumb.
+ * @return {number} The corresponding resolution.
+ * @private
+ */
+ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) {
+ var fn = this.getMap().getView().getResolutionForValueFunction();
+ return fn(1 - position);
+};
+
+
+/**
+ * Determines the relative position of the slider for the given resolution. A
+ * relative position of 0 corresponds to the minimum view resolution. A
+ * relative position of 1 corresponds to the maximum view resolution.
+ *
+ * @param {number} res The resolution.
+ * @return {number} The relative position value (between 0 and 1).
+ * @private
+ */
+ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) {
+ var fn = this.getMap().getView().getValueForResolutionFunction();
+ return 1 - fn(res);
+};
+
+goog.provide('ol.control.ZoomToExtent');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.control.Control');
+goog.require('ol.css');
+
+
+/**
+ * @classdesc
+ * A button control which, when pressed, changes the map view to a specific
+ * extent. To style this control use the css selector `.ol-zoom-extent`.
+ *
+ * @constructor
+ * @extends {ol.control.Control}
+ * @param {olx.control.ZoomToExtentOptions=} opt_options Options.
+ * @api stable
+ */
+ol.control.ZoomToExtent = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @type {ol.Extent}
+ * @private
+ */
+ this.extent_ = options.extent ? options.extent : null;
+
+ var className = options.className !== undefined ? options.className :
+ 'ol-zoom-extent';
+
+ var label = options.label !== undefined ? options.label : 'E';
+ var tipLabel = options.tipLabel !== undefined ?
+ options.tipLabel : 'Fit to extent';
+ var button = document.createElement('button');
+ button.setAttribute('type', 'button');
+ button.title = tipLabel;
+ button.appendChild(
+ typeof label === 'string' ? document.createTextNode(label) : label
+ );
+
+ ol.events.listen(button, ol.events.EventType.CLICK,
+ this.handleClick_, this);
+
+ var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
+ ol.css.CLASS_CONTROL;
+ var element = document.createElement('div');
+ element.className = cssClasses;
+ element.appendChild(button);
+
+ ol.control.Control.call(this, {
+ element: element,
+ target: options.target
+ });
+};
+ol.inherits(ol.control.ZoomToExtent, ol.control.Control);
+
+
+/**
+ * @param {Event} event The event to handle
+ * @private
+ */
+ol.control.ZoomToExtent.prototype.handleClick_ = function(event) {
+ event.preventDefault();
+ this.handleZoomToExtent_();
+};
+
+
+/**
+ * @private
+ */
+ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() {
+ var map = this.getMap();
+ var view = map.getView();
+ var extent = !this.extent_ ? view.getProjection().getExtent() : this.extent_;
+ var size = map.getSize();
+ goog.asserts.assert(size, 'size should be defined');
+ view.fit(extent, size);
+};
+
+goog.provide('ol.DeviceOrientation');
+
+goog.require('ol.events');
+goog.require('ol');
+goog.require('ol.Object');
+goog.require('ol.has');
+goog.require('ol.math');
+
+
+/**
+ * @enum {string}
+ */
+ol.DeviceOrientationProperty = {
+ ALPHA: 'alpha',
+ BETA: 'beta',
+ GAMMA: 'gamma',
+ HEADING: 'heading',
+ TRACKING: 'tracking'
+};
+
+
+/**
+ * @classdesc
+ * The ol.DeviceOrientation class provides access to information from
+ * DeviceOrientation events. See the [HTML 5 DeviceOrientation Specification](
+ * http://www.w3.org/TR/orientation-event/) for more details.
+ *
+ * Many new computers, and especially mobile phones
+ * and tablets, provide hardware support for device orientation. Web
+ * developers targeting mobile devices will be especially interested in this
+ * class.
+ *
+ * Device orientation data are relative to a common starting point. For mobile
+ * devices, the starting point is to lay your phone face up on a table with the
+ * top of the phone pointing north. This represents the zero state. All
+ * angles are then relative to this state. For computers, it is the same except
+ * the screen is open at 90 degrees.
+ *
+ * Device orientation is reported as three angles - `alpha`, `beta`, and
+ * `gamma` - relative to the starting position along the three planar axes X, Y
+ * and Z. The X axis runs from the left edge to the right edge through the
+ * middle of the device. Similarly, the Y axis runs from the bottom to the top
+ * of the device through the middle. The Z axis runs from the back to the front
+ * through the middle. In the starting position, the X axis points to the
+ * right, the Y axis points away from you and the Z axis points straight up
+ * from the device lying flat.
+ *
+ * The three angles representing the device orientation are relative to the
+ * three axes. `alpha` indicates how much the device has been rotated around the
+ * Z axis, which is commonly interpreted as the compass heading (see note
+ * below). `beta` indicates how much the device has been rotated around the X
+ * axis, or how much it is tilted from front to back. `gamma` indicates how
+ * much the device has been rotated around the Y axis, or how much it is tilted
+ * from left to right.
+ *
+ * For most browsers, the `alpha` value returns the compass heading so if the
+ * device points north, it will be 0. With Safari on iOS, the 0 value of
+ * `alpha` is calculated from when device orientation was first requested.
+ * ol.DeviceOrientation provides the `heading` property which normalizes this
+ * behavior across all browsers for you.
+ *
+ * It is important to note that the HTML 5 DeviceOrientation specification
+ * indicates that `alpha`, `beta` and `gamma` are in degrees while the
+ * equivalent properties in ol.DeviceOrientation are in radians for consistency
+ * with all other uses of angles throughout OpenLayers.
+ *
+ * To get notified of device orientation changes, register a listener for the
+ * generic `change` event on your `ol.DeviceOrientation` instance.
+ *
+ * @see {@link http://www.w3.org/TR/orientation-event/}
+ *
+ * @constructor
+ * @extends {ol.Object}
+ * @param {olx.DeviceOrientationOptions=} opt_options Options.
+ * @api
+ */
+ol.DeviceOrientation = function(opt_options) {
+
+ ol.Object.call(this);
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {?ol.EventsKey}
+ */
+ this.listenerKey_ = null;
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING),
+ this.handleTrackingChanged_, this);
+
+ this.setTracking(options.tracking !== undefined ? options.tracking : false);
+
+};
+ol.inherits(ol.DeviceOrientation, ol.Object);
+
+
+/**
+ * @inheritDoc
+ */
+ol.DeviceOrientation.prototype.disposeInternal = function() {
+ this.setTracking(false);
+ ol.Object.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @private
+ * @param {Event} originalEvent Event.
+ */
+ol.DeviceOrientation.prototype.orientationChange_ = function(originalEvent) {
+ var event = /** @type {DeviceOrientationEvent} */ (originalEvent);
+ if (event.alpha !== null) {
+ var alpha = ol.math.toRadians(event.alpha);
+ this.set(ol.DeviceOrientationProperty.ALPHA, alpha);
+ // event.absolute is undefined in iOS.
+ if (typeof event.absolute === 'boolean' && event.absolute) {
+ this.set(ol.DeviceOrientationProperty.HEADING, alpha);
+ } else if (goog.isNumber(event.webkitCompassHeading) &&
+ event.webkitCompassAccuracy != -1) {
+ var heading = ol.math.toRadians(event.webkitCompassHeading);
+ this.set(ol.DeviceOrientationProperty.HEADING, heading);
+ }
+ }
+ if (event.beta !== null) {
+ this.set(ol.DeviceOrientationProperty.BETA,
+ ol.math.toRadians(event.beta));
+ }
+ if (event.gamma !== null) {
+ this.set(ol.DeviceOrientationProperty.GAMMA,
+ ol.math.toRadians(event.gamma));
+ }
+ this.changed();
+};
+
+
+/**
+ * Rotation around the device z-axis (in radians).
+ * @return {number|undefined} The euler angle in radians of the device from the
+ * standard Z axis.
+ * @observable
+ * @api
+ */
+ol.DeviceOrientation.prototype.getAlpha = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.DeviceOrientationProperty.ALPHA));
+};
+
+
+/**
+ * Rotation around the device x-axis (in radians).
+ * @return {number|undefined} The euler angle in radians of the device from the
+ * planar X axis.
+ * @observable
+ * @api
+ */
+ol.DeviceOrientation.prototype.getBeta = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.DeviceOrientationProperty.BETA));
+};
+
+
+/**
+ * Rotation around the device y-axis (in radians).
+ * @return {number|undefined} The euler angle in radians of the device from the
+ * planar Y axis.
+ * @observable
+ * @api
+ */
+ol.DeviceOrientation.prototype.getGamma = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.DeviceOrientationProperty.GAMMA));
+};
+
+
+/**
+ * The heading of the device relative to north (in radians).
+ * @return {number|undefined} The heading of the device relative to north, in
+ * radians, normalizing for different browser behavior.
+ * @observable
+ * @api
+ */
+ol.DeviceOrientation.prototype.getHeading = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.DeviceOrientationProperty.HEADING));
+};
+
+
+/**
+ * Determine if orientation is being tracked.
+ * @return {boolean} Changes in device orientation are being tracked.
+ * @observable
+ * @api
+ */
+ol.DeviceOrientation.prototype.getTracking = function() {
+ return /** @type {boolean} */ (
+ this.get(ol.DeviceOrientationProperty.TRACKING));
+};
+
+
+/**
+ * @private
+ */
+ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() {
+ if (ol.has.DEVICE_ORIENTATION) {
+ var tracking = this.getTracking();
+ if (tracking && !this.listenerKey_) {
+ this.listenerKey_ = ol.events.listen(ol.global, 'deviceorientation',
+ this.orientationChange_, this);
+ } else if (!tracking && this.listenerKey_ !== null) {
+ ol.events.unlistenByKey(this.listenerKey_);
+ this.listenerKey_ = null;
+ }
+ }
+};
+
+
+/**
+ * Enable or disable tracking of device orientation events.
+ * @param {boolean} tracking The status of tracking changes to alpha, beta and
+ * gamma. If true, changes are tracked and reported immediately.
+ * @observable
+ * @api
+ */
+ol.DeviceOrientation.prototype.setTracking = function(tracking) {
+ this.set(ol.DeviceOrientationProperty.TRACKING, tracking);
+};
+
+goog.provide('ol.format.Feature');
+
+goog.require('ol.geom.Geometry');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for feature formats.
+ * {ol.format.Feature} subclasses provide the ability to decode and encode
+ * {@link ol.Feature} objects from a variety of commonly used geospatial
+ * file formats. See the documentation for each format for more details.
+ *
+ * @constructor
+ * @api stable
+ */
+ol.format.Feature = function() {
+
+ /**
+ * @protected
+ * @type {ol.proj.Projection}
+ */
+ this.defaultDataProjection = null;
+
+};
+
+
+/**
+ * @return {Array.<string>} Extensions.
+ */
+ol.format.Feature.prototype.getExtensions = goog.abstractMethod;
+
+
+/**
+ * Adds the data projection to the read options.
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @return {olx.format.ReadOptions|undefined} Options.
+ * @protected
+ */
+ol.format.Feature.prototype.getReadOptions = function(source, opt_options) {
+ var options;
+ if (opt_options) {
+ options = {
+ dataProjection: opt_options.dataProjection ?
+ opt_options.dataProjection : this.readProjection(source),
+ featureProjection: opt_options.featureProjection
+ };
+ }
+ return this.adaptOptions(options);
+};
+
+
+/**
+ * Sets the `defaultDataProjection` on the options, if no `dataProjection`
+ * is set.
+ * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options
+ * Options.
+ * @protected
+ * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined}
+ * Updated options.
+ */
+ol.format.Feature.prototype.adaptOptions = function(options) {
+ var updatedOptions;
+ if (options) {
+ updatedOptions = {
+ featureProjection: options.featureProjection,
+ dataProjection: options.dataProjection ?
+ options.dataProjection : this.defaultDataProjection,
+ rightHanded: options.rightHanded
+ };
+ if (options.decimals) {
+ updatedOptions.decimals = options.decimals;
+ }
+ }
+ return updatedOptions;
+};
+
+
+/**
+ * @return {ol.format.FormatType} Format.
+ */
+ol.format.Feature.prototype.getType = goog.abstractMethod;
+
+
+/**
+ * Read a single feature from a source.
+ *
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ */
+ol.format.Feature.prototype.readFeature = goog.abstractMethod;
+
+
+/**
+ * Read all features from a source.
+ *
+ * @param {Document|Node|ArrayBuffer|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.format.Feature.prototype.readFeatures = goog.abstractMethod;
+
+
+/**
+ * Read a single geometry from a source.
+ *
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.Feature.prototype.readGeometry = goog.abstractMethod;
+
+
+/**
+ * Read the projection from a source.
+ *
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.format.Feature.prototype.readProjection = goog.abstractMethod;
+
+
+/**
+ * Encode a feature in this format.
+ *
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} Result.
+ */
+ol.format.Feature.prototype.writeFeature = goog.abstractMethod;
+
+
+/**
+ * Encode an array of features in this format.
+ *
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} Result.
+ */
+ol.format.Feature.prototype.writeFeatures = goog.abstractMethod;
+
+
+/**
+ * Write a single geometry in this format.
+ *
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} Result.
+ */
+ol.format.Feature.prototype.writeGeometry = goog.abstractMethod;
+
+
+/**
+ * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.
+ * @param {boolean} write Set to true for writing, false for reading.
+ * @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options
+ * Options.
+ * @return {ol.geom.Geometry|ol.Extent} Transformed geometry.
+ * @protected
+ */
+ol.format.Feature.transformWithOptions = function(
+ geometry, write, opt_options) {
+ var featureProjection = opt_options ?
+ ol.proj.get(opt_options.featureProjection) : null;
+ var dataProjection = opt_options ?
+ ol.proj.get(opt_options.dataProjection) : null;
+ /**
+ * @type {ol.geom.Geometry|ol.Extent}
+ */
+ var transformed;
+ if (featureProjection && dataProjection &&
+ !ol.proj.equivalent(featureProjection, dataProjection)) {
+ if (geometry instanceof ol.geom.Geometry) {
+ transformed = (write ? geometry.clone() : geometry).transform(
+ write ? featureProjection : dataProjection,
+ write ? dataProjection : featureProjection);
+ } else {
+ // FIXME this is necessary because ol.format.GML treats extents
+ // as geometries
+ transformed = ol.proj.transformExtent(
+ write ? geometry.slice() : geometry,
+ write ? featureProjection : dataProjection,
+ write ? dataProjection : featureProjection);
+ }
+ } else {
+ transformed = geometry;
+ }
+ if (write && opt_options && opt_options.decimals) {
+ var power = Math.pow(10, opt_options.decimals);
+ // if decimals option on write, round each coordinate appropriately
+ /**
+ * @param {Array.<number>} coordinates Coordinates.
+ * @return {Array.<number>} Transformed coordinates.
+ */
+ var transform = function(coordinates) {
+ for (var i = 0, ii = coordinates.length; i < ii; ++i) {
+ coordinates[i] = Math.round(coordinates[i] * power) / power;
+ }
+ return coordinates;
+ };
+ if (Array.isArray(transformed)) {
+ transform(transformed);
+ } else {
+ transformed.applyTransform(transform);
+ }
+ }
+ return transformed;
+};
+
+goog.provide('ol.format.JSONFeature');
+
+goog.require('goog.asserts');
+goog.require('ol.format.Feature');
+goog.require('ol.format.FormatType');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for JSON feature formats.
+ *
+ * @constructor
+ * @extends {ol.format.Feature}
+ */
+ol.format.JSONFeature = function() {
+ ol.format.Feature.call(this);
+};
+ol.inherits(ol.format.JSONFeature, ol.format.Feature);
+
+
+/**
+ * @param {Document|Node|Object|string} source Source.
+ * @private
+ * @return {Object} Object.
+ */
+ol.format.JSONFeature.prototype.getObject_ = function(source) {
+ if (goog.isObject(source)) {
+ return source;
+ } else if (typeof source === 'string') {
+ var object = JSON.parse(source);
+ return object ? /** @type {Object} */ (object) : null;
+ } else {
+ goog.asserts.fail();
+ return null;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.getType = function() {
+ return ol.format.FormatType.JSON;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.readFeature = function(source, opt_options) {
+ return this.readFeatureFromObject(
+ this.getObject_(source), this.getReadOptions(source, opt_options));
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) {
+ return this.readFeaturesFromObject(
+ this.getObject_(source), this.getReadOptions(source, opt_options));
+};
+
+
+/**
+ * @param {Object} object Object.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @protected
+ * @return {ol.Feature} Feature.
+ */
+ol.format.JSONFeature.prototype.readFeatureFromObject = goog.abstractMethod;
+
+
+/**
+ * @param {Object} object Object.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @protected
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.format.JSONFeature.prototype.readFeaturesFromObject = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) {
+ return this.readGeometryFromObject(
+ this.getObject_(source), this.getReadOptions(source, opt_options));
+};
+
+
+/**
+ * @param {Object} object Object.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @protected
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.JSONFeature.prototype.readGeometryFromObject = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.readProjection = function(source) {
+ return this.readProjectionFromObject(this.getObject_(source));
+};
+
+
+/**
+ * @param {Object} object Object.
+ * @protected
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.format.JSONFeature.prototype.readProjectionFromObject = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) {
+ return JSON.stringify(this.writeFeatureObject(feature, opt_options));
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {Object} Object.
+ */
+ol.format.JSONFeature.prototype.writeFeatureObject = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.writeFeatures = function(features, opt_options) {
+ return JSON.stringify(this.writeFeaturesObject(features, opt_options));
+};
+
+
+/**
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {Object} Object.
+ */
+ol.format.JSONFeature.prototype.writeFeaturesObject = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.JSONFeature.prototype.writeGeometry = function(geometry, opt_options) {
+ return JSON.stringify(this.writeGeometryObject(geometry, opt_options));
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {Object} Object.
+ */
+ol.format.JSONFeature.prototype.writeGeometryObject = goog.abstractMethod;
+
+goog.provide('ol.geom.flat.interpolate');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.math');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} fraction Fraction.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @return {Array.<number>} Destination.
+ */
+ol.geom.flat.interpolate.lineString = function(flatCoordinates, offset, end, stride, fraction, opt_dest) {
+ // FIXME does not work when vertices are repeated
+ // FIXME interpolate extra dimensions
+ goog.asserts.assert(0 <= fraction && fraction <= 1,
+ 'fraction should be in between 0 and 1');
+ var pointX = NaN;
+ var pointY = NaN;
+ var n = (end - offset) / stride;
+ if (n === 0) {
+ goog.asserts.fail('n cannot be 0');
+ } else if (n == 1) {
+ pointX = flatCoordinates[offset];
+ pointY = flatCoordinates[offset + 1];
+ } else if (n == 2) {
+ pointX = (1 - fraction) * flatCoordinates[offset] +
+ fraction * flatCoordinates[offset + stride];
+ pointY = (1 - fraction) * flatCoordinates[offset + 1] +
+ fraction * flatCoordinates[offset + stride + 1];
+ } else {
+ var x1 = flatCoordinates[offset];
+ var y1 = flatCoordinates[offset + 1];
+ var length = 0;
+ var cumulativeLengths = [0];
+ var i;
+ for (i = offset + stride; i < end; i += stride) {
+ var x2 = flatCoordinates[i];
+ var y2 = flatCoordinates[i + 1];
+ length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
+ cumulativeLengths.push(length);
+ x1 = x2;
+ y1 = y2;
+ }
+ var target = fraction * length;
+ var index = ol.array.binarySearch(cumulativeLengths, target);
+ if (index < 0) {
+ var t = (target - cumulativeLengths[-index - 2]) /
+ (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);
+ var o = offset + (-index - 2) * stride;
+ pointX = ol.math.lerp(
+ flatCoordinates[o], flatCoordinates[o + stride], t);
+ pointY = ol.math.lerp(
+ flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t);
+ } else {
+ pointX = flatCoordinates[offset + index * stride];
+ pointY = flatCoordinates[offset + index * stride + 1];
+ }
+ }
+ if (opt_dest) {
+ opt_dest[0] = pointX;
+ opt_dest[1] = pointY;
+ return opt_dest;
+ } else {
+ return [pointX, pointY];
+ }
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {number} m M.
+ * @param {boolean} extrapolate Extrapolate.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ol.geom.flat.lineStringCoordinateAtM = function(flatCoordinates, offset, end, stride, m, extrapolate) {
+ if (end == offset) {
+ return null;
+ }
+ var coordinate;
+ if (m < flatCoordinates[offset + stride - 1]) {
+ if (extrapolate) {
+ coordinate = flatCoordinates.slice(offset, offset + stride);
+ coordinate[stride - 1] = m;
+ return coordinate;
+ } else {
+ return null;
+ }
+ } else if (flatCoordinates[end - 1] < m) {
+ if (extrapolate) {
+ coordinate = flatCoordinates.slice(end - stride, end);
+ coordinate[stride - 1] = m;
+ return coordinate;
+ } else {
+ return null;
+ }
+ }
+ // FIXME use O(1) search
+ if (m == flatCoordinates[offset + stride - 1]) {
+ return flatCoordinates.slice(offset, offset + stride);
+ }
+ var lo = offset / stride;
+ var hi = end / stride;
+ while (lo < hi) {
+ var mid = (lo + hi) >> 1;
+ if (m < flatCoordinates[(mid + 1) * stride - 1]) {
+ hi = mid;
+ } else {
+ lo = mid + 1;
+ }
+ }
+ var m0 = flatCoordinates[lo * stride - 1];
+ if (m == m0) {
+ return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);
+ }
+ var m1 = flatCoordinates[(lo + 1) * stride - 1];
+ goog.asserts.assert(m0 < m, 'm0 should be less than m');
+ goog.asserts.assert(m <= m1, 'm should be less than or equal to m1');
+ var t = (m - m0) / (m1 - m0);
+ coordinate = [];
+ var i;
+ for (i = 0; i < stride - 1; ++i) {
+ coordinate.push(ol.math.lerp(flatCoordinates[(lo - 1) * stride + i],
+ flatCoordinates[lo * stride + i], t));
+ }
+ coordinate.push(m);
+ goog.asserts.assert(coordinate.length == stride,
+ 'length of coordinate array should match stride');
+ return coordinate;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<number>} ends Ends.
+ * @param {number} stride Stride.
+ * @param {number} m M.
+ * @param {boolean} extrapolate Extrapolate.
+ * @param {boolean} interpolate Interpolate.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ol.geom.flat.lineStringsCoordinateAtM = function(
+ flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) {
+ if (interpolate) {
+ return ol.geom.flat.lineStringCoordinateAtM(
+ flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate);
+ }
+ var coordinate;
+ if (m < flatCoordinates[stride - 1]) {
+ if (extrapolate) {
+ coordinate = flatCoordinates.slice(0, stride);
+ coordinate[stride - 1] = m;
+ return coordinate;
+ } else {
+ return null;
+ }
+ }
+ if (flatCoordinates[flatCoordinates.length - 1] < m) {
+ if (extrapolate) {
+ coordinate = flatCoordinates.slice(flatCoordinates.length - stride);
+ coordinate[stride - 1] = m;
+ return coordinate;
+ } else {
+ return null;
+ }
+ }
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ if (offset == end) {
+ continue;
+ }
+ if (m < flatCoordinates[offset + stride - 1]) {
+ return null;
+ } else if (m <= flatCoordinates[end - 1]) {
+ return ol.geom.flat.lineStringCoordinateAtM(
+ flatCoordinates, offset, end, stride, m, false);
+ }
+ offset = end;
+ }
+ goog.asserts.fail(
+ 'ol.geom.flat.lineStringsCoordinateAtM should have returned');
+ return null;
+};
+
+goog.provide('ol.geom.flat.length');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @return {number} Length.
+ */
+ol.geom.flat.length.lineString = function(flatCoordinates, offset, end, stride) {
+ var x1 = flatCoordinates[offset];
+ var y1 = flatCoordinates[offset + 1];
+ var length = 0;
+ var i;
+ for (i = offset + stride; i < end; i += stride) {
+ var x2 = flatCoordinates[i];
+ var y2 = flatCoordinates[i + 1];
+ length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
+ x1 = x2;
+ y1 = y2;
+ }
+ return length;
+};
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @return {number} Perimeter.
+ */
+ol.geom.flat.length.linearRing = function(flatCoordinates, offset, end, stride) {
+ var perimeter =
+ ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride);
+ var dx = flatCoordinates[end - stride] - flatCoordinates[offset];
+ var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];
+ perimeter += Math.sqrt(dx * dx + dy * dy);
+ return perimeter;
+};
+
+goog.provide('ol.geom.LineString');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.closest');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.geom.flat.interpolate');
+goog.require('ol.geom.flat.intersectsextent');
+goog.require('ol.geom.flat.length');
+goog.require('ol.geom.flat.segments');
+goog.require('ol.geom.flat.simplify');
+
+
+/**
+ * @classdesc
+ * Linestring geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.LineString = function(coordinates, opt_layout) {
+
+ ol.geom.SimpleGeometry.call(this);
+
+ /**
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.flatMidpoint_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.flatMidpointRevision_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDelta_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDeltaRevision_ = -1;
+
+ this.setCoordinates(coordinates, opt_layout);
+
+};
+ol.inherits(ol.geom.LineString, ol.geom.SimpleGeometry);
+
+
+/**
+ * Append the passed coordinate to the coordinates of the linestring.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @api stable
+ */
+ol.geom.LineString.prototype.appendCoordinate = function(coordinate) {
+ goog.asserts.assert(coordinate.length == this.stride,
+ 'length of coordinate array should match stride');
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = coordinate.slice();
+ } else {
+ ol.array.extend(this.flatCoordinates, coordinate);
+ }
+ this.changed();
+};
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.LineString} Clone.
+ * @api stable
+ */
+ol.geom.LineString.prototype.clone = function() {
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
+ return lineString;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.LineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ if (this.maxDeltaRevision_ != this.getRevision()) {
+ this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
+ this.maxDeltaRevision_ = this.getRevision();
+ }
+ return ol.geom.flat.closest.getClosestPoint(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
+};
+
+
+/**
+ * Iterate over each segment, calling the provided callback.
+ * If the callback returns a truthy value the function returns that
+ * value immediately. Otherwise the function returns `false`.
+ *
+ * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
+ * called for each segment.
+ * @param {S=} opt_this The object to be used as the value of 'this'
+ * within callback.
+ * @return {T|boolean} Value.
+ * @template T,S
+ * @api
+ */
+ol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) {
+ return ol.geom.flat.segments.forEach(this.flatCoordinates, 0,
+ this.flatCoordinates.length, this.stride, callback, opt_this);
+};
+
+
+/**
+ * Returns the coordinate at `m` using linear interpolation, or `null` if no
+ * such coordinate exists.
+ *
+ * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
+ * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
+ * M will return the first coordinate and Ms greater than the last M will
+ * return the last coordinate.
+ *
+ * @param {number} m M.
+ * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
+ * @return {ol.Coordinate} Coordinate.
+ * @api stable
+ */
+ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
+ if (this.layout != ol.geom.GeometryLayout.XYM &&
+ this.layout != ol.geom.GeometryLayout.XYZM) {
+ return null;
+ }
+ var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
+ return ol.geom.flat.lineStringCoordinateAtM(this.flatCoordinates, 0,
+ this.flatCoordinates.length, this.stride, m, extrapolate);
+};
+
+
+/**
+ * Return the coordinates of the linestring.
+ * @return {Array.<ol.Coordinate>} Coordinates.
+ * @api stable
+ */
+ol.geom.LineString.prototype.getCoordinates = function() {
+ return ol.geom.flat.inflate.coordinates(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
+};
+
+
+/**
+ * Return the coordinate at the provided fraction along the linestring.
+ * The `fraction` is a number between 0 and 1, where 0 is the start of the
+ * linestring and 1 is the end.
+ * @param {number} fraction Fraction.
+ * @param {ol.Coordinate=} opt_dest Optional coordinate whose values will
+ * be modified. If not provided, a new coordinate will be returned.
+ * @return {ol.Coordinate} Coordinate of the interpolated point.
+ * @api
+ */
+ol.geom.LineString.prototype.getCoordinateAt = function(fraction, opt_dest) {
+ return ol.geom.flat.interpolate.lineString(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ fraction, opt_dest);
+};
+
+
+/**
+ * Return the length of the linestring on projected plane.
+ * @return {number} Length (on projected plane).
+ * @api stable
+ */
+ol.geom.LineString.prototype.getLength = function() {
+ return ol.geom.flat.length.lineString(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
+};
+
+
+/**
+ * @return {Array.<number>} Flat midpoint.
+ */
+ol.geom.LineString.prototype.getFlatMidpoint = function() {
+ if (this.flatMidpointRevision_ != this.getRevision()) {
+ this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);
+ this.flatMidpointRevision_ = this.getRevision();
+ }
+ return this.flatMidpoint_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.LineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
+ var simplifiedFlatCoordinates = [];
+ simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ squaredTolerance, simplifiedFlatCoordinates, 0);
+ var simplifiedLineString = new ol.geom.LineString(null);
+ simplifiedLineString.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
+ return simplifiedLineString;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.LineString.prototype.getType = function() {
+ return ol.geom.GeometryType.LINE_STRING;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.LineString.prototype.intersectsExtent = function(extent) {
+ return ol.geom.flat.intersectsextent.lineString(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
+ extent);
+};
+
+
+/**
+ * Set the coordinates of the linestring.
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.LineString.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
+ } else {
+ this.setLayout(opt_layout, coordinates, 1);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
+ this.flatCoordinates, 0, coordinates, this.stride);
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ */
+ol.geom.LineString.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.changed();
+};
+
+goog.provide('ol.geom.MultiLineString');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.closest');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.geom.flat.interpolate');
+goog.require('ol.geom.flat.intersectsextent');
+goog.require('ol.geom.flat.simplify');
+
+
+/**
+ * @classdesc
+ * Multi-linestring geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.MultiLineString = function(coordinates, opt_layout) {
+
+ ol.geom.SimpleGeometry.call(this);
+
+ /**
+ * @type {Array.<number>}
+ * @private
+ */
+ this.ends_ = [];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDelta_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDeltaRevision_ = -1;
+
+ this.setCoordinates(coordinates, opt_layout);
+
+};
+ol.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry);
+
+
+/**
+ * Append the passed linestring to the multilinestring.
+ * @param {ol.geom.LineString} lineString LineString.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.appendLineString = function(lineString) {
+ goog.asserts.assert(lineString.getLayout() == this.layout,
+ 'layout of lineString should match the layout');
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = lineString.getFlatCoordinates().slice();
+ } else {
+ ol.array.extend(
+ this.flatCoordinates, lineString.getFlatCoordinates().slice());
+ }
+ this.ends_.push(this.flatCoordinates.length);
+ this.changed();
+};
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.MultiLineString} Clone.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.clone = function() {
+ var multiLineString = new ol.geom.MultiLineString(null);
+ multiLineString.setFlatCoordinates(
+ this.layout, this.flatCoordinates.slice(), this.ends_.slice());
+ return multiLineString;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.MultiLineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ if (this.maxDeltaRevision_ != this.getRevision()) {
+ this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(
+ this.flatCoordinates, 0, this.ends_, this.stride, 0));
+ this.maxDeltaRevision_ = this.getRevision();
+ }
+ return ol.geom.flat.closest.getsClosestPoint(
+ this.flatCoordinates, 0, this.ends_, this.stride,
+ this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
+};
+
+
+/**
+ * Returns the coordinate at `m` using linear interpolation, or `null` if no
+ * such coordinate exists.
+ *
+ * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
+ * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
+ * M will return the first coordinate and Ms greater than the last M will
+ * return the last coordinate.
+ *
+ * `opt_interpolate` controls interpolation between consecutive LineStrings
+ * within the MultiLineString. If `opt_interpolate` is `true` the coordinates
+ * will be linearly interpolated between the last coordinate of one LineString
+ * and the first coordinate of the next LineString. If `opt_interpolate` is
+ * `false` then the function will return `null` for Ms falling between
+ * LineStrings.
+ *
+ * @param {number} m M.
+ * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
+ * @param {boolean=} opt_interpolate Interpolate. Default is `false`.
+ * @return {ol.Coordinate} Coordinate.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.getCoordinateAtM = function(m, opt_extrapolate, opt_interpolate) {
+ if ((this.layout != ol.geom.GeometryLayout.XYM &&
+ this.layout != ol.geom.GeometryLayout.XYZM) ||
+ this.flatCoordinates.length === 0) {
+ return null;
+ }
+ var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
+ var interpolate = opt_interpolate !== undefined ? opt_interpolate : false;
+ return ol.geom.flat.lineStringsCoordinateAtM(this.flatCoordinates, 0,
+ this.ends_, this.stride, m, extrapolate, interpolate);
+};
+
+
+/**
+ * Return the coordinates of the multilinestring.
+ * @return {Array.<Array.<ol.Coordinate>>} Coordinates.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.getCoordinates = function() {
+ return ol.geom.flat.inflate.coordinatess(
+ this.flatCoordinates, 0, this.ends_, this.stride);
+};
+
+
+/**
+ * @return {Array.<number>} Ends.
+ */
+ol.geom.MultiLineString.prototype.getEnds = function() {
+ return this.ends_;
+};
+
+
+/**
+ * Return the linestring at the specified index.
+ * @param {number} index Index.
+ * @return {ol.geom.LineString} LineString.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.getLineString = function(index) {
+ goog.asserts.assert(0 <= index && index < this.ends_.length,
+ 'index should be in between 0 and length of the this.ends_ array');
+ if (index < 0 || this.ends_.length <= index) {
+ return null;
+ }
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
+ index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));
+ return lineString;
+};
+
+
+/**
+ * Return the linestrings of this multilinestring.
+ * @return {Array.<ol.geom.LineString>} LineStrings.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.getLineStrings = function() {
+ var flatCoordinates = this.flatCoordinates;
+ var ends = this.ends_;
+ var layout = this.layout;
+ /** @type {Array.<ol.geom.LineString>} */
+ var lineStrings = [];
+ var offset = 0;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));
+ lineStrings.push(lineString);
+ offset = end;
+ }
+ return lineStrings;
+};
+
+
+/**
+ * @return {Array.<number>} Flat midpoints.
+ */
+ol.geom.MultiLineString.prototype.getFlatMidpoints = function() {
+ var midpoints = [];
+ var flatCoordinates = this.flatCoordinates;
+ var offset = 0;
+ var ends = this.ends_;
+ var stride = this.stride;
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ var end = ends[i];
+ var midpoint = ol.geom.flat.interpolate.lineString(
+ flatCoordinates, offset, end, stride, 0.5);
+ ol.array.extend(midpoints, midpoint);
+ offset = end;
+ }
+ return midpoints;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
+ var simplifiedFlatCoordinates = [];
+ var simplifiedEnds = [];
+ simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers(
+ this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance,
+ simplifiedFlatCoordinates, 0, simplifiedEnds);
+ var simplifiedMultiLineString = new ol.geom.MultiLineString(null);
+ simplifiedMultiLineString.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);
+ return simplifiedMultiLineString;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.getType = function() {
+ return ol.geom.GeometryType.MULTI_LINE_STRING;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) {
+ return ol.geom.flat.intersectsextent.lineStrings(
+ this.flatCoordinates, 0, this.ends_, this.stride, extent);
+};
+
+
+/**
+ * Set the coordinates of the multilinestring.
+ * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.MultiLineString.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);
+ } else {
+ this.setLayout(opt_layout, coordinates, 2);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ var ends = ol.geom.flat.deflate.coordinatess(
+ this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
+ this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {Array.<number>} ends Ends.
+ */
+ol.geom.MultiLineString.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {
+ if (!flatCoordinates) {
+ goog.asserts.assert(ends && ends.length === 0,
+ 'ends must be truthy and ends.length should be 0');
+ } else if (ends.length === 0) {
+ goog.asserts.assert(flatCoordinates.length === 0,
+ 'flatCoordinates should be an empty array');
+ } else {
+ goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1],
+ 'length of flatCoordinates array should match the last value of ends');
+ }
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.ends_ = ends;
+ this.changed();
+};
+
+
+/**
+ * @param {Array.<ol.geom.LineString>} lineStrings LineStrings.
+ */
+ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) {
+ var layout = this.getLayout();
+ var flatCoordinates = [];
+ var ends = [];
+ var i, ii;
+ for (i = 0, ii = lineStrings.length; i < ii; ++i) {
+ var lineString = lineStrings[i];
+ if (i === 0) {
+ layout = lineString.getLayout();
+ } else {
+ // FIXME better handle the case of non-matching layouts
+ goog.asserts.assert(lineString.getLayout() == layout,
+ 'layout of lineString should match layout');
+ }
+ ol.array.extend(flatCoordinates, lineString.getFlatCoordinates());
+ ends.push(flatCoordinates.length);
+ }
+ this.setFlatCoordinates(layout, flatCoordinates, ends);
+};
+
+goog.provide('ol.geom.MultiPoint');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.math');
+
+
+/**
+ * @classdesc
+ * Multi-point geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.MultiPoint = function(coordinates, opt_layout) {
+ ol.geom.SimpleGeometry.call(this);
+ this.setCoordinates(coordinates, opt_layout);
+};
+ol.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry);
+
+
+/**
+ * Append the passed point to this multipoint.
+ * @param {ol.geom.Point} point Point.
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.appendPoint = function(point) {
+ goog.asserts.assert(point.getLayout() == this.layout,
+ 'the layout of point should match layout');
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = point.getFlatCoordinates().slice();
+ } else {
+ ol.array.extend(this.flatCoordinates, point.getFlatCoordinates());
+ }
+ this.changed();
+};
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.MultiPoint} Clone.
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.clone = function() {
+ var multiPoint = new ol.geom.MultiPoint(null);
+ multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
+ return multiPoint;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.MultiPoint.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ var flatCoordinates = this.flatCoordinates;
+ var stride = this.stride;
+ var i, ii, j;
+ for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
+ var squaredDistance = ol.math.squaredDistance(
+ x, y, flatCoordinates[i], flatCoordinates[i + 1]);
+ if (squaredDistance < minSquaredDistance) {
+ minSquaredDistance = squaredDistance;
+ for (j = 0; j < stride; ++j) {
+ closestPoint[j] = flatCoordinates[i + j];
+ }
+ closestPoint.length = stride;
+ }
+ }
+ return minSquaredDistance;
+};
+
+
+/**
+ * Return the coordinates of the multipoint.
+ * @return {Array.<ol.Coordinate>} Coordinates.
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.getCoordinates = function() {
+ return ol.geom.flat.inflate.coordinates(
+ this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
+};
+
+
+/**
+ * Return the point at the specified index.
+ * @param {number} index Index.
+ * @return {ol.geom.Point} Point.
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.getPoint = function(index) {
+ var n = !this.flatCoordinates ?
+ 0 : this.flatCoordinates.length / this.stride;
+ goog.asserts.assert(0 <= index && index < n,
+ 'index should be in between 0 and n');
+ if (index < 0 || n <= index) {
+ return null;
+ }
+ var point = new ol.geom.Point(null);
+ point.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
+ index * this.stride, (index + 1) * this.stride));
+ return point;
+};
+
+
+/**
+ * Return the points of this multipoint.
+ * @return {Array.<ol.geom.Point>} Points.
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.getPoints = function() {
+ var flatCoordinates = this.flatCoordinates;
+ var layout = this.layout;
+ var stride = this.stride;
+ /** @type {Array.<ol.geom.Point>} */
+ var points = [];
+ var i, ii;
+ for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
+ var point = new ol.geom.Point(null);
+ point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride));
+ points.push(point);
+ }
+ return points;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.getType = function() {
+ return ol.geom.GeometryType.MULTI_POINT;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) {
+ var flatCoordinates = this.flatCoordinates;
+ var stride = this.stride;
+ var i, ii, x, y;
+ for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
+ x = flatCoordinates[i];
+ y = flatCoordinates[i + 1];
+ if (ol.extent.containsXY(extent, x, y)) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Set the coordinates of the multipoint.
+ * @param {Array.<ol.Coordinate>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.MultiPoint.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
+ } else {
+ this.setLayout(opt_layout, coordinates, 1);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
+ this.flatCoordinates, 0, coordinates, this.stride);
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ */
+ol.geom.MultiPoint.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.changed();
+};
+
+goog.provide('ol.geom.flat.center');
+
+goog.require('ol.extent');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {Array.<Array.<number>>} endss Endss.
+ * @param {number} stride Stride.
+ * @return {Array.<number>} Flat centers.
+ */
+ol.geom.flat.center.linearRingss = function(flatCoordinates, offset, endss, stride) {
+ var flatCenters = [];
+ var i, ii;
+ var extent = ol.extent.createEmpty();
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i];
+ extent = ol.extent.createOrUpdateFromFlatCoordinates(
+ flatCoordinates, offset, ends[0], stride);
+ flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2);
+ offset = ends[ends.length - 1];
+ }
+ return flatCenters;
+};
+
+goog.provide('ol.geom.MultiPolygon');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.Polygon');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.area');
+goog.require('ol.geom.flat.center');
+goog.require('ol.geom.flat.closest');
+goog.require('ol.geom.flat.contains');
+goog.require('ol.geom.flat.deflate');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.geom.flat.interiorpoint');
+goog.require('ol.geom.flat.intersectsextent');
+goog.require('ol.geom.flat.orient');
+goog.require('ol.geom.flat.simplify');
+
+
+/**
+ * @classdesc
+ * Multi-polygon geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.MultiPolygon = function(coordinates, opt_layout) {
+
+ ol.geom.SimpleGeometry.call(this);
+
+ /**
+ * @type {Array.<Array.<number>>}
+ * @private
+ */
+ this.endss_ = [];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.flatInteriorPointsRevision_ = -1;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.flatInteriorPoints_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDelta_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxDeltaRevision_ = -1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.orientedRevision_ = -1;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.orientedFlatCoordinates_ = null;
+
+ this.setCoordinates(coordinates, opt_layout);
+
+};
+ol.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry);
+
+
+/**
+ * Append the passed polygon to this multipolygon.
+ * @param {ol.geom.Polygon} polygon Polygon.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) {
+ goog.asserts.assert(polygon.getLayout() == this.layout,
+ 'layout of polygon should match layout');
+ /** @type {Array.<number>} */
+ var ends;
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = polygon.getFlatCoordinates().slice();
+ ends = polygon.getEnds().slice();
+ this.endss_.push();
+ } else {
+ var offset = this.flatCoordinates.length;
+ ol.array.extend(this.flatCoordinates, polygon.getFlatCoordinates());
+ ends = polygon.getEnds().slice();
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ ends[i] += offset;
+ }
+ }
+ this.endss_.push(ends);
+ this.changed();
+};
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.MultiPolygon} Clone.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.clone = function() {
+ var multiPolygon = new ol.geom.MultiPolygon(null);
+
+ var len = this.endss_.length;
+ var newEndss = new Array(len);
+ for (var i = 0; i < len; ++i) {
+ newEndss[i] = this.endss_[i].slice();
+ }
+
+ multiPolygon.setFlatCoordinates(
+ this.layout, this.flatCoordinates.slice(), newEndss);
+ return multiPolygon;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.MultiPolygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ if (this.maxDeltaRevision_ != this.getRevision()) {
+ this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta(
+ this.flatCoordinates, 0, this.endss_, this.stride, 0));
+ this.maxDeltaRevision_ = this.getRevision();
+ }
+ return ol.geom.flat.closest.getssClosestPoint(
+ this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
+ this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.MultiPolygon.prototype.containsXY = function(x, y) {
+ return ol.geom.flat.contains.linearRingssContainsXY(
+ this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y);
+};
+
+
+/**
+ * Return the area of the multipolygon on projected plane.
+ * @return {number} Area (on projected plane).
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.getArea = function() {
+ return ol.geom.flat.area.linearRingss(
+ this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride);
+};
+
+
+/**
+ * Get the coordinate array for this geometry. This array has the structure
+ * of a GeoJSON coordinate array for multi-polygons.
+ *
+ * @param {boolean=} opt_right Orient coordinates according to the right-hand
+ * rule (counter-clockwise for exterior and clockwise for interior rings).
+ * If `false`, coordinates will be oriented according to the left-hand rule
+ * (clockwise for exterior and counter-clockwise for interior rings).
+ * By default, coordinate orientation will depend on how the geometry was
+ * constructed.
+ * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) {
+ var flatCoordinates;
+ if (opt_right !== undefined) {
+ flatCoordinates = this.getOrientedFlatCoordinates().slice();
+ ol.geom.flat.orient.orientLinearRingss(
+ flatCoordinates, 0, this.endss_, this.stride, opt_right);
+ } else {
+ flatCoordinates = this.flatCoordinates;
+ }
+
+ return ol.geom.flat.inflate.coordinatesss(
+ flatCoordinates, 0, this.endss_, this.stride);
+};
+
+
+/**
+ * @return {Array.<Array.<number>>} Endss.
+ */
+ol.geom.MultiPolygon.prototype.getEndss = function() {
+ return this.endss_;
+};
+
+
+/**
+ * @return {Array.<number>} Flat interior points.
+ */
+ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() {
+ if (this.flatInteriorPointsRevision_ != this.getRevision()) {
+ var flatCenters = ol.geom.flat.center.linearRingss(
+ this.flatCoordinates, 0, this.endss_, this.stride);
+ this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss(
+ this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
+ flatCenters);
+ this.flatInteriorPointsRevision_ = this.getRevision();
+ }
+ return this.flatInteriorPoints_;
+};
+
+
+/**
+ * Return the interior points as {@link ol.geom.MultiPoint multipoint}.
+ * @return {ol.geom.MultiPoint} Interior points.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.getInteriorPoints = function() {
+ var interiorPoints = new ol.geom.MultiPoint(null);
+ interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY,
+ this.getFlatInteriorPoints().slice());
+ return interiorPoints;
+};
+
+
+/**
+ * @return {Array.<number>} Oriented flat coordinates.
+ */
+ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() {
+ if (this.orientedRevision_ != this.getRevision()) {
+ var flatCoordinates = this.flatCoordinates;
+ if (ol.geom.flat.orient.linearRingssAreOriented(
+ flatCoordinates, 0, this.endss_, this.stride)) {
+ this.orientedFlatCoordinates_ = flatCoordinates;
+ } else {
+ this.orientedFlatCoordinates_ = flatCoordinates.slice();
+ this.orientedFlatCoordinates_.length =
+ ol.geom.flat.orient.orientLinearRingss(
+ this.orientedFlatCoordinates_, 0, this.endss_, this.stride);
+ }
+ this.orientedRevision_ = this.getRevision();
+ }
+ return this.orientedFlatCoordinates_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
+ var simplifiedFlatCoordinates = [];
+ var simplifiedEndss = [];
+ simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess(
+ this.flatCoordinates, 0, this.endss_, this.stride,
+ Math.sqrt(squaredTolerance),
+ simplifiedFlatCoordinates, 0, simplifiedEndss);
+ var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null);
+ simplifiedMultiPolygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss);
+ return simplifiedMultiPolygon;
+};
+
+
+/**
+ * Return the polygon at the specified index.
+ * @param {number} index Index.
+ * @return {ol.geom.Polygon} Polygon.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.getPolygon = function(index) {
+ goog.asserts.assert(0 <= index && index < this.endss_.length,
+ 'index should be in between 0 and the length of this.endss_');
+ if (index < 0 || this.endss_.length <= index) {
+ return null;
+ }
+ var offset;
+ if (index === 0) {
+ offset = 0;
+ } else {
+ var prevEnds = this.endss_[index - 1];
+ offset = prevEnds[prevEnds.length - 1];
+ }
+ var ends = this.endss_[index].slice();
+ var end = ends[ends.length - 1];
+ if (offset !== 0) {
+ var i, ii;
+ for (i = 0, ii = ends.length; i < ii; ++i) {
+ ends[i] -= offset;
+ }
+ }
+ var polygon = new ol.geom.Polygon(null);
+ polygon.setFlatCoordinates(
+ this.layout, this.flatCoordinates.slice(offset, end), ends);
+ return polygon;
+};
+
+
+/**
+ * Return the polygons of this multipolygon.
+ * @return {Array.<ol.geom.Polygon>} Polygons.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.getPolygons = function() {
+ var layout = this.layout;
+ var flatCoordinates = this.flatCoordinates;
+ var endss = this.endss_;
+ var polygons = [];
+ var offset = 0;
+ var i, ii, j, jj;
+ for (i = 0, ii = endss.length; i < ii; ++i) {
+ var ends = endss[i].slice();
+ var end = ends[ends.length - 1];
+ if (offset !== 0) {
+ for (j = 0, jj = ends.length; j < jj; ++j) {
+ ends[j] -= offset;
+ }
+ }
+ var polygon = new ol.geom.Polygon(null);
+ polygon.setFlatCoordinates(
+ layout, flatCoordinates.slice(offset, end), ends);
+ polygons.push(polygon);
+ offset = end;
+ }
+ return polygons;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.getType = function() {
+ return ol.geom.GeometryType.MULTI_POLYGON;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) {
+ return ol.geom.flat.intersectsextent.linearRingss(
+ this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);
+};
+
+
+/**
+ * Set the coordinates of the multipolygon.
+ * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api stable
+ */
+ol.geom.MultiPolygon.prototype.setCoordinates = function(coordinates, opt_layout) {
+ if (!coordinates) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_);
+ } else {
+ this.setLayout(opt_layout, coordinates, 3);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ var endss = ol.geom.flat.deflate.coordinatesss(
+ this.flatCoordinates, 0, coordinates, this.stride, this.endss_);
+ if (endss.length === 0) {
+ this.flatCoordinates.length = 0;
+ } else {
+ var lastEnds = endss[endss.length - 1];
+ this.flatCoordinates.length = lastEnds.length === 0 ?
+ 0 : lastEnds[lastEnds.length - 1];
+ }
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {Array.<Array.<number>>} endss Endss.
+ */
+ol.geom.MultiPolygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, endss) {
+ goog.asserts.assert(endss, 'endss must be truthy');
+ if (!flatCoordinates || flatCoordinates.length === 0) {
+ goog.asserts.assert(endss.length === 0, 'the length of endss should be 0');
+ } else {
+ goog.asserts.assert(endss.length > 0, 'endss cannot be an empty array');
+ var ends = endss[endss.length - 1];
+ goog.asserts.assert(flatCoordinates.length == ends[ends.length - 1],
+ 'the length of flatCoordinates should be the last value of ends');
+ }
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.endss_ = endss;
+ this.changed();
+};
+
+
+/**
+ * @param {Array.<ol.geom.Polygon>} polygons Polygons.
+ */
+ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) {
+ var layout = this.getLayout();
+ var flatCoordinates = [];
+ var endss = [];
+ var i, ii, ends;
+ for (i = 0, ii = polygons.length; i < ii; ++i) {
+ var polygon = polygons[i];
+ if (i === 0) {
+ layout = polygon.getLayout();
+ } else {
+ // FIXME better handle the case of non-matching layouts
+ goog.asserts.assert(polygon.getLayout() == layout,
+ 'layout of polygon should be layout');
+ }
+ var offset = flatCoordinates.length;
+ ends = polygon.getEnds();
+ var j, jj;
+ for (j = 0, jj = ends.length; j < jj; ++j) {
+ ends[j] += offset;
+ }
+ ol.array.extend(flatCoordinates, polygon.getFlatCoordinates());
+ endss.push(ends);
+ }
+ this.setFlatCoordinates(layout, flatCoordinates, endss);
+};
+
+goog.provide('ol.format.EsriJSON');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.format.Feature');
+goog.require('ol.format.JSONFeature');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.LinearRing');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.geom.flat.orient');
+goog.require('ol.object');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the EsriJSON format.
+ *
+ * @constructor
+ * @extends {ol.format.JSONFeature}
+ * @param {olx.format.EsriJSONOptions=} opt_options Options.
+ * @api
+ */
+ol.format.EsriJSON = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.JSONFeature.call(this);
+
+ /**
+ * Name of the geometry attribute for features.
+ * @type {string|undefined}
+ * @private
+ */
+ this.geometryName_ = options.geometryName;
+
+};
+ol.inherits(ol.format.EsriJSON, ol.format.JSONFeature);
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @private
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.EsriJSON.readGeometry_ = function(object, opt_options) {
+ if (!object) {
+ return null;
+ }
+ var type;
+ if (goog.isNumber(object.x) && goog.isNumber(object.y)) {
+ type = ol.geom.GeometryType.POINT;
+ } else if (object.points) {
+ type = ol.geom.GeometryType.MULTI_POINT;
+ } else if (object.paths) {
+ if (object.paths.length === 1) {
+ type = ol.geom.GeometryType.LINE_STRING;
+ } else {
+ type = ol.geom.GeometryType.MULTI_LINE_STRING;
+ }
+ } else if (object.rings) {
+ var layout = ol.format.EsriJSON.getGeometryLayout_(object);
+ var rings = ol.format.EsriJSON.convertRings_(object.rings, layout);
+ object = /** @type {EsriJSONGeometry} */(ol.object.assign({}, object));
+ if (rings.length === 1) {
+ type = ol.geom.GeometryType.POLYGON;
+ object.rings = rings[0];
+ } else {
+ type = ol.geom.GeometryType.MULTI_POLYGON;
+ object.rings = rings;
+ }
+ }
+ goog.asserts.assert(type, 'geometry type should be defined');
+ var geometryReader = ol.format.EsriJSON.GEOMETRY_READERS_[type];
+ goog.asserts.assert(geometryReader,
+ 'geometryReader should be defined');
+ return /** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(
+ geometryReader(object), false, opt_options));
+};
+
+
+/**
+ * Determines inner and outer rings.
+ * Checks if any polygons in this array contain any other polygons in this
+ * array. It is used for checking for holes.
+ * Logic inspired by: https://github.com/Esri/terraformer-arcgis-parser
+ * @param {Array.<!Array.<!Array.<number>>>} rings Rings.
+ * @param {ol.geom.GeometryLayout} layout Geometry layout.
+ * @private
+ * @return {Array.<!Array.<!Array.<number>>>} Transoformed rings.
+ */
+ol.format.EsriJSON.convertRings_ = function(rings, layout) {
+ var outerRings = [];
+ var holes = [];
+ var i, ii;
+ for (i = 0, ii = rings.length; i < ii; ++i) {
+ var flatRing = ol.array.flatten(rings[i]);
+ // is this ring an outer ring? is it clockwise?
+ var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0,
+ flatRing.length, layout.length);
+ if (clockwise) {
+ outerRings.push([rings[i]]);
+ } else {
+ holes.push(rings[i]);
+ }
+ }
+ while (holes.length) {
+ var hole = holes.shift();
+ var matched = false;
+ // loop over all outer rings and see if they contain our hole.
+ for (i = outerRings.length - 1; i >= 0; i--) {
+ var outerRing = outerRings[i][0];
+ if (ol.extent.containsExtent(new ol.geom.LinearRing(
+ outerRing).getExtent(),
+ new ol.geom.LinearRing(hole).getExtent())) {
+ // the hole is contained push it into our polygon
+ outerRings[i].push(hole);
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ // no outer rings contain this hole turn it into and outer
+ // ring (reverse it)
+ outerRings.push([hole.reverse()]);
+ }
+ }
+ return outerRings;
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Geometry} Point.
+ */
+ol.format.EsriJSON.readPointGeometry_ = function(object) {
+ goog.asserts.assert(goog.isNumber(object.x), 'object.x should be number');
+ goog.asserts.assert(goog.isNumber(object.y), 'object.y should be number');
+ var point;
+ if (object.m !== undefined && object.z !== undefined) {
+ point = new ol.geom.Point([object.x, object.y, object.z, object.m],
+ ol.geom.GeometryLayout.XYZM);
+ } else if (object.z !== undefined) {
+ point = new ol.geom.Point([object.x, object.y, object.z],
+ ol.geom.GeometryLayout.XYZ);
+ } else if (object.m !== undefined) {
+ point = new ol.geom.Point([object.x, object.y, object.m],
+ ol.geom.GeometryLayout.XYM);
+ } else {
+ point = new ol.geom.Point([object.x, object.y]);
+ }
+ return point;
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Geometry} LineString.
+ */
+ol.format.EsriJSON.readLineStringGeometry_ = function(object) {
+ goog.asserts.assert(Array.isArray(object.paths),
+ 'object.paths should be an array');
+ goog.asserts.assert(object.paths.length === 1,
+ 'object.paths array length should be 1');
+ var layout = ol.format.EsriJSON.getGeometryLayout_(object);
+ return new ol.geom.LineString(object.paths[0], layout);
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Geometry} MultiLineString.
+ */
+ol.format.EsriJSON.readMultiLineStringGeometry_ = function(object) {
+ goog.asserts.assert(Array.isArray(object.paths),
+ 'object.paths should be an array');
+ goog.asserts.assert(object.paths.length > 1,
+ 'object.paths array length should be more than 1');
+ var layout = ol.format.EsriJSON.getGeometryLayout_(object);
+ return new ol.geom.MultiLineString(object.paths, layout);
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.GeometryLayout} The geometry layout to use.
+ */
+ol.format.EsriJSON.getGeometryLayout_ = function(object) {
+ var layout = ol.geom.GeometryLayout.XY;
+ if (object.hasZ === true && object.hasM === true) {
+ layout = ol.geom.GeometryLayout.XYZM;
+ } else if (object.hasZ === true) {
+ layout = ol.geom.GeometryLayout.XYZ;
+ } else if (object.hasM === true) {
+ layout = ol.geom.GeometryLayout.XYM;
+ }
+ return layout;
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Geometry} MultiPoint.
+ */
+ol.format.EsriJSON.readMultiPointGeometry_ = function(object) {
+ goog.asserts.assert(object.points, 'object.points should be defined');
+ var layout = ol.format.EsriJSON.getGeometryLayout_(object);
+ return new ol.geom.MultiPoint(object.points, layout);
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Geometry} MultiPolygon.
+ */
+ol.format.EsriJSON.readMultiPolygonGeometry_ = function(object) {
+ goog.asserts.assert(object.rings);
+ goog.asserts.assert(object.rings.length > 1,
+ 'object.rings should have length larger than 1');
+ var layout = ol.format.EsriJSON.getGeometryLayout_(object);
+ return new ol.geom.MultiPolygon(
+ /** @type {Array.<Array.<Array.<Array.<number>>>>} */(object.rings),
+ layout);
+};
+
+
+/**
+ * @param {EsriJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Geometry} Polygon.
+ */
+ol.format.EsriJSON.readPolygonGeometry_ = function(object) {
+ goog.asserts.assert(object.rings);
+ var layout = ol.format.EsriJSON.getGeometryLayout_(object);
+ return new ol.geom.Polygon(object.rings, layout);
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONGeometry} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writePointGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Point,
+ 'geometry should be an ol.geom.Point');
+ var coordinates = geometry.getCoordinates();
+ var layout = geometry.getLayout();
+ if (layout === ol.geom.GeometryLayout.XYZ) {
+ return /** @type {EsriJSONPoint} */ ({
+ x: coordinates[0],
+ y: coordinates[1],
+ z: coordinates[2]
+ });
+ } else if (layout === ol.geom.GeometryLayout.XYM) {
+ return /** @type {EsriJSONPoint} */ ({
+ x: coordinates[0],
+ y: coordinates[1],
+ m: coordinates[2]
+ });
+ } else if (layout === ol.geom.GeometryLayout.XYZM) {
+ return /** @type {EsriJSONPoint} */ ({
+ x: coordinates[0],
+ y: coordinates[1],
+ z: coordinates[2],
+ m: coordinates[3]
+ });
+ } else if (layout === ol.geom.GeometryLayout.XY) {
+ return /** @type {EsriJSONPoint} */ ({
+ x: coordinates[0],
+ y: coordinates[1]
+ });
+ } else {
+ goog.asserts.fail('Unknown geometry layout');
+ }
+};
+
+
+/**
+ * @param {ol.geom.SimpleGeometry} geometry Geometry.
+ * @private
+ * @return {Object} Object with boolean hasZ and hasM keys.
+ */
+ol.format.EsriJSON.getHasZM_ = function(geometry) {
+ var layout = geometry.getLayout();
+ return {
+ hasZ: (layout === ol.geom.GeometryLayout.XYZ ||
+ layout === ol.geom.GeometryLayout.XYZM),
+ hasM: (layout === ol.geom.GeometryLayout.XYM ||
+ layout === ol.geom.GeometryLayout.XYZM)
+ };
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONPolyline} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writeLineStringGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
+ 'geometry should be an ol.geom.LineString');
+ var hasZM = ol.format.EsriJSON.getHasZM_(geometry);
+ return /** @type {EsriJSONPolyline} */ ({
+ hasZ: hasZM.hasZ,
+ hasM: hasZM.hasM,
+ paths: [geometry.getCoordinates()]
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONPolygon} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writePolygonGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
+ 'geometry should be an ol.geom.Polygon');
+ // Esri geometries use the left-hand rule
+ var hasZM = ol.format.EsriJSON.getHasZM_(geometry);
+ return /** @type {EsriJSONPolygon} */ ({
+ hasZ: hasZM.hasZ,
+ hasM: hasZM.hasM,
+ rings: geometry.getCoordinates(false)
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONPolyline} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writeMultiLineStringGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString,
+ 'geometry should be an ol.geom.MultiLineString');
+ var hasZM = ol.format.EsriJSON.getHasZM_(geometry);
+ return /** @type {EsriJSONPolyline} */ ({
+ hasZ: hasZM.hasZ,
+ hasM: hasZM.hasM,
+ paths: geometry.getCoordinates()
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONMultipoint} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint,
+ 'geometry should be an ol.geom.MultiPoint');
+ var hasZM = ol.format.EsriJSON.getHasZM_(geometry);
+ return /** @type {EsriJSONMultipoint} */ ({
+ hasZ: hasZM.hasZ,
+ hasM: hasZM.hasM,
+ points: geometry.getCoordinates()
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONPolygon} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writeMultiPolygonGeometry_ = function(geometry,
+ opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon,
+ 'geometry should be an ol.geom.MultiPolygon');
+ var hasZM = ol.format.EsriJSON.getHasZM_(geometry);
+ var coordinates = geometry.getCoordinates(false);
+ var output = [];
+ for (var i = 0; i < coordinates.length; i++) {
+ for (var x = coordinates[i].length - 1; x >= 0; x--) {
+ output.push(coordinates[i][x]);
+ }
+ }
+ return /** @type {EsriJSONPolygon} */ ({
+ hasZ: hasZM.hasZ,
+ hasM: hasZM.hasM,
+ rings: output
+ });
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<ol.geom.GeometryType, function(EsriJSONGeometry): ol.geom.Geometry>}
+ */
+ol.format.EsriJSON.GEOMETRY_READERS_ = {};
+ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POINT] =
+ ol.format.EsriJSON.readPointGeometry_;
+ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.LINE_STRING] =
+ ol.format.EsriJSON.readLineStringGeometry_;
+ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POLYGON] =
+ ol.format.EsriJSON.readPolygonGeometry_;
+ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POINT] =
+ ol.format.EsriJSON.readMultiPointGeometry_;
+ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_LINE_STRING] =
+ ol.format.EsriJSON.readMultiLineStringGeometry_;
+ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POLYGON] =
+ ol.format.EsriJSON.readMultiPolygonGeometry_;
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (EsriJSONGeometry)>}
+ */
+ol.format.EsriJSON.GEOMETRY_WRITERS_ = {};
+ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POINT] =
+ ol.format.EsriJSON.writePointGeometry_;
+ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.LINE_STRING] =
+ ol.format.EsriJSON.writeLineStringGeometry_;
+ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POLYGON] =
+ ol.format.EsriJSON.writePolygonGeometry_;
+ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POINT] =
+ ol.format.EsriJSON.writeMultiPointGeometry_;
+ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_LINE_STRING] =
+ ol.format.EsriJSON.writeMultiLineStringGeometry_;
+ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POLYGON] =
+ ol.format.EsriJSON.writeMultiPolygonGeometry_;
+
+
+/**
+ * Read a feature from a EsriJSON Feature source. Only works for Feature,
+ * use `readFeatures` to read FeatureCollection source.
+ *
+ * @function
+ * @param {ArrayBuffer|Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api
+ */
+ol.format.EsriJSON.prototype.readFeature;
+
+
+/**
+ * Read all features from a EsriJSON source. Works with both Feature and
+ * FeatureCollection sources.
+ *
+ * @function
+ * @param {ArrayBuffer|Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api
+ */
+ol.format.EsriJSON.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.EsriJSON.prototype.readFeatureFromObject = function(
+ object, opt_options) {
+ var esriJSONFeature = /** @type {EsriJSONFeature} */ (object);
+ goog.asserts.assert(esriJSONFeature.geometry ||
+ esriJSONFeature.attributes,
+ 'geometry or attributes should be defined');
+ var geometry = ol.format.EsriJSON.readGeometry_(esriJSONFeature.geometry,
+ opt_options);
+ var feature = new ol.Feature();
+ if (this.geometryName_) {
+ feature.setGeometryName(this.geometryName_);
+ }
+ feature.setGeometry(geometry);
+ if (opt_options && opt_options.idField &&
+ esriJSONFeature.attributes[opt_options.idField]) {
+ goog.asserts.assert(
+ goog.isNumber(esriJSONFeature.attributes[opt_options.idField]),
+ 'objectIdFieldName value should be a number');
+ feature.setId(/** @type {number} */(
+ esriJSONFeature.attributes[opt_options.idField]));
+ }
+ if (esriJSONFeature.attributes) {
+ feature.setProperties(esriJSONFeature.attributes);
+ }
+ return feature;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.EsriJSON.prototype.readFeaturesFromObject = function(
+ object, opt_options) {
+ var esriJSONObject = /** @type {EsriJSONObject} */ (object);
+ var options = opt_options ? opt_options : {};
+ if (esriJSONObject.features) {
+ var esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */
+ (object);
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ var esriJSONFeatures = esriJSONFeatureCollection.features;
+ var i, ii;
+ options.idField = object.objectIdFieldName;
+ for (i = 0, ii = esriJSONFeatures.length; i < ii; ++i) {
+ features.push(this.readFeatureFromObject(esriJSONFeatures[i],
+ options));
+ }
+ return features;
+ } else {
+ return [this.readFeatureFromObject(object, options)];
+ }
+};
+
+
+/**
+ * Read a geometry from a EsriJSON source.
+ *
+ * @function
+ * @param {ArrayBuffer|Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.geom.Geometry} Geometry.
+ * @api
+ */
+ol.format.EsriJSON.prototype.readGeometry;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.EsriJSON.prototype.readGeometryFromObject = function(
+ object, opt_options) {
+ return ol.format.EsriJSON.readGeometry_(
+ /** @type {EsriJSONGeometry} */ (object), opt_options);
+};
+
+
+/**
+ * Read the projection from a EsriJSON source.
+ *
+ * @function
+ * @param {ArrayBuffer|Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api
+ */
+ol.format.EsriJSON.prototype.readProjection;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.EsriJSON.prototype.readProjectionFromObject = function(object) {
+ var esriJSONObject = /** @type {EsriJSONObject} */ (object);
+ if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) {
+ var crs = esriJSONObject.spatialReference.wkid;
+ return ol.proj.get('EPSG:' + crs);
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {EsriJSONGeometry} EsriJSON geometry.
+ */
+ol.format.EsriJSON.writeGeometry_ = function(geometry, opt_options) {
+ var geometryWriter = ol.format.EsriJSON.GEOMETRY_WRITERS_[geometry.getType()];
+ goog.asserts.assert(geometryWriter, 'geometryWriter should be defined');
+ return geometryWriter(/** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(geometry, true, opt_options)),
+ opt_options);
+};
+
+
+/**
+ * Encode a geometry as a EsriJSON string.
+ *
+ * @function
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} EsriJSON.
+ * @api
+ */
+ol.format.EsriJSON.prototype.writeGeometry;
+
+
+/**
+ * Encode a geometry as a EsriJSON object.
+ *
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {EsriJSONGeometry} Object.
+ * @api
+ */
+ol.format.EsriJSON.prototype.writeGeometryObject = function(geometry,
+ opt_options) {
+ return ol.format.EsriJSON.writeGeometry_(geometry,
+ this.adaptOptions(opt_options));
+};
+
+
+/**
+ * Encode a feature as a EsriJSON Feature string.
+ *
+ * @function
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} EsriJSON.
+ * @api
+ */
+ol.format.EsriJSON.prototype.writeFeature;
+
+
+/**
+ * Encode a feature as a esriJSON Feature object.
+ *
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {Object} Object.
+ * @api
+ */
+ol.format.EsriJSON.prototype.writeFeatureObject = function(
+ feature, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ var object = {};
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ object['geometry'] =
+ ol.format.EsriJSON.writeGeometry_(geometry, opt_options);
+ }
+ var properties = feature.getProperties();
+ delete properties[feature.getGeometryName()];
+ if (!ol.object.isEmpty(properties)) {
+ object['attributes'] = properties;
+ } else {
+ object['attributes'] = {};
+ }
+ if (opt_options && opt_options.featureProjection) {
+ object['spatialReference'] = /** @type {EsriJSONCRS} */({
+ wkid: ol.proj.get(
+ opt_options.featureProjection).getCode().split(':').pop()
+ });
+ }
+ return object;
+};
+
+
+/**
+ * Encode an array of features as EsriJSON.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} EsriJSON.
+ * @api
+ */
+ol.format.EsriJSON.prototype.writeFeatures;
+
+
+/**
+ * Encode an array of features as a EsriJSON object.
+ *
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {Object} EsriJSON Object.
+ * @api
+ */
+ol.format.EsriJSON.prototype.writeFeaturesObject = function(features, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ var objects = [];
+ var i, ii;
+ for (i = 0, ii = features.length; i < ii; ++i) {
+ objects.push(this.writeFeatureObject(features[i], opt_options));
+ }
+ return /** @type {EsriJSONFeatureCollection} */ ({
+ 'features': objects
+ });
+};
+
+goog.provide('ol.geom.GeometryCollection');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.object');
+
+
+/**
+ * @classdesc
+ * An array of {@link ol.geom.Geometry} objects.
+ *
+ * @constructor
+ * @extends {ol.geom.Geometry}
+ * @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries.
+ * @api stable
+ */
+ol.geom.GeometryCollection = function(opt_geometries) {
+
+ ol.geom.Geometry.call(this);
+
+ /**
+ * @private
+ * @type {Array.<ol.geom.Geometry>}
+ */
+ this.geometries_ = opt_geometries ? opt_geometries : null;
+
+ this.listenGeometriesChange_();
+};
+ol.inherits(ol.geom.GeometryCollection, ol.geom.Geometry);
+
+
+/**
+ * @param {Array.<ol.geom.Geometry>} geometries Geometries.
+ * @private
+ * @return {Array.<ol.geom.Geometry>} Cloned geometries.
+ */
+ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) {
+ var clonedGeometries = [];
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ clonedGeometries.push(geometries[i].clone());
+ }
+ return clonedGeometries;
+};
+
+
+/**
+ * @private
+ */
+ol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() {
+ var i, ii;
+ if (!this.geometries_) {
+ return;
+ }
+ for (i = 0, ii = this.geometries_.length; i < ii; ++i) {
+ ol.events.unlisten(
+ this.geometries_[i], ol.events.EventType.CHANGE,
+ this.changed, this);
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() {
+ var i, ii;
+ if (!this.geometries_) {
+ return;
+ }
+ for (i = 0, ii = this.geometries_.length; i < ii; ++i) {
+ ol.events.listen(
+ this.geometries_[i], ol.events.EventType.CHANGE,
+ this.changed, this);
+ }
+};
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.GeometryCollection} Clone.
+ * @api stable
+ */
+ol.geom.GeometryCollection.prototype.clone = function() {
+ var geometryCollection = new ol.geom.GeometryCollection(null);
+ geometryCollection.setGeometries(this.geometries_);
+ return geometryCollection;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.GeometryCollection.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ if (minSquaredDistance <
+ ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
+ return minSquaredDistance;
+ }
+ var geometries = this.geometries_;
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ minSquaredDistance = geometries[i].closestPointXY(
+ x, y, closestPoint, minSquaredDistance);
+ }
+ return minSquaredDistance;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.GeometryCollection.prototype.containsXY = function(x, y) {
+ var geometries = this.geometries_;
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ if (geometries[i].containsXY(x, y)) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.GeometryCollection.prototype.computeExtent = function(extent) {
+ ol.extent.createOrUpdateEmpty(extent);
+ var geometries = this.geometries_;
+ for (var i = 0, ii = geometries.length; i < ii; ++i) {
+ ol.extent.extend(extent, geometries[i].getExtent());
+ }
+ return extent;
+};
+
+
+/**
+ * Return the geometries that make up this geometry collection.
+ * @return {Array.<ol.geom.Geometry>} Geometries.
+ * @api stable
+ */
+ol.geom.GeometryCollection.prototype.getGeometries = function() {
+ return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_);
+};
+
+
+/**
+ * @return {Array.<ol.geom.Geometry>} Geometries.
+ */
+ol.geom.GeometryCollection.prototype.getGeometriesArray = function() {
+ return this.geometries_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.GeometryCollection.prototype.getSimplifiedGeometry = function(squaredTolerance) {
+ if (this.simplifiedGeometryRevision != this.getRevision()) {
+ ol.object.clear(this.simplifiedGeometryCache);
+ this.simplifiedGeometryMaxMinSquaredTolerance = 0;
+ this.simplifiedGeometryRevision = this.getRevision();
+ }
+ if (squaredTolerance < 0 ||
+ (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
+ squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {
+ return this;
+ }
+ var key = squaredTolerance.toString();
+ if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
+ return this.simplifiedGeometryCache[key];
+ } else {
+ var simplifiedGeometries = [];
+ var geometries = this.geometries_;
+ var simplified = false;
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ var geometry = geometries[i];
+ var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
+ simplifiedGeometries.push(simplifiedGeometry);
+ if (simplifiedGeometry !== geometry) {
+ simplified = true;
+ }
+ }
+ if (simplified) {
+ var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null);
+ simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);
+ this.simplifiedGeometryCache[key] = simplifiedGeometryCollection;
+ return simplifiedGeometryCollection;
+ } else {
+ this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
+ return this;
+ }
+ }
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.GeometryCollection.prototype.getType = function() {
+ return ol.geom.GeometryType.GEOMETRY_COLLECTION;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) {
+ var geometries = this.geometries_;
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ if (geometries[i].intersectsExtent(extent)) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * @return {boolean} Is empty.
+ */
+ol.geom.GeometryCollection.prototype.isEmpty = function() {
+ return this.geometries_.length === 0;
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.geom.GeometryCollection.prototype.rotate = function(angle, anchor) {
+ var geometries = this.geometries_;
+ for (var i = 0, ii = geometries.length; i < ii; ++i) {
+ geometries[i].rotate(angle, anchor);
+ }
+ this.changed();
+};
+
+
+/**
+ * Set the geometries that make up this geometry collection.
+ * @param {Array.<ol.geom.Geometry>} geometries Geometries.
+ * @api stable
+ */
+ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) {
+ this.setGeometriesArray(
+ ol.geom.GeometryCollection.cloneGeometries_(geometries));
+};
+
+
+/**
+ * @param {Array.<ol.geom.Geometry>} geometries Geometries.
+ */
+ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) {
+ this.unlistenGeometriesChange_();
+ this.geometries_ = geometries;
+ this.listenGeometriesChange_();
+ this.changed();
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) {
+ var geometries = this.geometries_;
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ geometries[i].applyTransform(transformFn);
+ }
+ this.changed();
+};
+
+
+/**
+ * Translate the geometry.
+ * @param {number} deltaX Delta X.
+ * @param {number} deltaY Delta Y.
+ * @api
+ */
+ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) {
+ var geometries = this.geometries_;
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ geometries[i].translate(deltaX, deltaY);
+ }
+ this.changed();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.GeometryCollection.prototype.disposeInternal = function() {
+ this.unlistenGeometriesChange_();
+ ol.geom.Geometry.prototype.disposeInternal.call(this);
+};
+
+// TODO: serialize dataProjection as crs member when writing
+// see https://github.com/openlayers/ol3/issues/2078
+
+goog.provide('ol.format.GeoJSON');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.JSONFeature');
+goog.require('ol.geom.GeometryCollection');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.object');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the GeoJSON format.
+ *
+ * @constructor
+ * @extends {ol.format.JSONFeature}
+ * @param {olx.format.GeoJSONOptions=} opt_options Options.
+ * @api stable
+ */
+ol.format.GeoJSON = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.JSONFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get(
+ options.defaultDataProjection ?
+ options.defaultDataProjection : 'EPSG:4326');
+
+
+ /**
+ * Name of the geometry attribute for features.
+ * @type {string|undefined}
+ * @private
+ */
+ this.geometryName_ = options.geometryName;
+
+};
+ol.inherits(ol.format.GeoJSON, ol.format.JSONFeature);
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.GeoJSON.EXTENSIONS_ = ['.geojson'];
+
+
+/**
+ * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @private
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.GeoJSON.readGeometry_ = function(object, opt_options) {
+ if (!object) {
+ return null;
+ }
+ var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type];
+ goog.asserts.assert(geometryReader, 'geometryReader should be defined');
+ return /** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(
+ geometryReader(object), false, opt_options));
+};
+
+
+/**
+ * @param {GeoJSONGeometryCollection} object Object.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @private
+ * @return {ol.geom.GeometryCollection} Geometry collection.
+ */
+ol.format.GeoJSON.readGeometryCollectionGeometry_ = function(
+ object, opt_options) {
+ goog.asserts.assert(object.type == 'GeometryCollection',
+ 'object.type should be GeometryCollection');
+ var geometries = object.geometries.map(
+ /**
+ * @param {GeoJSONGeometry} geometry Geometry.
+ * @return {ol.geom.Geometry} geometry Geometry.
+ */
+ function(geometry) {
+ return ol.format.GeoJSON.readGeometry_(geometry, opt_options);
+ });
+ return new ol.geom.GeometryCollection(geometries);
+};
+
+
+/**
+ * @param {GeoJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Point} Point.
+ */
+ol.format.GeoJSON.readPointGeometry_ = function(object) {
+ goog.asserts.assert(object.type == 'Point',
+ 'object.type should be Point');
+ return new ol.geom.Point(object.coordinates);
+};
+
+
+/**
+ * @param {GeoJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.LineString} LineString.
+ */
+ol.format.GeoJSON.readLineStringGeometry_ = function(object) {
+ goog.asserts.assert(object.type == 'LineString',
+ 'object.type should be LineString');
+ return new ol.geom.LineString(object.coordinates);
+};
+
+
+/**
+ * @param {GeoJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.MultiLineString} MultiLineString.
+ */
+ol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) {
+ goog.asserts.assert(object.type == 'MultiLineString',
+ 'object.type should be MultiLineString');
+ return new ol.geom.MultiLineString(object.coordinates);
+};
+
+
+/**
+ * @param {GeoJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.MultiPoint} MultiPoint.
+ */
+ol.format.GeoJSON.readMultiPointGeometry_ = function(object) {
+ goog.asserts.assert(object.type == 'MultiPoint',
+ 'object.type should be MultiPoint');
+ return new ol.geom.MultiPoint(object.coordinates);
+};
+
+
+/**
+ * @param {GeoJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.MultiPolygon} MultiPolygon.
+ */
+ol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) {
+ goog.asserts.assert(object.type == 'MultiPolygon',
+ 'object.type should be MultiPolygon');
+ return new ol.geom.MultiPolygon(object.coordinates);
+};
+
+
+/**
+ * @param {GeoJSONGeometry} object Object.
+ * @private
+ * @return {ol.geom.Polygon} Polygon.
+ */
+ol.format.GeoJSON.readPolygonGeometry_ = function(object) {
+ goog.asserts.assert(object.type == 'Polygon',
+ 'object.type should be Polygon');
+ return new ol.geom.Polygon(object.coordinates);
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {
+ var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];
+ goog.asserts.assert(geometryWriter, 'geometryWriter should be defined');
+ return geometryWriter(/** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(geometry, true, opt_options)),
+ opt_options);
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @private
+ * @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection.
+ */
+ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) {
+ return /** @type {GeoJSONGeometryCollection} */ ({
+ type: 'GeometryCollection',
+ geometries: []
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometryCollection} GeoJSON geometry collection.
+ */
+ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(
+ geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection,
+ 'geometry should be an ol.geom.GeometryCollection');
+ var geometries = geometry.getGeometriesArray().map(function(geometry) {
+ var options = ol.object.assign({}, opt_options);
+ delete options.featureProjection;
+ return ol.format.GeoJSON.writeGeometry_(geometry, options);
+ });
+ return /** @type {GeoJSONGeometryCollection} */ ({
+ type: 'GeometryCollection',
+ geometries: geometries
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
+ 'geometry should be an ol.geom.LineString');
+ return /** @type {GeoJSONGeometry} */ ({
+ type: 'LineString',
+ coordinates: geometry.getCoordinates()
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writeMultiLineStringGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString,
+ 'geometry should be an ol.geom.MultiLineString');
+ return /** @type {GeoJSONGeometry} */ ({
+ type: 'MultiLineString',
+ coordinates: geometry.getCoordinates()
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint,
+ 'geometry should be an ol.geom.MultiPoint');
+ return /** @type {GeoJSONGeometry} */ ({
+ type: 'MultiPoint',
+ coordinates: geometry.getCoordinates()
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon,
+ 'geometry should be an ol.geom.MultiPolygon');
+ var right;
+ if (opt_options) {
+ right = opt_options.rightHanded;
+ }
+ return /** @type {GeoJSONGeometry} */ ({
+ type: 'MultiPolygon',
+ coordinates: geometry.getCoordinates(right)
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Point,
+ 'geometry should be an ol.geom.Point');
+ return /** @type {GeoJSONGeometry} */ ({
+ type: 'Point',
+ coordinates: geometry.getCoordinates()
+ });
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @private
+ * @return {GeoJSONGeometry} GeoJSON geometry.
+ */
+ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
+ 'geometry should be an ol.geom.Polygon');
+ var right;
+ if (opt_options) {
+ right = opt_options.rightHanded;
+ }
+ return /** @type {GeoJSONGeometry} */ ({
+ type: 'Polygon',
+ coordinates: geometry.getCoordinates(right)
+ });
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>}
+ */
+ol.format.GeoJSON.GEOMETRY_READERS_ = {
+ 'Point': ol.format.GeoJSON.readPointGeometry_,
+ 'LineString': ol.format.GeoJSON.readLineStringGeometry_,
+ 'Polygon': ol.format.GeoJSON.readPolygonGeometry_,
+ 'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_,
+ 'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_,
+ 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_,
+ 'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>}
+ */
+ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
+ 'Point': ol.format.GeoJSON.writePointGeometry_,
+ 'LineString': ol.format.GeoJSON.writeLineStringGeometry_,
+ 'Polygon': ol.format.GeoJSON.writePolygonGeometry_,
+ 'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_,
+ 'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_,
+ 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_,
+ 'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_,
+ 'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GeoJSON.prototype.getExtensions = function() {
+ return ol.format.GeoJSON.EXTENSIONS_;
+};
+
+
+/**
+ * Read a feature from a GeoJSON Feature source. Only works for Feature,
+ * use `readFeatures` to read FeatureCollection source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.readFeature;
+
+
+/**
+ * Read all features from a GeoJSON source. Works with both Feature and
+ * FeatureCollection sources.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GeoJSON.prototype.readFeatureFromObject = function(
+ object, opt_options) {
+ var geoJSONFeature = /** @type {GeoJSONFeature} */ (object);
+ goog.asserts.assert(geoJSONFeature.type == 'Feature',
+ 'geoJSONFeature.type should be Feature');
+ var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry,
+ opt_options);
+ var feature = new ol.Feature();
+ if (this.geometryName_) {
+ feature.setGeometryName(this.geometryName_);
+ }
+ feature.setGeometry(geometry);
+ if (geoJSONFeature.id !== undefined) {
+ feature.setId(geoJSONFeature.id);
+ }
+ if (geoJSONFeature.properties) {
+ feature.setProperties(geoJSONFeature.properties);
+ }
+ return feature;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GeoJSON.prototype.readFeaturesFromObject = function(
+ object, opt_options) {
+ var geoJSONObject = /** @type {GeoJSONObject} */ (object);
+ if (geoJSONObject.type == 'Feature') {
+ return [this.readFeatureFromObject(object, opt_options)];
+ } else if (geoJSONObject.type == 'FeatureCollection') {
+ var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */
+ (object);
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ var geoJSONFeatures = geoJSONFeatureCollection.features;
+ var i, ii;
+ for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {
+ features.push(this.readFeatureFromObject(geoJSONFeatures[i],
+ opt_options));
+ }
+ return features;
+ } else {
+ goog.asserts.fail('Unknown geoJSONObject.type: ' + geoJSONObject.type);
+ return [];
+ }
+};
+
+
+/**
+ * Read a geometry from a GeoJSON source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.geom.Geometry} Geometry.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.readGeometry;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GeoJSON.prototype.readGeometryFromObject = function(
+ object, opt_options) {
+ return ol.format.GeoJSON.readGeometry_(
+ /** @type {GeoJSONGeometry} */ (object), opt_options);
+};
+
+
+/**
+ * Read the projection from a GeoJSON source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.readProjection;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) {
+ var geoJSONObject = /** @type {GeoJSONObject} */ (object);
+ var crs = geoJSONObject.crs;
+ if (crs) {
+ if (crs.type == 'name') {
+ return ol.proj.get(crs.properties.name);
+ } else if (crs.type == 'EPSG') {
+ // 'EPSG' is not part of the GeoJSON specification, but is generated by
+ // GeoServer.
+ // TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996
+ // is fixed and widely deployed.
+ return ol.proj.get('EPSG:' + crs.properties.code);
+ } else {
+ goog.asserts.fail('Unknown crs.type: ' + crs.type);
+ return null;
+ }
+ } else {
+ return this.defaultDataProjection;
+ }
+};
+
+
+/**
+ * Encode a feature as a GeoJSON Feature string.
+ *
+ * @function
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} GeoJSON.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.writeFeature;
+
+
+/**
+ * Encode a feature as a GeoJSON Feature object.
+ *
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {GeoJSONFeature} Object.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.writeFeatureObject = function(feature, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+
+ var object = /** @type {GeoJSONFeature} */ ({
+ 'type': 'Feature'
+ });
+ var id = feature.getId();
+ if (id !== undefined) {
+ object.id = id;
+ }
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ object.geometry =
+ ol.format.GeoJSON.writeGeometry_(geometry, opt_options);
+ } else {
+ object.geometry = null;
+ }
+ var properties = feature.getProperties();
+ delete properties[feature.getGeometryName()];
+ if (!ol.object.isEmpty(properties)) {
+ object.properties = properties;
+ } else {
+ object.properties = null;
+ }
+ return object;
+};
+
+
+/**
+ * Encode an array of features as GeoJSON.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} GeoJSON.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.writeFeatures;
+
+
+/**
+ * Encode an array of features as a GeoJSON object.
+ *
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {GeoJSONFeatureCollection} GeoJSON Object.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.writeFeaturesObject = function(features, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ var objects = [];
+ var i, ii;
+ for (i = 0, ii = features.length; i < ii; ++i) {
+ objects.push(this.writeFeatureObject(features[i], opt_options));
+ }
+ return /** @type {GeoJSONFeatureCollection} */ ({
+ type: 'FeatureCollection',
+ features: objects
+ });
+};
+
+
+/**
+ * Encode a geometry as a GeoJSON string.
+ *
+ * @function
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} GeoJSON.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.writeGeometry;
+
+
+/**
+ * Encode a geometry as a GeoJSON object.
+ *
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object.
+ * @api stable
+ */
+ol.format.GeoJSON.prototype.writeGeometryObject = function(geometry,
+ opt_options) {
+ return ol.format.GeoJSON.writeGeometry_(geometry,
+ this.adaptOptions(opt_options));
+};
+
+goog.provide('ol.format.XMLFeature');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.format.Feature');
+goog.require('ol.format.FormatType');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for XML feature formats.
+ *
+ * @constructor
+ * @extends {ol.format.Feature}
+ */
+ol.format.XMLFeature = function() {
+
+ /**
+ * @type {XMLSerializer}
+ * @private
+ */
+ this.xmlSerializer_ = new XMLSerializer();
+
+ ol.format.Feature.call(this);
+};
+ol.inherits(ol.format.XMLFeature, ol.format.Feature);
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.getType = function() {
+ return ol.format.FormatType.XML;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.readFeature = function(source, opt_options) {
+ if (ol.xml.isDocument(source)) {
+ return this.readFeatureFromDocument(
+ /** @type {Document} */ (source), opt_options);
+ } else if (ol.xml.isNode(source)) {
+ return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options);
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readFeatureFromDocument(doc, opt_options);
+ } else {
+ goog.asserts.fail('Unknown source type');
+ return null;
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @return {ol.Feature} Feature.
+ */
+ol.format.XMLFeature.prototype.readFeatureFromDocument = function(
+ doc, opt_options) {
+ var features = this.readFeaturesFromDocument(doc, opt_options);
+ if (features.length > 0) {
+ return features[0];
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @return {ol.Feature} Feature.
+ */
+ol.format.XMLFeature.prototype.readFeatureFromNode = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) {
+ if (ol.xml.isDocument(source)) {
+ return this.readFeaturesFromDocument(
+ /** @type {Document} */ (source), opt_options);
+ } else if (ol.xml.isNode(source)) {
+ return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options);
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readFeaturesFromDocument(doc, opt_options);
+ } else {
+ goog.asserts.fail('Unknown source type');
+ return [];
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @protected
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.format.XMLFeature.prototype.readFeaturesFromDocument = function(
+ doc, opt_options) {
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ var n;
+ for (n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ ol.array.extend(features, this.readFeaturesFromNode(n, opt_options));
+ }
+ }
+ return features;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @protected
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.format.XMLFeature.prototype.readFeaturesFromNode = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) {
+ if (ol.xml.isDocument(source)) {
+ return this.readGeometryFromDocument(
+ /** @type {Document} */ (source), opt_options);
+ } else if (ol.xml.isNode(source)) {
+ return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options);
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readGeometryFromDocument(doc, opt_options);
+ } else {
+ goog.asserts.fail('Unknown source type');
+ return null;
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @protected
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.XMLFeature.prototype.readGeometryFromDocument = goog.abstractMethod;
+
+
+/**
+ * @param {Node} node Node.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @protected
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.XMLFeature.prototype.readGeometryFromNode = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.readProjection = function(source) {
+ if (ol.xml.isDocument(source)) {
+ return this.readProjectionFromDocument(/** @type {Document} */ (source));
+ } else if (ol.xml.isNode(source)) {
+ return this.readProjectionFromNode(/** @type {Node} */ (source));
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readProjectionFromDocument(doc);
+ } else {
+ goog.asserts.fail('Unknown source type');
+ return null;
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @protected
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) {
+ return this.defaultDataProjection;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @protected
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.format.XMLFeature.prototype.readProjectionFromNode = function(node) {
+ return this.defaultDataProjection;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) {
+ var node = this.writeFeatureNode(feature, opt_options);
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return this.xmlSerializer_.serializeToString(node);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @protected
+ * @return {Node} Node.
+ */
+ol.format.XMLFeature.prototype.writeFeatureNode = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) {
+ var node = this.writeFeaturesNode(features, opt_options);
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return this.xmlSerializer_.serializeToString(node);
+};
+
+
+/**
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ */
+ol.format.XMLFeature.prototype.writeFeaturesNode = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) {
+ var node = this.writeGeometryNode(geometry, opt_options);
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return this.xmlSerializer_.serializeToString(node);
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ */
+ol.format.XMLFeature.prototype.writeGeometryNode = goog.abstractMethod;
+
+// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part
+// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect
+// envelopes/extents, only geometries!
+goog.provide('ol.format.GMLBase');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.XMLFeature');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.LinearRing');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Feature base format for reading and writing data in the GML format.
+ * This class cannot be instantiated, it contains only base content that
+ * is shared with versioned format classes ol.format.GML2 and
+ * ol.format.GML3.
+ *
+ * @constructor
+ * @param {olx.format.GMLOptions=} opt_options
+ * Optional configuration object.
+ * @extends {ol.format.XMLFeature}
+ */
+ol.format.GMLBase = function(opt_options) {
+ var options = /** @type {olx.format.GMLOptions} */
+ (opt_options ? opt_options : {});
+
+ /**
+ * @protected
+ * @type {Array.<string>|string|undefined}
+ */
+ this.featureType = options.featureType;
+
+ /**
+ * @protected
+ * @type {Object.<string, string>|string|undefined}
+ */
+ this.featureNS = options.featureNS;
+
+ /**
+ * @protected
+ * @type {string}
+ */
+ this.srsName = options.srsName;
+
+ /**
+ * @protected
+ * @type {string}
+ */
+ this.schemaLocation = '';
+
+ /**
+ * @type {Object.<string, Object.<string, Object>>}
+ */
+ this.FEATURE_COLLECTION_PARSERS = {};
+ this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = {
+ 'featureMember': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readFeaturesInternal),
+ 'featureMembers': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readFeaturesInternal)
+ };
+
+ ol.format.XMLFeature.call(this);
+};
+ol.inherits(ol.format.GMLBase, ol.format.XMLFeature);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml';
+
+
+/**
+ * A regular expression that matches if a string only contains whitespace
+ * characters. It will e.g. match `''`, `' '`, `'\n'` etc. The non-breaking
+ * space (0xa0) is explicitly included as IE doesn't include it in its
+ * definition of `\s`.
+ *
+ * Information from `goog.string.isEmptyOrWhitespace`: https://github.com/google/closure-library/blob/e877b1e/closure/goog/string/string.js#L156-L160
+ *
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.format.GMLBase.ONLY_WHITESPACE_RE_ = /^[\s\xa0]*$/;
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Array.<ol.Feature> | undefined} Features.
+ */
+ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ var localName = node.localName;
+ var features = null;
+ if (localName == 'FeatureCollection') {
+ if (node.namespaceURI === 'http://www.opengis.net/wfs') {
+ features = ol.xml.pushParseAndPop([],
+ this.FEATURE_COLLECTION_PARSERS, node,
+ objectStack, this);
+ } else {
+ features = ol.xml.pushParseAndPop(null,
+ this.FEATURE_COLLECTION_PARSERS, node,
+ objectStack, this);
+ }
+ } else if (localName == 'featureMembers' || localName == 'featureMember') {
+ var context = objectStack[0];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var featureType = context['featureType'];
+ var featureNS = context['featureNS'];
+ var i, ii, prefix = 'p', defaultPrefix = 'p0';
+ if (!featureType && node.childNodes) {
+ featureType = [], featureNS = {};
+ for (i = 0, ii = node.childNodes.length; i < ii; ++i) {
+ var child = node.childNodes[i];
+ if (child.nodeType === 1) {
+ var ft = child.nodeName.split(':').pop();
+ if (featureType.indexOf(ft) === -1) {
+ var key = '';
+ var count = 0;
+ var uri = child.namespaceURI;
+ for (var candidate in featureNS) {
+ if (featureNS[candidate] === uri) {
+ key = candidate;
+ break;
+ }
+ ++count;
+ }
+ if (!key) {
+ key = prefix + count;
+ featureNS[key] = uri;
+ }
+ featureType.push(key + ':' + ft);
+ }
+ }
+ }
+ if (localName != 'featureMember') {
+ // recheck featureType for each featureMember
+ context['featureType'] = featureType;
+ context['featureNS'] = featureNS;
+ }
+ }
+ if (typeof featureNS === 'string') {
+ var ns = featureNS;
+ featureNS = {};
+ featureNS[defaultPrefix] = ns;
+ }
+ var parsersNS = {};
+ var featureTypes = Array.isArray(featureType) ? featureType : [featureType];
+ for (var p in featureNS) {
+ var parsers = {};
+ for (i = 0, ii = featureTypes.length; i < ii; ++i) {
+ var featurePrefix = featureTypes[i].indexOf(':') === -1 ?
+ defaultPrefix : featureTypes[i].split(':')[0];
+ if (featurePrefix === p) {
+ parsers[featureTypes[i].split(':').pop()] =
+ (localName == 'featureMembers') ?
+ ol.xml.makeArrayPusher(this.readFeatureElement, this) :
+ ol.xml.makeReplacer(this.readFeatureElement, this);
+ }
+ }
+ parsersNS[featureNS[p]] = parsers;
+ }
+ if (localName == 'featureMember') {
+ features = ol.xml.pushParseAndPop(undefined, parsersNS, node, objectStack);
+ } else {
+ features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack);
+ }
+ }
+ if (features === null) {
+ features = [];
+ }
+ return features;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.Geometry|undefined} Geometry.
+ */
+ol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) {
+ var context = objectStack[0];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ context['srsName'] = node.firstElementChild.getAttribute('srsName');
+ /** @type {ol.geom.Geometry} */
+ var geometry = ol.xml.pushParseAndPop(null,
+ this.GEOMETRY_PARSERS_, node, objectStack, this);
+ if (geometry) {
+ return /** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(geometry, false, context));
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.Feature} Feature.
+ */
+ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) {
+ var n;
+ var fid = node.getAttribute('fid') ||
+ ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id');
+ var values = {}, geometryName;
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ var localName = n.localName;
+ // Assume attribute elements have one child node and that the child
+ // is a text or CDATA node (to be treated as text).
+ // Otherwise assume it is a geometry node.
+ if (n.childNodes.length === 0 ||
+ (n.childNodes.length === 1 &&
+ (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
+ var value = ol.xml.getAllTextContent(n, false);
+ if (ol.format.GMLBase.ONLY_WHITESPACE_RE_.test(value)) {
+ value = undefined;
+ }
+ values[localName] = value;
+ } else {
+ // boundedBy is an extent and must not be considered as a geometry
+ if (localName !== 'boundedBy') {
+ geometryName = localName;
+ }
+ values[localName] = this.readGeometryElement(n, objectStack);
+ }
+ }
+ var feature = new ol.Feature(values);
+ if (geometryName) {
+ feature.setGeometryName(geometryName);
+ }
+ if (fid) {
+ feature.setId(fid);
+ }
+ return feature;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.Point|undefined} Point.
+ */
+ol.format.GMLBase.prototype.readPoint = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Point', 'localName should be Point');
+ var flatCoordinates =
+ this.readFlatCoordinatesFromNode_(node, objectStack);
+ if (flatCoordinates) {
+ var point = new ol.geom.Point(null);
+ goog.asserts.assert(flatCoordinates.length == 3,
+ 'flatCoordinates should have a length of 3');
+ point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
+ return point;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.MultiPoint|undefined} MultiPoint.
+ */
+ol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MultiPoint',
+ 'localName should be MultiPoint');
+ /** @type {Array.<Array.<number>>} */
+ var coordinates = ol.xml.pushParseAndPop([],
+ this.MULTIPOINT_PARSERS_, node, objectStack, this);
+ if (coordinates) {
+ return new ol.geom.MultiPoint(coordinates);
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.MultiLineString|undefined} MultiLineString.
+ */
+ol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MultiLineString',
+ 'localName should be MultiLineString');
+ /** @type {Array.<ol.geom.LineString>} */
+ var lineStrings = ol.xml.pushParseAndPop([],
+ this.MULTILINESTRING_PARSERS_, node, objectStack, this);
+ if (lineStrings) {
+ var multiLineString = new ol.geom.MultiLineString(null);
+ multiLineString.setLineStrings(lineStrings);
+ return multiLineString;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.MultiPolygon|undefined} MultiPolygon.
+ */
+ol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MultiPolygon',
+ 'localName should be MultiPolygon');
+ /** @type {Array.<ol.geom.Polygon>} */
+ var polygons = ol.xml.pushParseAndPop([],
+ this.MULTIPOLYGON_PARSERS_, node, objectStack, this);
+ if (polygons) {
+ var multiPolygon = new ol.geom.MultiPolygon(null);
+ multiPolygon.setPolygons(polygons);
+ return multiPolygon;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'pointMember' ||
+ node.localName == 'pointMembers',
+ 'localName should be pointMember or pointMembers');
+ ol.xml.parseNode(this.POINTMEMBER_PARSERS_,
+ node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GMLBase.prototype.lineStringMemberParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'lineStringMember' ||
+ node.localName == 'lineStringMembers',
+ 'localName should be LineStringMember or LineStringMembers');
+ ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_,
+ node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GMLBase.prototype.polygonMemberParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'polygonMember' ||
+ node.localName == 'polygonMembers',
+ 'localName should be polygonMember or polygonMembers');
+ ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node,
+ objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.LineString|undefined} LineString.
+ */
+ol.format.GMLBase.prototype.readLineString = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LineString',
+ 'localName should be LineString');
+ var flatCoordinates =
+ this.readFlatCoordinatesFromNode_(node, objectStack);
+ if (flatCoordinates) {
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
+ return lineString;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>|undefined} LinearRing flat coordinates.
+ */
+ol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LinearRing',
+ 'localName should be LinearRing');
+ var ring = ol.xml.pushParseAndPop(null,
+ this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
+ objectStack, this);
+ if (ring) {
+ return ring;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.LinearRing|undefined} LinearRing.
+ */
+ol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LinearRing',
+ 'localName should be LinearRing');
+ var flatCoordinates =
+ this.readFlatCoordinatesFromNode_(node, objectStack);
+ if (flatCoordinates) {
+ var ring = new ol.geom.LinearRing(null);
+ ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
+ return ring;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.geom.Polygon|undefined} Polygon.
+ */
+ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Polygon',
+ 'localName should be Polygon');
+ /** @type {Array.<Array.<number>>} */
+ var flatLinearRings = ol.xml.pushParseAndPop([null],
+ this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
+ if (flatLinearRings && flatLinearRings[0]) {
+ var polygon = new ol.geom.Polygon(null);
+ var flatCoordinates = flatLinearRings[0];
+ var ends = [flatCoordinates.length];
+ var i, ii;
+ for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
+ ol.array.extend(flatCoordinates, flatLinearRings[i]);
+ ends.push(flatCoordinates.length);
+ }
+ polygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
+ return polygon;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return ol.xml.pushParseAndPop(null,
+ this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
+ objectStack, this);
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'pointMember': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.pointMemberParser_),
+ 'pointMembers': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.pointMemberParser_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'lineStringMember': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.lineStringMemberParser_),
+ 'lineStringMembers': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.lineStringMemberParser_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'polygonMember': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.polygonMemberParser_),
+ 'polygonMembers': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.polygonMemberParser_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'Point': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'LineString': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.readLineString)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'Polygon': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.readPolygon)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @protected
+ */
+ol.format.GMLBase.prototype.RING_PARSERS = {
+ 'http://www.opengis.net/gml' : {
+ 'LinearRing': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readFlatLinearRing_)
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GMLBase.prototype.readGeometryFromNode = function(node, opt_options) {
+ var geometry = this.readGeometryElement(node,
+ [this.getReadOptions(node, opt_options ? opt_options : {})]);
+ return geometry ? geometry : null;
+};
+
+
+/**
+ * Read all features from a GML FeatureCollection.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.GMLBase.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GMLBase.prototype.readFeaturesFromNode = function(node, opt_options) {
+ var options = {
+ featureType: this.featureType,
+ featureNS: this.featureNS
+ };
+ if (opt_options) {
+ ol.object.assign(options, this.getReadOptions(node, opt_options));
+ }
+ var features = this.readFeaturesInternal(node, [options]);
+ return features || [];
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GMLBase.prototype.readProjectionFromNode = function(node) {
+ return ol.proj.get(this.srsName ? this.srsName :
+ node.firstElementChild.getAttribute('srsName'));
+};
+
+goog.provide('ol.format.XSD');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.xml');
+goog.require('ol.string');
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema';
+
+
+/**
+ * @param {Node} node Node.
+ * @return {boolean|undefined} Boolean.
+ */
+ol.format.XSD.readBoolean = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ return ol.format.XSD.readBooleanString(s);
+};
+
+
+/**
+ * @param {string} string String.
+ * @return {boolean|undefined} Boolean.
+ */
+ol.format.XSD.readBooleanString = function(string) {
+ var m = /^\s*(true|1)|(false|0)\s*$/.exec(string);
+ if (m) {
+ return m[1] !== undefined || false;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {number|undefined} DateTime in seconds.
+ */
+ol.format.XSD.readDateTime = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ var re =
+ /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/;
+ var m = re.exec(s);
+ if (m) {
+ var year = parseInt(m[1], 10);
+ var month = parseInt(m[2], 10) - 1;
+ var day = parseInt(m[3], 10);
+ var hour = parseInt(m[4], 10);
+ var minute = parseInt(m[5], 10);
+ var second = parseInt(m[6], 10);
+ var dateTime = Date.UTC(year, month, day, hour, minute, second) / 1000;
+ if (m[7] != 'Z') {
+ var sign = m[8] == '-' ? -1 : 1;
+ dateTime += sign * 60 * parseInt(m[9], 10);
+ if (m[10] !== undefined) {
+ dateTime += sign * 60 * 60 * parseInt(m[10], 10);
+ }
+ }
+ return dateTime;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {number|undefined} Decimal.
+ */
+ol.format.XSD.readDecimal = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ return ol.format.XSD.readDecimalString(s);
+};
+
+
+/**
+ * @param {string} string String.
+ * @return {number|undefined} Decimal.
+ */
+ol.format.XSD.readDecimalString = function(string) {
+ // FIXME check spec
+ var m = /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(string);
+ if (m) {
+ return parseFloat(m[1]);
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {number|undefined} Non negative integer.
+ */
+ol.format.XSD.readNonNegativeInteger = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ return ol.format.XSD.readNonNegativeIntegerString(s);
+};
+
+
+/**
+ * @param {string} string String.
+ * @return {number|undefined} Non negative integer.
+ */
+ol.format.XSD.readNonNegativeIntegerString = function(string) {
+ var m = /^\s*(\d+)\s*$/.exec(string);
+ if (m) {
+ return parseInt(m[1], 10);
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {string|undefined} String.
+ */
+ol.format.XSD.readString = function(node) {
+ return ol.xml.getAllTextContent(node, false).trim();
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the boolean to.
+ * @param {boolean} bool Boolean.
+ */
+ol.format.XSD.writeBooleanTextNode = function(node, bool) {
+ ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0');
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the dateTime to.
+ * @param {number} dateTime DateTime in seconds.
+ */
+ol.format.XSD.writeDateTimeTextNode = function(node, dateTime) {
+ var date = new Date(dateTime * 1000);
+ var string = date.getUTCFullYear() + '-' +
+ ol.string.padNumber(date.getUTCMonth() + 1, 2) + '-' +
+ ol.string.padNumber(date.getUTCDate(), 2) + 'T' +
+ ol.string.padNumber(date.getUTCHours(), 2) + ':' +
+ ol.string.padNumber(date.getUTCMinutes(), 2) + ':' +
+ ol.string.padNumber(date.getUTCSeconds(), 2) + 'Z';
+ node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the decimal to.
+ * @param {number} decimal Decimal.
+ */
+ol.format.XSD.writeDecimalTextNode = function(node, decimal) {
+ var string = decimal.toPrecision();
+ node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the decimal to.
+ * @param {number} nonNegativeInteger Non negative integer.
+ */
+ol.format.XSD.writeNonNegativeIntegerTextNode = function(node, nonNegativeInteger) {
+ goog.asserts.assert(nonNegativeInteger >= 0, 'value should be more than 0');
+ goog.asserts.assert(nonNegativeInteger == (nonNegativeInteger | 0),
+ 'value should be an integer value');
+ var string = nonNegativeInteger.toString();
+ node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the string to.
+ * @param {string} string String.
+ */
+ol.format.XSD.writeStringTextNode = function(node, string) {
+ node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
+};
+
+goog.provide('ol.format.GML2');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.format.GMLBase');
+goog.require('ol.format.XSD');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the GML format,
+ * version 2.1.2.
+ *
+ * @constructor
+ * @param {olx.format.GMLOptions=} opt_options Optional configuration object.
+ * @extends {ol.format.GMLBase}
+ * @api
+ */
+ol.format.GML2 = function(opt_options) {
+ var options = /** @type {olx.format.GMLOptions} */
+ (opt_options ? opt_options : {});
+
+ ol.format.GMLBase.call(this, options);
+
+ this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][
+ 'featureMember'] =
+ ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);
+
+ /**
+ * @inheritDoc
+ */
+ this.schemaLocation = options.schemaLocation ?
+ options.schemaLocation : ol.format.GML2.schemaLocation_;
+
+};
+ol.inherits(ol.format.GML2, ol.format.GMLBase);
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS +
+ ' http://schemas.opengis.net/gml/2.1.2/feature.xsd';
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>|undefined} Flat coordinates.
+ */
+ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
+ var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
+ var context = /** @type {ol.XmlNodeStackItem} */ (objectStack[0]);
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var containerSrs = context['srsName'];
+ var containerDimension = node.parentNode.getAttribute('srsDimension');
+ var axisOrientation = 'enu';
+ if (containerSrs) {
+ var proj = ol.proj.get(containerSrs);
+ if (proj) {
+ axisOrientation = proj.getAxisOrientation();
+ }
+ }
+ var coords = s.split(/[\s,]+/);
+ // The "dimension" attribute is from the GML 3.0.1 spec.
+ var dim = 2;
+ if (node.getAttribute('srsDimension')) {
+ dim = ol.format.XSD.readNonNegativeIntegerString(
+ node.getAttribute('srsDimension'));
+ } else if (node.getAttribute('dimension')) {
+ dim = ol.format.XSD.readNonNegativeIntegerString(
+ node.getAttribute('dimension'));
+ } else if (containerDimension) {
+ dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension);
+ }
+ var x, y, z;
+ var flatCoordinates = [];
+ for (var i = 0, ii = coords.length; i < ii; i += dim) {
+ x = parseFloat(coords[i]);
+ y = parseFloat(coords[i + 1]);
+ z = (dim === 3) ? parseFloat(coords[i + 2]) : 0;
+ if (axisOrientation.substr(0, 2) === 'en') {
+ flatCoordinates.push(x, y, z);
+ } else {
+ flatCoordinates.push(y, x, z);
+ }
+ }
+ return flatCoordinates;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.Extent|undefined} Envelope.
+ */
+ol.format.GML2.prototype.readBox_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Box', 'localName should be Box');
+ /** @type {Array.<number>} */
+ var flatCoordinates = ol.xml.pushParseAndPop([null],
+ this.BOX_PARSERS_, node, objectStack, this);
+ return ol.extent.createOrUpdate(flatCoordinates[1][0],
+ flatCoordinates[1][1], flatCoordinates[1][3],
+ flatCoordinates[1][4]);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GML2.prototype.innerBoundaryIsParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'innerBoundaryIs',
+ 'localName should be innerBoundaryIs');
+ /** @type {Array.<number>|undefined} */
+ var flatLinearRing = ol.xml.pushParseAndPop(undefined,
+ this.RING_PARSERS, node, objectStack, this);
+ if (flatLinearRing) {
+ var flatLinearRings = /** @type {Array.<Array.<number>>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(flatLinearRings),
+ 'flatLinearRings should be an array');
+ goog.asserts.assert(flatLinearRings.length > 0,
+ 'flatLinearRings should have an array length larger than 0');
+ flatLinearRings.push(flatLinearRing);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GML2.prototype.outerBoundaryIsParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'outerBoundaryIs',
+ 'localName should be outerBoundaryIs');
+ /** @type {Array.<number>|undefined} */
+ var flatLinearRing = ol.xml.pushParseAndPop(undefined,
+ this.RING_PARSERS, node, objectStack, this);
+ if (flatLinearRing) {
+ var flatLinearRings = /** @type {Array.<Array.<number>>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(flatLinearRings),
+ 'flatLinearRings should be an array');
+ goog.asserts.assert(flatLinearRings.length > 0,
+ 'flatLinearRings should have an array length larger than 0');
+ flatLinearRings[0] = flatLinearRing;
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'coordinates': ol.xml.makeReplacer(
+ ol.format.GML2.prototype.readFlatCoordinates_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_,
+ 'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML2.prototype.BOX_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'coordinates': ol.xml.makeArrayPusher(
+ ol.format.GML2.prototype.readFlatCoordinates_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML2.prototype.GEOMETRY_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),
+ 'MultiPoint': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readMultiPoint),
+ 'LineString': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readLineString),
+ 'MultiLineString': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readMultiLineString),
+ 'LinearRing' : ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readLinearRing),
+ 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),
+ 'MultiPolygon': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readMultiPolygon),
+ 'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_)
+ }
+};
+
+goog.provide('ol.format.GML');
+goog.provide('ol.format.GML3');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.array');
+goog.require('ol.Feature');
+goog.require('ol.extent');
+goog.require('ol.format.Feature');
+goog.require('ol.format.GMLBase');
+goog.require('ol.format.XSD');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.LinearRing');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the GML format
+ * version 3.1.1.
+ * Currently only supports GML 3.1.1 Simple Features profile.
+ *
+ * @constructor
+ * @param {olx.format.GMLOptions=} opt_options
+ * Optional configuration object.
+ * @extends {ol.format.GMLBase}
+ * @api
+ */
+ol.format.GML3 = function(opt_options) {
+ var options = /** @type {olx.format.GMLOptions} */
+ (opt_options ? opt_options : {});
+
+ ol.format.GMLBase.call(this, options);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.surface_ = options.surface !== undefined ? options.surface : false;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.curve_ = options.curve !== undefined ? options.curve : false;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.multiCurve_ = options.multiCurve !== undefined ?
+ options.multiCurve : true;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.multiSurface_ = options.multiSurface !== undefined ?
+ options.multiSurface : true;
+
+ /**
+ * @inheritDoc
+ */
+ this.schemaLocation = options.schemaLocation ?
+ options.schemaLocation : ol.format.GML3.schemaLocation_;
+
+};
+ol.inherits(ol.format.GML3, ol.format.GMLBase);
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.GML3.schemaLocation_ = ol.format.GMLBase.GMLNS +
+ ' http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' +
+ '1.0.0/gmlsf.xsd';
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.MultiLineString|undefined} MultiLineString.
+ */
+ol.format.GML3.prototype.readMultiCurve_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MultiCurve',
+ 'localName should be MultiCurve');
+ /** @type {Array.<ol.geom.LineString>} */
+ var lineStrings = ol.xml.pushParseAndPop([],
+ this.MULTICURVE_PARSERS_, node, objectStack, this);
+ if (lineStrings) {
+ var multiLineString = new ol.geom.MultiLineString(null);
+ multiLineString.setLineStrings(lineStrings);
+ return multiLineString;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.MultiPolygon|undefined} MultiPolygon.
+ */
+ol.format.GML3.prototype.readMultiSurface_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MultiSurface',
+ 'localName should be MultiSurface');
+ /** @type {Array.<ol.geom.Polygon>} */
+ var polygons = ol.xml.pushParseAndPop([],
+ this.MULTISURFACE_PARSERS_, node, objectStack, this);
+ if (polygons) {
+ var multiPolygon = new ol.geom.MultiPolygon(null);
+ multiPolygon.setPolygons(polygons);
+ return multiPolygon;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GML3.prototype.curveMemberParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'curveMember' ||
+ node.localName == 'curveMembers',
+ 'localName should be curveMember or curveMembers');
+ ol.xml.parseNode(this.CURVEMEMBER_PARSERS_, node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GML3.prototype.surfaceMemberParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'surfaceMember' ||
+ node.localName == 'surfaceMembers',
+ 'localName should be surfaceMember or surfaceMembers');
+ ol.xml.parseNode(this.SURFACEMEMBER_PARSERS_,
+ node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<(Array.<number>)>|undefined} flat coordinates.
+ */
+ol.format.GML3.prototype.readPatch_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'patches',
+ 'localName should be patches');
+ return ol.xml.pushParseAndPop([null],
+ this.PATCHES_PARSERS_, node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>|undefined} flat coordinates.
+ */
+ol.format.GML3.prototype.readSegment_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'segments',
+ 'localName should be segments');
+ return ol.xml.pushParseAndPop([null],
+ this.SEGMENTS_PARSERS_, node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<(Array.<number>)>|undefined} flat coordinates.
+ */
+ol.format.GML3.prototype.readPolygonPatch_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'npde.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'PolygonPatch',
+ 'localName should be PolygonPatch');
+ return ol.xml.pushParseAndPop([null],
+ this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>|undefined} flat coordinates.
+ */
+ol.format.GML3.prototype.readLineStringSegment_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LineStringSegment',
+ 'localName should be LineStringSegment');
+ return ol.xml.pushParseAndPop([null],
+ this.GEOMETRY_FLAT_COORDINATES_PARSERS_,
+ node, objectStack, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GML3.prototype.interiorParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'interior',
+ 'localName should be interior');
+ /** @type {Array.<number>|undefined} */
+ var flatLinearRing = ol.xml.pushParseAndPop(undefined,
+ this.RING_PARSERS, node, objectStack, this);
+ if (flatLinearRing) {
+ var flatLinearRings = /** @type {Array.<Array.<number>>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(flatLinearRings),
+ 'flatLinearRings should be an array');
+ goog.asserts.assert(flatLinearRings.length > 0,
+ 'flatLinearRings should have an array length of 1 or more');
+ flatLinearRings.push(flatLinearRing);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GML3.prototype.exteriorParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'exterior',
+ 'localName should be exterior');
+ /** @type {Array.<number>|undefined} */
+ var flatLinearRing = ol.xml.pushParseAndPop(undefined,
+ this.RING_PARSERS, node, objectStack, this);
+ if (flatLinearRing) {
+ var flatLinearRings = /** @type {Array.<Array.<number>>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(flatLinearRings),
+ 'flatLinearRings should be an array');
+ goog.asserts.assert(flatLinearRings.length > 0,
+ 'flatLinearRings should have an array length of 1 or more');
+ flatLinearRings[0] = flatLinearRing;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.Polygon|undefined} Polygon.
+ */
+ol.format.GML3.prototype.readSurface_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Surface',
+ 'localName should be Surface');
+ /** @type {Array.<Array.<number>>} */
+ var flatLinearRings = ol.xml.pushParseAndPop([null],
+ this.SURFACE_PARSERS_, node, objectStack, this);
+ if (flatLinearRings && flatLinearRings[0]) {
+ var polygon = new ol.geom.Polygon(null);
+ var flatCoordinates = flatLinearRings[0];
+ var ends = [flatCoordinates.length];
+ var i, ii;
+ for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
+ ol.array.extend(flatCoordinates, flatLinearRings[i]);
+ ends.push(flatCoordinates.length);
+ }
+ polygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
+ return polygon;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.LineString|undefined} LineString.
+ */
+ol.format.GML3.prototype.readCurve_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Curve', 'localName should be Curve');
+ /** @type {Array.<number>} */
+ var flatCoordinates = ol.xml.pushParseAndPop([null],
+ this.CURVE_PARSERS_, node, objectStack, this);
+ if (flatCoordinates) {
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
+ return lineString;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.Extent|undefined} Envelope.
+ */
+ol.format.GML3.prototype.readEnvelope_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Envelope',
+ 'localName should be Envelope');
+ /** @type {Array.<number>} */
+ var flatCoordinates = ol.xml.pushParseAndPop([null],
+ this.ENVELOPE_PARSERS_, node, objectStack, this);
+ return ol.extent.createOrUpdate(flatCoordinates[1][0],
+ flatCoordinates[1][1], flatCoordinates[2][0],
+ flatCoordinates[2][1]);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>|undefined} Flat coordinates.
+ */
+ol.format.GML3.prototype.readFlatPos_ = function(node, objectStack) {
+ var s = ol.xml.getAllTextContent(node, false);
+ var re = /^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/;
+ /** @type {Array.<number>} */
+ var flatCoordinates = [];
+ var m;
+ while ((m = re.exec(s))) {
+ flatCoordinates.push(parseFloat(m[1]));
+ s = s.substr(m[0].length);
+ }
+ if (s !== '') {
+ return undefined;
+ }
+ var context = objectStack[0];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var containerSrs = context['srsName'];
+ var axisOrientation = 'enu';
+ if (containerSrs) {
+ var proj = ol.proj.get(containerSrs);
+ axisOrientation = proj.getAxisOrientation();
+ }
+ if (axisOrientation === 'neu') {
+ var i, ii;
+ for (i = 0, ii = flatCoordinates.length; i < ii; i += 3) {
+ var y = flatCoordinates[i];
+ var x = flatCoordinates[i + 1];
+ flatCoordinates[i] = x;
+ flatCoordinates[i + 1] = y;
+ }
+ }
+ var len = flatCoordinates.length;
+ if (len == 2) {
+ flatCoordinates.push(0);
+ }
+ if (len === 0) {
+ return undefined;
+ }
+ return flatCoordinates;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>|undefined} Flat coordinates.
+ */
+ol.format.GML3.prototype.readFlatPosList_ = function(node, objectStack) {
+ var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
+ var context = objectStack[0];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var containerSrs = context['srsName'];
+ var containerDimension = node.parentNode.getAttribute('srsDimension');
+ var axisOrientation = 'enu';
+ if (containerSrs) {
+ var proj = ol.proj.get(containerSrs);
+ axisOrientation = proj.getAxisOrientation();
+ }
+ var coords = s.split(/\s+/);
+ // The "dimension" attribute is from the GML 3.0.1 spec.
+ var dim = 2;
+ if (node.getAttribute('srsDimension')) {
+ dim = ol.format.XSD.readNonNegativeIntegerString(
+ node.getAttribute('srsDimension'));
+ } else if (node.getAttribute('dimension')) {
+ dim = ol.format.XSD.readNonNegativeIntegerString(
+ node.getAttribute('dimension'));
+ } else if (containerDimension) {
+ dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension);
+ }
+ var x, y, z;
+ var flatCoordinates = [];
+ for (var i = 0, ii = coords.length; i < ii; i += dim) {
+ x = parseFloat(coords[i]);
+ y = parseFloat(coords[i + 1]);
+ z = (dim === 3) ? parseFloat(coords[i + 2]) : 0;
+ if (axisOrientation.substr(0, 2) === 'en') {
+ flatCoordinates.push(x, y, z);
+ } else {
+ flatCoordinates.push(y, x, z);
+ }
+ }
+ return flatCoordinates;
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'pos': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPos_),
+ 'posList': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPosList_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.FLAT_LINEAR_RINGS_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'interior': ol.format.GML3.prototype.interiorParser_,
+ 'exterior': ol.format.GML3.prototype.exteriorParser_
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.GEOMETRY_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),
+ 'MultiPoint': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readMultiPoint),
+ 'LineString': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readLineString),
+ 'MultiLineString': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readMultiLineString),
+ 'LinearRing' : ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readLinearRing),
+ 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),
+ 'MultiPolygon': ol.xml.makeReplacer(
+ ol.format.GMLBase.prototype.readMultiPolygon),
+ 'Surface': ol.xml.makeReplacer(ol.format.GML3.prototype.readSurface_),
+ 'MultiSurface': ol.xml.makeReplacer(
+ ol.format.GML3.prototype.readMultiSurface_),
+ 'Curve': ol.xml.makeReplacer(ol.format.GML3.prototype.readCurve_),
+ 'MultiCurve': ol.xml.makeReplacer(
+ ol.format.GML3.prototype.readMultiCurve_),
+ 'Envelope': ol.xml.makeReplacer(ol.format.GML3.prototype.readEnvelope_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.MULTICURVE_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'curveMember': ol.xml.makeArrayPusher(
+ ol.format.GML3.prototype.curveMemberParser_),
+ 'curveMembers': ol.xml.makeArrayPusher(
+ ol.format.GML3.prototype.curveMemberParser_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.MULTISURFACE_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'surfaceMember': ol.xml.makeArrayPusher(
+ ol.format.GML3.prototype.surfaceMemberParser_),
+ 'surfaceMembers': ol.xml.makeArrayPusher(
+ ol.format.GML3.prototype.surfaceMemberParser_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.CURVEMEMBER_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'LineString': ol.xml.makeArrayPusher(
+ ol.format.GMLBase.prototype.readLineString),
+ 'Curve': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readCurve_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.SURFACEMEMBER_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'Polygon': ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readPolygon),
+ 'Surface': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readSurface_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.SURFACE_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'patches': ol.xml.makeReplacer(ol.format.GML3.prototype.readPatch_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.CURVE_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'segments': ol.xml.makeReplacer(ol.format.GML3.prototype.readSegment_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.ENVELOPE_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'lowerCorner': ol.xml.makeArrayPusher(
+ ol.format.GML3.prototype.readFlatPosList_),
+ 'upperCorner': ol.xml.makeArrayPusher(
+ ol.format.GML3.prototype.readFlatPosList_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.PATCHES_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'PolygonPatch': ol.xml.makeReplacer(
+ ol.format.GML3.prototype.readPolygonPatch_)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GML3.prototype.SEGMENTS_PARSERS_ = {
+ 'http://www.opengis.net/gml' : {
+ 'LineStringSegment': ol.xml.makeReplacer(
+ ol.format.GML3.prototype.readLineStringSegment_)
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Point} value Point geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writePos_ = function(node, value, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ var axisOrientation = 'enu';
+ if (srsName) {
+ axisOrientation = ol.proj.get(srsName).getAxisOrientation();
+ }
+ var point = value.getCoordinates();
+ var coords;
+ // only 2d for simple features profile
+ if (axisOrientation.substr(0, 2) === 'en') {
+ coords = (point[0] + ' ' + point[1]);
+ } else {
+ coords = (point[1] + ' ' + point[0]);
+ }
+ ol.format.XSD.writeStringTextNode(node, coords);
+};
+
+
+/**
+ * @param {Array.<number>} point Point geometry.
+ * @param {string=} opt_srsName Optional srsName
+ * @return {string} The coords string.
+ * @private
+ */
+ol.format.GML3.prototype.getCoords_ = function(point, opt_srsName) {
+ var axisOrientation = 'enu';
+ if (opt_srsName) {
+ axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation();
+ }
+ return ((axisOrientation.substr(0, 2) === 'en') ?
+ point[0] + ' ' + point[1] :
+ point[1] + ' ' + point[0]);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writePosList_ = function(node, value, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ // only 2d for simple features profile
+ var points = value.getCoordinates();
+ var len = points.length;
+ var parts = new Array(len);
+ var point;
+ for (var i = 0; i < len; ++i) {
+ point = points[i];
+ parts[i] = this.getCoords_(point, srsName);
+ }
+ ol.format.XSD.writeStringTextNode(node, parts.join(' '));
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Point} geometry Point geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writePoint_ = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ var pos = ol.xml.createElementNS(node.namespaceURI, 'pos');
+ node.appendChild(pos);
+ this.writePos_(pos, geometry, objectStack);
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GML3.ENVELOPE_SERIALIZERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Extent} extent Extent.
+ * @param {Array.<*>} objectStack Node stack.
+ */
+ol.format.GML3.prototype.writeEnvelope = function(node, extent, objectStack) {
+ goog.asserts.assert(extent.length == 4, 'extent should have 4 items');
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ var keys = ['lowerCorner', 'upperCorner'];
+ var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]];
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
+ ({node: node}), ol.format.GML3.ENVELOPE_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
+ values,
+ objectStack, keys, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LinearRing} geometry LinearRing geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeLinearRing_ = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ var posList = ol.xml.createElementNS(node.namespaceURI, 'posList');
+ node.appendChild(posList);
+ this.writePosList_(posList, geometry, objectStack);
+};
+
+
+/**
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node} Node.
+ * @private
+ */
+ol.format.GML3.prototype.RING_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
+ var context = objectStack[objectStack.length - 1];
+ var parentNode = context.node;
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var exteriorWritten = context['exteriorWritten'];
+ if (exteriorWritten === undefined) {
+ context['exteriorWritten'] = true;
+ }
+ return ol.xml.createElementNS(parentNode.namespaceURI,
+ exteriorWritten !== undefined ? 'interior' : 'exterior');
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Polygon} geometry Polygon geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeSurfaceOrPolygon_ = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ if (node.nodeName !== 'PolygonPatch' && srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') {
+ var rings = geometry.getLinearRings();
+ ol.xml.pushSerializeAndPop(
+ {node: node, srsName: srsName},
+ ol.format.GML3.RING_SERIALIZERS_,
+ this.RING_NODE_FACTORY_,
+ rings, objectStack, undefined, this);
+ } else if (node.nodeName === 'Surface') {
+ var patches = ol.xml.createElementNS(node.namespaceURI, 'patches');
+ node.appendChild(patches);
+ this.writeSurfacePatches_(
+ patches, geometry, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LineString} geometry LineString geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeCurveOrLineString_ = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ if (node.nodeName !== 'LineStringSegment' && srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ if (node.nodeName === 'LineString' ||
+ node.nodeName === 'LineStringSegment') {
+ var posList = ol.xml.createElementNS(node.namespaceURI, 'posList');
+ node.appendChild(posList);
+ this.writePosList_(posList, geometry, objectStack);
+ } else if (node.nodeName === 'Curve') {
+ var segments = ol.xml.createElementNS(node.namespaceURI, 'segments');
+ node.appendChild(segments);
+ this.writeCurveSegments_(segments,
+ geometry, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_ = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ var surface = context['surface'];
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ var polygons = geometry.getPolygons();
+ ol.xml.pushSerializeAndPop({node: node, srsName: srsName, surface: surface},
+ ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_,
+ this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons,
+ objectStack, undefined, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.MultiPoint} geometry MultiPoint geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeMultiPoint_ = function(node, geometry,
+ objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ var points = geometry.getPoints();
+ ol.xml.pushSerializeAndPop({node: node, srsName: srsName},
+ ol.format.GML3.POINTMEMBER_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('pointMember'), points,
+ objectStack, undefined, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.MultiLineString} geometry MultiLineString geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeMultiCurveOrLineString_ = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var srsName = context['srsName'];
+ var curve = context['curve'];
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ var lines = geometry.getLineStrings();
+ ol.xml.pushSerializeAndPop({node: node, srsName: srsName, curve: curve},
+ ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_,
+ this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines,
+ objectStack, undefined, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LinearRing} ring LinearRing geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeRing_ = function(node, ring, objectStack) {
+ var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing');
+ node.appendChild(linearRing);
+ this.writeLinearRing_(linearRing, ring, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Polygon} polygon Polygon geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeSurfaceOrPolygonMember_ = function(node, polygon, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var child = this.GEOMETRY_NODE_FACTORY_(
+ polygon, objectStack);
+ if (child) {
+ node.appendChild(child);
+ this.writeSurfaceOrPolygon_(child, polygon, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Point} point Point geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writePointMember_ = function(node, point, objectStack) {
+ var child = ol.xml.createElementNS(node.namespaceURI, 'Point');
+ node.appendChild(child);
+ this.writePoint_(child, point, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LineString} line LineString geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeLineStringOrCurveMember_ = function(node, line, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack);
+ if (child) {
+ node.appendChild(child);
+ this.writeCurveOrLineString_(child, line, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Polygon} polygon Polygon geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeSurfacePatches_ = function(node, polygon, objectStack) {
+ var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch');
+ node.appendChild(child);
+ this.writeSurfaceOrPolygon_(child, polygon, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LineString} line LineString geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeCurveSegments_ = function(node, line, objectStack) {
+ var child = ol.xml.createElementNS(node.namespaceURI,
+ 'LineStringSegment');
+ node.appendChild(child);
+ this.writeCurveOrLineString_(child, line, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.
+ * @param {Array.<*>} objectStack Node stack.
+ */
+ol.format.GML3.prototype.writeGeometryElement = function(node, geometry, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var item = ol.object.assign({}, context);
+ item.node = node;
+ var value;
+ if (Array.isArray(geometry)) {
+ if (context.dataProjection) {
+ value = ol.proj.transformExtent(
+ geometry, context.featureProjection, context.dataProjection);
+ } else {
+ value = geometry;
+ }
+ } else {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Geometry,
+ 'geometry should be an ol.geom.Geometry');
+ value =
+ ol.format.Feature.transformWithOptions(geometry, true, context);
+ }
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
+ (item), ol.format.GML3.GEOMETRY_SERIALIZERS_,
+ this.GEOMETRY_NODE_FACTORY_, [value],
+ objectStack, undefined, this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Node stack.
+ */
+ol.format.GML3.prototype.writeFeatureElement = function(node, feature, objectStack) {
+ var fid = feature.getId();
+ if (fid) {
+ node.setAttribute('fid', fid);
+ }
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var featureNS = context['featureNS'];
+ var geometryName = feature.getGeometryName();
+ if (!context.serializers) {
+ context.serializers = {};
+ context.serializers[featureNS] = {};
+ }
+ var properties = feature.getProperties();
+ var keys = [], values = [];
+ for (var key in properties) {
+ var value = properties[key];
+ if (value !== null) {
+ keys.push(key);
+ values.push(value);
+ if (key == geometryName || value instanceof ol.geom.Geometry) {
+ if (!(key in context.serializers[featureNS])) {
+ context.serializers[featureNS][key] = ol.xml.makeChildAppender(
+ this.writeGeometryElement, this);
+ }
+ } else {
+ if (!(key in context.serializers[featureNS])) {
+ context.serializers[featureNS][key] = ol.xml.makeChildAppender(
+ ol.format.XSD.writeStringTextNode);
+ }
+ }
+ }
+ }
+ var item = ol.object.assign({}, context);
+ item.node = node;
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
+ (item), context.serializers,
+ ol.xml.makeSimpleNodeFactory(undefined, featureNS),
+ values,
+ objectStack, keys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GML3.prototype.writeFeatureMembers_ = function(node, features, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var featureType = context['featureType'];
+ var featureNS = context['featureNS'];
+ var serializers = {};
+ serializers[featureNS] = {};
+ serializers[featureNS][featureType] = ol.xml.makeChildAppender(
+ this.writeFeatureElement, this);
+ var item = ol.object.assign({}, context);
+ item.node = node;
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
+ (item),
+ serializers,
+ ol.xml.makeSimpleNodeFactory(featureType, featureNS), features,
+ objectStack);
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'surfaceMember': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeSurfaceOrPolygonMember_),
+ 'polygonMember': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeSurfaceOrPolygonMember_)
+ }
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GML3.POINTMEMBER_SERIALIZERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'pointMember': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writePointMember_)
+ }
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'lineStringMember': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeLineStringOrCurveMember_),
+ 'curveMember': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeLineStringOrCurveMember_)
+ }
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GML3.RING_SERIALIZERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'exterior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_),
+ 'interior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_)
+ }
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GML3.GEOMETRY_SERIALIZERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'Curve': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeCurveOrLineString_),
+ 'MultiCurve': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeMultiCurveOrLineString_),
+ 'Point': ol.xml.makeChildAppender(ol.format.GML3.prototype.writePoint_),
+ 'MultiPoint': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeMultiPoint_),
+ 'LineString': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeCurveOrLineString_),
+ 'MultiLineString': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeMultiCurveOrLineString_),
+ 'LinearRing': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeLinearRing_),
+ 'Polygon': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeSurfaceOrPolygon_),
+ 'MultiPolygon': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_),
+ 'Surface': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeSurfaceOrPolygon_),
+ 'MultiSurface': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_),
+ 'Envelope': ol.xml.makeChildAppender(
+ ol.format.GML3.prototype.writeEnvelope)
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, string>}
+ * @private
+ */
+ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = {
+ 'MultiLineString': 'lineStringMember',
+ 'MultiCurve': 'curveMember',
+ 'MultiPolygon': 'polygonMember',
+ 'MultiSurface': 'surfaceMember'
+};
+
+
+/**
+ * @const
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node|undefined} Node.
+ * @private
+ */
+ol.format.GML3.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
+ var parentNode = objectStack[objectStack.length - 1].node;
+ goog.asserts.assert(ol.xml.isNode(parentNode),
+ 'parentNode should be a node');
+ return ol.xml.createElementNS('http://www.opengis.net/gml',
+ ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]);
+};
+
+
+/**
+ * @const
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node|undefined} Node.
+ * @private
+ */
+ol.format.GML3.prototype.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var multiSurface = context['multiSurface'];
+ var surface = context['surface'];
+ var curve = context['curve'];
+ var multiCurve = context['multiCurve'];
+ var parentNode = objectStack[objectStack.length - 1].node;
+ goog.asserts.assert(ol.xml.isNode(parentNode),
+ 'parentNode should be a node');
+ var nodeName;
+ if (!Array.isArray(value)) {
+ goog.asserts.assertInstanceof(value, ol.geom.Geometry,
+ 'value should be an ol.geom.Geometry');
+ nodeName = value.getType();
+ if (nodeName === 'MultiPolygon' && multiSurface === true) {
+ nodeName = 'MultiSurface';
+ } else if (nodeName === 'Polygon' && surface === true) {
+ nodeName = 'Surface';
+ } else if (nodeName === 'LineString' && curve === true) {
+ nodeName = 'Curve';
+ } else if (nodeName === 'MultiLineString' && multiCurve === true) {
+ nodeName = 'MultiCurve';
+ }
+ } else {
+ nodeName = 'Envelope';
+ }
+ return ol.xml.createElementNS('http://www.opengis.net/gml',
+ nodeName);
+};
+
+
+/**
+ * Encode a geometry in GML 3.1.1 Simple Features.
+ *
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ * @api
+ */
+ol.format.GML3.prototype.writeGeometryNode = function(geometry, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom');
+ var context = {node: geom, srsName: this.srsName,
+ curve: this.curve_, surface: this.surface_,
+ multiSurface: this.multiSurface_, multiCurve: this.multiCurve_};
+ if (opt_options) {
+ ol.object.assign(context, opt_options);
+ }
+ this.writeGeometryElement(geom, geometry, [context]);
+ return geom;
+};
+
+
+/**
+ * Encode an array of features in GML 3.1.1 Simple Features.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {string} Result.
+ * @api stable
+ */
+ol.format.GML3.prototype.writeFeatures;
+
+
+/**
+ * Encode an array of features in the GML 3.1.1 format as an XML node.
+ *
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ * @api
+ */
+ol.format.GML3.prototype.writeFeaturesNode = function(features, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ var node = ol.xml.createElementNS('http://www.opengis.net/gml',
+ 'featureMembers');
+ ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation', this.schemaLocation);
+ var context = {
+ srsName: this.srsName,
+ curve: this.curve_,
+ surface: this.surface_,
+ multiSurface: this.multiSurface_,
+ multiCurve: this.multiCurve_,
+ featureNS: this.featureNS,
+ featureType: this.featureType
+ };
+ if (opt_options) {
+ ol.object.assign(context, opt_options);
+ }
+ this.writeFeatureMembers_(node, features, [context]);
+ return node;
+};
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the GML format
+ * version 3.1.1.
+ * Currently only supports GML 3.1.1 Simple Features profile.
+ *
+ * @constructor
+ * @param {olx.format.GMLOptions=} opt_options
+ * Optional configuration object.
+ * @extends {ol.format.GMLBase}
+ * @api stable
+ */
+ol.format.GML = ol.format.GML3;
+
+
+/**
+ * Encode an array of features in GML 3.1.1 Simple Features.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {string} Result.
+ * @api stable
+ */
+ol.format.GML.prototype.writeFeatures;
+
+
+/**
+ * Encode an array of features in the GML 3.1.1 format as an XML node.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ * @api
+ */
+ol.format.GML.prototype.writeFeaturesNode;
+
+goog.provide('ol.format.GPX');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.array');
+goog.require('ol.format.Feature');
+goog.require('ol.format.XMLFeature');
+goog.require('ol.format.XSD');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.Point');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the GPX format.
+ *
+ * @constructor
+ * @extends {ol.format.XMLFeature}
+ * @param {olx.format.GPXOptions=} opt_options Options.
+ * @api stable
+ */
+ol.format.GPX = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.XMLFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get('EPSG:4326');
+
+ /**
+ * @type {function(ol.Feature, Node)|undefined}
+ * @private
+ */
+ this.readExtensions_ = options.readExtensions;
+};
+ol.inherits(ol.format.GPX, ol.format.XMLFeature);
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<string>}
+ */
+ol.format.GPX.NAMESPACE_URIS_ = [
+ null,
+ 'http://www.topografix.com/GPX/1/0',
+ 'http://www.topografix.com/GPX/1/1'
+];
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.GPX.SCHEMA_LOCATION_ = 'http://www.topografix.com/GPX/1/1 ' +
+ 'http://www.topografix.com/GPX/1/1/gpx.xsd';
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {Node} node Node.
+ * @param {Object} values Values.
+ * @private
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ flatCoordinates.push(
+ parseFloat(node.getAttribute('lon')),
+ parseFloat(node.getAttribute('lat')));
+ if ('ele' in values) {
+ flatCoordinates.push(/** @type {number} */ (values['ele']));
+ delete values['ele'];
+ } else {
+ flatCoordinates.push(0);
+ }
+ if ('time' in values) {
+ flatCoordinates.push(/** @type {number} */ (values['time']));
+ delete values['time'];
+ } else {
+ flatCoordinates.push(0);
+ }
+ return flatCoordinates;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.parseLink_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'link', 'localName should be link');
+ var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ var href = node.getAttribute('href');
+ if (href !== null) {
+ values['link'] = href;
+ }
+ ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.parseExtensions_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'extensions',
+ 'localName should be extensions');
+ var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ values['extensionsNode_'] = node;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.parseRtePt_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'rtept', 'localName should be rtept');
+ var values = ol.xml.pushParseAndPop(
+ {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack);
+ if (values) {
+ var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ var flatCoordinates = /** @type {Array.<number>} */
+ (rteValues['flatCoordinates']);
+ ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.parseTrkPt_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'trkpt', 'localName should be trkpt');
+ var values = ol.xml.pushParseAndPop(
+ {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack);
+ if (values) {
+ var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ var flatCoordinates = /** @type {Array.<number>} */
+ (trkValues['flatCoordinates']);
+ ol.format.GPX.appendCoordinate_(flatCoordinates, node, values);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.parseTrkSeg_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'trkseg',
+ 'localName should be trkseg');
+ var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack);
+ var flatCoordinates = /** @type {Array.<number>} */
+ (values['flatCoordinates']);
+ var ends = /** @type {Array.<number>} */ (values['ends']);
+ ends.push(flatCoordinates.length);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.Feature|undefined} Track.
+ */
+ol.format.GPX.readRte_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'rte', 'localName should be rte');
+ var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
+ var values = ol.xml.pushParseAndPop({
+ 'flatCoordinates': []
+ }, ol.format.GPX.RTE_PARSERS_, node, objectStack);
+ if (!values) {
+ return undefined;
+ }
+ var flatCoordinates = /** @type {Array.<number>} */
+ (values['flatCoordinates']);
+ delete values['flatCoordinates'];
+ var geometry = new ol.geom.LineString(null);
+ geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);
+ ol.format.Feature.transformWithOptions(geometry, false, options);
+ var feature = new ol.Feature(geometry);
+ feature.setProperties(values);
+ return feature;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.Feature|undefined} Track.
+ */
+ol.format.GPX.readTrk_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'trk', 'localName should be trk');
+ var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
+ var values = ol.xml.pushParseAndPop({
+ 'flatCoordinates': [],
+ 'ends': []
+ }, ol.format.GPX.TRK_PARSERS_, node, objectStack);
+ if (!values) {
+ return undefined;
+ }
+ var flatCoordinates = /** @type {Array.<number>} */
+ (values['flatCoordinates']);
+ delete values['flatCoordinates'];
+ var ends = /** @type {Array.<number>} */ (values['ends']);
+ delete values['ends'];
+ var geometry = new ol.geom.MultiLineString(null);
+ geometry.setFlatCoordinates(
+ ol.geom.GeometryLayout.XYZM, flatCoordinates, ends);
+ ol.format.Feature.transformWithOptions(geometry, false, options);
+ var feature = new ol.Feature(geometry);
+ feature.setProperties(values);
+ return feature;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.Feature|undefined} Waypoint.
+ */
+ol.format.GPX.readWpt_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'wpt', 'localName should be wpt');
+ var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
+ var values = ol.xml.pushParseAndPop(
+ {}, ol.format.GPX.WPT_PARSERS_, node, objectStack);
+ if (!values) {
+ return undefined;
+ }
+ var coordinates = ol.format.GPX.appendCoordinate_([], node, values);
+ var geometry = new ol.geom.Point(
+ coordinates, ol.geom.GeometryLayout.XYZM);
+ ol.format.Feature.transformWithOptions(geometry, false, options);
+ var feature = new ol.Feature(geometry);
+ feature.setProperties(values);
+ return feature;
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>}
+ * @private
+ */
+ol.format.GPX.FEATURE_READER_ = {
+ 'rte': ol.format.GPX.readRte_,
+ 'trk': ol.format.GPX.readTrk_,
+ 'wpt': ol.format.GPX.readWpt_
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_),
+ 'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_),
+ 'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'text':
+ ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'),
+ 'type':
+ ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType')
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'link': ol.format.GPX.parseLink_,
+ 'number':
+ ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
+ 'extensions': ol.format.GPX.parseExtensions_,
+ 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'rtept': ol.format.GPX.parseRtePt_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'link': ol.format.GPX.parseLink_,
+ 'number':
+ ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
+ 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'extensions': ol.format.GPX.parseExtensions_,
+ 'trkseg': ol.format.GPX.parseTrkSeg_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'trkpt': ol.format.GPX.parseTrkPt_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.GPX.WPT_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime),
+ 'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'link': ol.format.GPX.parseLink_,
+ 'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'sat': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'ageofdgpsdata':
+ ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'dgpsid':
+ ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
+ 'extensions': ol.format.GPX.parseExtensions_
+ });
+
+
+/**
+ * @param {Array.<ol.Feature>} features List of features.
+ * @private
+ */
+ol.format.GPX.prototype.handleReadExtensions_ = function(features) {
+ if (!features) {
+ features = [];
+ }
+ for (var i = 0, ii = features.length; i < ii; ++i) {
+ var feature = features[i];
+ if (this.readExtensions_) {
+ var extensionsNode = feature.get('extensionsNode_') || null;
+ this.readExtensions_(feature, extensionsNode);
+ }
+ feature.set('extensionsNode_', undefined);
+ }
+};
+
+
+/**
+ * Read the first feature from a GPX source.
+ * Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)
+ * into MultiLineString. Any properties on route and track waypoints are ignored.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api stable
+ */
+ol.format.GPX.prototype.readFeature;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {
+ return null;
+ }
+ var featureReader = ol.format.GPX.FEATURE_READER_[node.localName];
+ if (!featureReader) {
+ return null;
+ }
+ var feature = featureReader(node, [this.getReadOptions(node, opt_options)]);
+ if (!feature) {
+ return null;
+ }
+ this.handleReadExtensions_([feature]);
+ return feature;
+};
+
+
+/**
+ * Read all features from a GPX source.
+ * Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)
+ * into MultiLineString. Any properties on route and track waypoints are ignored.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.GPX.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {
+ return [];
+ }
+ if (node.localName == 'gpx') {
+ /** @type {Array.<ol.Feature>} */
+ var features = ol.xml.pushParseAndPop([], ol.format.GPX.GPX_PARSERS_,
+ node, [this.getReadOptions(node, opt_options)]);
+ if (features) {
+ this.handleReadExtensions_(features);
+ return features;
+ } else {
+ return [];
+ }
+ }
+ return [];
+};
+
+
+/**
+ * Read the projection from a GPX source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.GPX.prototype.readProjection;
+
+
+/**
+ * @param {Node} node Node.
+ * @param {string} value Value for the link's `href` attribute.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.GPX.writeLink_ = function(node, value, objectStack) {
+ node.setAttribute('href', value);
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var properties = context['properties'];
+ var link = [
+ properties['linkText'],
+ properties['linkType']
+ ];
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */ ({node: node}),
+ ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
+ link, objectStack, ol.format.GPX.LINK_SEQUENCE_);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var parentNode = context.node;
+ goog.asserts.assert(ol.xml.isNode(parentNode),
+ 'parentNode should be an XML node');
+ var namespaceURI = parentNode.namespaceURI;
+ var properties = context['properties'];
+ //FIXME Projection handling
+ ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]);
+ ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]);
+ var geometryLayout = context['geometryLayout'];
+ switch (geometryLayout) {
+ case ol.geom.GeometryLayout.XYZM:
+ if (coordinate[3] !== 0) {
+ properties['time'] = coordinate[3];
+ }
+ // fall through
+ case ol.geom.GeometryLayout.XYZ:
+ if (coordinate[2] !== 0) {
+ properties['ele'] = coordinate[2];
+ }
+ break;
+ case ol.geom.GeometryLayout.XYM:
+ if (coordinate[2] !== 0) {
+ properties['time'] = coordinate[2];
+ }
+ break;
+ default:
+ // pass
+ }
+ var orderedKeys = (node.nodeName == 'rtept') ?
+ ol.format.GPX.RTEPT_TYPE_SEQUENCE_[namespaceURI] :
+ ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
+ ({node: node, 'properties': properties}),
+ ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
+ values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.writeRte_ = function(node, feature, objectStack) {
+ var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
+ var properties = feature.getProperties();
+ var context = {node: node, 'properties': properties};
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
+ 'geometry should be an ol.geom.LineString');
+ geometry = /** @type {ol.geom.LineString} */
+ (ol.format.Feature.transformWithOptions(geometry, true, options));
+ context['geometryLayout'] = geometry.getLayout();
+ properties['rtept'] = geometry.getCoordinates();
+ }
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
+ values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.writeTrk_ = function(node, feature, objectStack) {
+ var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
+ var properties = feature.getProperties();
+ /** @type {ol.XmlNodeStackItem} */
+ var context = {node: node, 'properties': properties};
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString,
+ 'geometry should be an ol.geom.MultiLineString');
+ geometry = /** @type {ol.geom.MultiLineString} */
+ (ol.format.Feature.transformWithOptions(geometry, true, options));
+ properties['trkseg'] = geometry.getLineStrings();
+ }
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
+ values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LineString} lineString LineString.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) {
+ /** @type {ol.XmlNodeStackItem} */
+ var context = {node: node, 'geometryLayout': lineString.getLayout(),
+ 'properties': {}};
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_,
+ lineString.getCoordinates(), objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.GPX.writeWpt_ = function(node, feature, objectStack) {
+ var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ context['properties'] = feature.getProperties();
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Point,
+ 'geometry should be an ol.geom.Point');
+ geometry = /** @type {ol.geom.Point} */
+ (ol.format.Feature.transformWithOptions(geometry, true, options));
+ context['geometryLayout'] = geometry.getLayout();
+ ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack);
+ }
+};
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.GPX.LINK_SEQUENCE_ = ['text', 'type'];
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, [
+ 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
+ 'number': ol.xml.makeChildAppender(
+ ol.format.XSD.writeNonNegativeIntegerTextNode),
+ 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(
+ ol.format.GPX.writeWptType_))
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.GPX.RTEPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, [
+ 'ele', 'time'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, [
+ 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
+ 'number': ol.xml.makeChildAppender(
+ ol.format.XSD.writeNonNegativeIntegerTextNode),
+ 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(
+ ol.format.GPX.writeTrkSeg_))
+ });
+
+
+/**
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt');
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, [
+ 'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src',
+ 'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop',
+ 'ageofdgpsdata', 'dgpsid'
+ ]);
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode),
+ 'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'geoidheight': ol.xml.makeChildAppender(
+ ol.format.XSD.writeDecimalTextNode),
+ 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
+ 'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'sat': ol.xml.makeChildAppender(
+ ol.format.XSD.writeNonNegativeIntegerTextNode),
+ 'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'ageofdgpsdata': ol.xml.makeChildAppender(
+ ol.format.XSD.writeDecimalTextNode),
+ 'dgpsid': ol.xml.makeChildAppender(
+ ol.format.XSD.writeNonNegativeIntegerTextNode)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, string>}
+ * @private
+ */
+ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = {
+ 'Point': 'wpt',
+ 'LineString': 'rte',
+ 'MultiLineString': 'trk'
+};
+
+
+/**
+ * @const
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node|undefined} Node.
+ * @private
+ */
+ol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
+ goog.asserts.assertInstanceof(value, ol.Feature,
+ 'value should be an ol.Feature');
+ var geometry = value.getGeometry();
+ if (geometry) {
+ var nodeName = ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()];
+ if (nodeName) {
+ var parentNode = objectStack[objectStack.length - 1].node;
+ goog.asserts.assert(ol.xml.isNode(parentNode),
+ 'parentNode should be an XML node');
+ return ol.xml.createElementNS(parentNode.namespaceURI, nodeName);
+ }
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.GPX.NAMESPACE_URIS_, {
+ 'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_),
+ 'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_),
+ 'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_)
+ });
+
+
+/**
+ * Encode an array of features in the GPX format.
+ * LineString geometries are output as routes (`<rte>`), and MultiLineString
+ * as tracks (`<trk>`).
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} Result.
+ * @api stable
+ */
+ol.format.GPX.prototype.writeFeatures;
+
+
+/**
+ * Encode an array of features in the GPX format as an XML node.
+ * LineString geometries are output as routes (`<rte>`), and MultiLineString
+ * as tracks (`<trk>`).
+ *
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ * @api
+ */
+ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ //FIXME Serialize metadata
+ var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');
+ var xmlnsUri = 'http://www.w3.org/2000/xmlns/';
+ var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance';
+ ol.xml.setAttributeNS(gpx, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri);
+ ol.xml.setAttributeNS(gpx, xmlSchemaInstanceUri, 'xsi:schemaLocation',
+ ol.format.GPX.SCHEMA_LOCATION_);
+ gpx.setAttribute('version', '1.1');
+ gpx.setAttribute('creator', 'OpenLayers 3');
+
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
+ ({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_,
+ ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]);
+ return gpx;
+};
+
+goog.provide('ol.format.TextFeature');
+
+goog.require('goog.asserts');
+goog.require('ol.format.Feature');
+goog.require('ol.format.FormatType');
+
+
+/**
+ * @classdesc
+ * Abstract base class; normally only used for creating subclasses and not
+ * instantiated in apps.
+ * Base class for text feature formats.
+ *
+ * @constructor
+ * @extends {ol.format.Feature}
+ */
+ol.format.TextFeature = function() {
+ ol.format.Feature.call(this);
+};
+ol.inherits(ol.format.TextFeature, ol.format.Feature);
+
+
+/**
+ * @param {Document|Node|Object|string} source Source.
+ * @private
+ * @return {string} Text.
+ */
+ol.format.TextFeature.prototype.getText_ = function(source) {
+ if (typeof source === 'string') {
+ return source;
+ } else {
+ goog.asserts.fail();
+ return '';
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.getType = function() {
+ return ol.format.FormatType.TEXT;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.readFeature = function(source, opt_options) {
+ return this.readFeatureFromText(
+ this.getText_(source), this.adaptOptions(opt_options));
+};
+
+
+/**
+ * @param {string} text Text.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @protected
+ * @return {ol.Feature} Feature.
+ */
+ol.format.TextFeature.prototype.readFeatureFromText = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) {
+ return this.readFeaturesFromText(
+ this.getText_(source), this.adaptOptions(opt_options));
+};
+
+
+/**
+ * @param {string} text Text.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @protected
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.format.TextFeature.prototype.readFeaturesFromText = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) {
+ return this.readGeometryFromText(
+ this.getText_(source), this.adaptOptions(opt_options));
+};
+
+
+/**
+ * @param {string} text Text.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @protected
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.TextFeature.prototype.readGeometryFromText = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.readProjection = function(source) {
+ return this.readProjectionFromText(this.getText_(source));
+};
+
+
+/**
+ * @param {string} text Text.
+ * @protected
+ * @return {ol.proj.Projection} Projection.
+ */
+ol.format.TextFeature.prototype.readProjectionFromText = function(text) {
+ return this.defaultDataProjection;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) {
+ return this.writeFeatureText(feature, this.adaptOptions(opt_options));
+};
+
+
+/**
+ * @param {ol.Feature} feature Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @protected
+ * @return {string} Text.
+ */
+ol.format.TextFeature.prototype.writeFeatureText = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.writeFeatures = function(
+ features, opt_options) {
+ return this.writeFeaturesText(features, this.adaptOptions(opt_options));
+};
+
+
+/**
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @protected
+ * @return {string} Text.
+ */
+ol.format.TextFeature.prototype.writeFeaturesText = goog.abstractMethod;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TextFeature.prototype.writeGeometry = function(
+ geometry, opt_options) {
+ return this.writeGeometryText(geometry, this.adaptOptions(opt_options));
+};
+
+
+/**
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @protected
+ * @return {string} Text.
+ */
+ol.format.TextFeature.prototype.writeGeometryText = goog.abstractMethod;
+
+goog.provide('ol.format.IGC');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.TextFeature');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.proj');
+
+
+/**
+ * IGC altitude/z. One of 'barometric', 'gps', 'none'.
+ * @enum {string}
+ */
+ol.format.IGCZ = {
+ BAROMETRIC: 'barometric',
+ GPS: 'gps',
+ NONE: 'none'
+};
+
+
+/**
+ * @classdesc
+ * Feature format for `*.igc` flight recording files.
+ *
+ * @constructor
+ * @extends {ol.format.TextFeature}
+ * @param {olx.format.IGCOptions=} opt_options Options.
+ * @api
+ */
+ol.format.IGC = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.TextFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get('EPSG:4326');
+
+ /**
+ * @private
+ * @type {ol.format.IGCZ}
+ */
+ this.altitudeMode_ = options.altitudeMode ?
+ options.altitudeMode : ol.format.IGCZ.NONE;
+
+};
+ol.inherits(ol.format.IGC, ol.format.TextFeature);
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.IGC.EXTENSIONS_ = ['.igc'];
+
+
+/**
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.format.IGC.B_RECORD_RE_ =
+ /^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/;
+
+
+/**
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/;
+
+
+/**
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\d{2})(\d{2})(\d{2})/;
+
+
+/**
+ * A regular expression matching the newline characters `\r\n`, `\r` and `\n`.
+ *
+ * @const
+ * @type {RegExp}
+ * @private
+ */
+ol.format.IGC.NEWLINE_RE_ = /\r\n|\r|\n/;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.IGC.prototype.getExtensions = function() {
+ return ol.format.IGC.EXTENSIONS_;
+};
+
+
+/**
+ * Read the feature from the IGC source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api
+ */
+ol.format.IGC.prototype.readFeature;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) {
+ var altitudeMode = this.altitudeMode_;
+ var lines = text.split(ol.format.IGC.NEWLINE_RE_);
+ /** @type {Object.<string, string>} */
+ var properties = {};
+ var flatCoordinates = [];
+ var year = 2000;
+ var month = 0;
+ var day = 1;
+ var lastDateTime = -1;
+ var i, ii;
+ for (i = 0, ii = lines.length; i < ii; ++i) {
+ var line = lines[i];
+ var m;
+ if (line.charAt(0) == 'B') {
+ m = ol.format.IGC.B_RECORD_RE_.exec(line);
+ if (m) {
+ var hour = parseInt(m[1], 10);
+ var minute = parseInt(m[2], 10);
+ var second = parseInt(m[3], 10);
+ var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000;
+ if (m[6] == 'S') {
+ y = -y;
+ }
+ var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000;
+ if (m[9] == 'W') {
+ x = -x;
+ }
+ flatCoordinates.push(x, y);
+ if (altitudeMode != ol.format.IGCZ.NONE) {
+ var z;
+ if (altitudeMode == ol.format.IGCZ.GPS) {
+ z = parseInt(m[11], 10);
+ } else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) {
+ z = parseInt(m[12], 10);
+ } else {
+ goog.asserts.fail();
+ z = 0;
+ }
+ flatCoordinates.push(z);
+ }
+ var dateTime = Date.UTC(year, month, day, hour, minute, second);
+ // Detect UTC midnight wrap around.
+ if (dateTime < lastDateTime) {
+ dateTime = Date.UTC(year, month, day + 1, hour, minute, second);
+ }
+ flatCoordinates.push(dateTime / 1000);
+ lastDateTime = dateTime;
+ }
+ } else if (line.charAt(0) == 'H') {
+ m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line);
+ if (m) {
+ day = parseInt(m[1], 10);
+ month = parseInt(m[2], 10) - 1;
+ year = 2000 + parseInt(m[3], 10);
+ } else {
+ m = ol.format.IGC.H_RECORD_RE_.exec(line);
+ if (m) {
+ properties[m[1]] = m[2].trim();
+ }
+ }
+ }
+ }
+ if (flatCoordinates.length === 0) {
+ return null;
+ }
+ var lineString = new ol.geom.LineString(null);
+ var layout = altitudeMode == ol.format.IGCZ.NONE ?
+ ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM;
+ lineString.setFlatCoordinates(layout, flatCoordinates);
+ var feature = new ol.Feature(ol.format.Feature.transformWithOptions(
+ lineString, false, opt_options));
+ feature.setProperties(properties);
+ return feature;
+};
+
+
+/**
+ * Read the feature from the source. As IGC sources contain a single
+ * feature, this will return the feature in an array.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api
+ */
+ol.format.IGC.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) {
+ var feature = this.readFeatureFromText(text, opt_options);
+ if (feature) {
+ return [feature];
+ } else {
+ return [];
+ }
+};
+
+
+/**
+ * Read the projection from the IGC source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api
+ */
+ol.format.IGC.prototype.readProjection;
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Generics method for collection-like classes and objects.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ *
+ * This file contains functions to work with collections. It supports using
+ * Map, Set, Array and Object and other classes that implement collection-like
+ * methods.
+ */
+
+
+goog.provide('goog.structs');
+
+goog.require('goog.array');
+goog.require('goog.object');
+
+
+// We treat an object as a dictionary if it has getKeys or it is an object that
+// isn't arrayLike.
+
+
+/**
+ * Returns the number of values in the collection-like object.
+ * @param {Object} col The collection-like object.
+ * @return {number} The number of values in the collection-like object.
+ */
+goog.structs.getCount = function(col) {
+ if (col.getCount && typeof col.getCount == 'function') {
+ return col.getCount();
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return col.length;
+ }
+ return goog.object.getCount(col);
+};
+
+
+/**
+ * Returns the values of the collection-like object.
+ * @param {Object} col The collection-like object.
+ * @return {!Array<?>} The values in the collection-like object.
+ */
+goog.structs.getValues = function(col) {
+ if (col.getValues && typeof col.getValues == 'function') {
+ return col.getValues();
+ }
+ if (goog.isString(col)) {
+ return col.split('');
+ }
+ if (goog.isArrayLike(col)) {
+ var rv = [];
+ var l = col.length;
+ for (var i = 0; i < l; i++) {
+ rv.push(col[i]);
+ }
+ return rv;
+ }
+ return goog.object.getValues(col);
+};
+
+
+/**
+ * Returns the keys of the collection. Some collections have no notion of
+ * keys/indexes and this function will return undefined in those cases.
+ * @param {Object} col The collection-like object.
+ * @return {!Array|undefined} The keys in the collection.
+ */
+goog.structs.getKeys = function(col) {
+ if (col.getKeys && typeof col.getKeys == 'function') {
+ return col.getKeys();
+ }
+ // if we have getValues but no getKeys we know this is a key-less collection
+ if (col.getValues && typeof col.getValues == 'function') {
+ return undefined;
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ var rv = [];
+ var l = col.length;
+ for (var i = 0; i < l; i++) {
+ rv.push(i);
+ }
+ return rv;
+ }
+
+ return goog.object.getKeys(col);
+};
+
+
+/**
+ * Whether the collection contains the given value. This is O(n) and uses
+ * equals (==) to test the existence.
+ * @param {Object} col The collection-like object.
+ * @param {*} val The value to check for.
+ * @return {boolean} True if the map contains the value.
+ */
+goog.structs.contains = function(col, val) {
+ if (col.contains && typeof col.contains == 'function') {
+ return col.contains(val);
+ }
+ if (col.containsValue && typeof col.containsValue == 'function') {
+ return col.containsValue(val);
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return goog.array.contains(/** @type {!Array<?>} */ (col), val);
+ }
+ return goog.object.containsValue(col, val);
+};
+
+
+/**
+ * Whether the collection is empty.
+ * @param {Object} col The collection-like object.
+ * @return {boolean} True if empty.
+ */
+goog.structs.isEmpty = function(col) {
+ if (col.isEmpty && typeof col.isEmpty == 'function') {
+ return col.isEmpty();
+ }
+
+ // We do not use goog.string.isEmptyOrWhitespace because here we treat the
+ // string as
+ // collection and as such even whitespace matters
+
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return goog.array.isEmpty(/** @type {!Array<?>} */ (col));
+ }
+ return goog.object.isEmpty(col);
+};
+
+
+/**
+ * Removes all the elements from the collection.
+ * @param {Object} col The collection-like object.
+ */
+goog.structs.clear = function(col) {
+ // NOTE(arv): This should not contain strings because strings are immutable
+ if (col.clear && typeof col.clear == 'function') {
+ col.clear();
+ } else if (goog.isArrayLike(col)) {
+ goog.array.clear(/** @type {IArrayLike<?>} */ (col));
+ } else {
+ goog.object.clear(col);
+ }
+};
+
+
+/**
+ * Calls a function for each value in a collection. The function takes
+ * three arguments; the value, the key and the collection.
+ *
+ * NOTE: This will be deprecated soon! Please use a more specific method if
+ * possible, e.g. goog.array.forEach, goog.object.forEach, etc.
+ *
+ * @param {S} col The collection-like object.
+ * @param {function(this:T,?,?,S):?} f The function to call for every value.
+ * This function takes
+ * 3 arguments (the value, the key or undefined if the collection has no
+ * notion of keys, and the collection) and the return value is irrelevant.
+ * @param {T=} opt_obj The object to be used as the value of 'this'
+ * within {@code f}.
+ * @template T,S
+ */
+goog.structs.forEach = function(col, f, opt_obj) {
+ if (col.forEach && typeof col.forEach == 'function') {
+ col.forEach(f, opt_obj);
+ } else if (goog.isArrayLike(col) || goog.isString(col)) {
+ goog.array.forEach(/** @type {!Array<?>} */ (col), f, opt_obj);
+ } else {
+ var keys = goog.structs.getKeys(col);
+ var values = goog.structs.getValues(col);
+ var l = values.length;
+ for (var i = 0; i < l; i++) {
+ f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col);
+ }
+ }
+};
+
+
+/**
+ * Calls a function for every value in the collection. When a call returns true,
+ * adds the value to a new collection (Array is returned by default).
+ *
+ * @param {S} col The collection-like object.
+ * @param {function(this:T,?,?,S):boolean} f The function to call for every
+ * value. This function takes
+ * 3 arguments (the value, the key or undefined if the collection has no
+ * notion of keys, and the collection) and should return a Boolean. If the
+ * return value is true the value is added to the result collection. If it
+ * is false the value is not included.
+ * @param {T=} opt_obj The object to be used as the value of 'this'
+ * within {@code f}.
+ * @return {!Object|!Array<?>} A new collection where the passed values are
+ * present. If col is a key-less collection an array is returned. If col
+ * has keys and values a plain old JS object is returned.
+ * @template T,S
+ */
+goog.structs.filter = function(col, f, opt_obj) {
+ if (typeof col.filter == 'function') {
+ return col.filter(f, opt_obj);
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return goog.array.filter(/** @type {!Array<?>} */ (col), f, opt_obj);
+ }
+
+ var rv;
+ var keys = goog.structs.getKeys(col);
+ var values = goog.structs.getValues(col);
+ var l = values.length;
+ if (keys) {
+ rv = {};
+ for (var i = 0; i < l; i++) {
+ if (f.call(/** @type {?} */ (opt_obj), values[i], keys[i], col)) {
+ rv[keys[i]] = values[i];
+ }
+ }
+ } else {
+ // We should not use goog.array.filter here since we want to make sure that
+ // the index is undefined as well as make sure that col is passed to the
+ // function.
+ rv = [];
+ for (var i = 0; i < l; i++) {
+ if (f.call(opt_obj, values[i], undefined, col)) {
+ rv.push(values[i]);
+ }
+ }
+ }
+ return rv;
+};
+
+
+/**
+ * Calls a function for every value in the collection and adds the result into a
+ * new collection (defaults to creating a new Array).
+ *
+ * @param {S} col The collection-like object.
+ * @param {function(this:T,?,?,S):V} f The function to call for every value.
+ * This function takes 3 arguments (the value, the key or undefined if the
+ * collection has no notion of keys, and the collection) and should return
+ * something. The result will be used as the value in the new collection.
+ * @param {T=} opt_obj The object to be used as the value of 'this'
+ * within {@code f}.
+ * @return {!Object<V>|!Array<V>} A new collection with the new values. If
+ * col is a key-less collection an array is returned. If col has keys and
+ * values a plain old JS object is returned.
+ * @template T,S,V
+ */
+goog.structs.map = function(col, f, opt_obj) {
+ if (typeof col.map == 'function') {
+ return col.map(f, opt_obj);
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return goog.array.map(/** @type {!Array<?>} */ (col), f, opt_obj);
+ }
+
+ var rv;
+ var keys = goog.structs.getKeys(col);
+ var values = goog.structs.getValues(col);
+ var l = values.length;
+ if (keys) {
+ rv = {};
+ for (var i = 0; i < l; i++) {
+ rv[keys[i]] = f.call(/** @type {?} */ (opt_obj), values[i], keys[i], col);
+ }
+ } else {
+ // We should not use goog.array.map here since we want to make sure that
+ // the index is undefined as well as make sure that col is passed to the
+ // function.
+ rv = [];
+ for (var i = 0; i < l; i++) {
+ rv[i] = f.call(/** @type {?} */ (opt_obj), values[i], undefined, col);
+ }
+ }
+ return rv;
+};
+
+
+/**
+ * Calls f for each value in a collection. If any call returns true this returns
+ * true (without checking the rest). If all returns false this returns false.
+ *
+ * @param {S} col The collection-like object.
+ * @param {function(this:T,?,?,S):boolean} f The function to call for every
+ * value. This function takes 3 arguments (the value, the key or undefined
+ * if the collection has no notion of keys, and the collection) and should
+ * return a boolean.
+ * @param {T=} opt_obj The object to be used as the value of 'this'
+ * within {@code f}.
+ * @return {boolean} True if any value passes the test.
+ * @template T,S
+ */
+goog.structs.some = function(col, f, opt_obj) {
+ if (typeof col.some == 'function') {
+ return col.some(f, opt_obj);
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return goog.array.some(/** @type {!Array<?>} */ (col), f, opt_obj);
+ }
+ var keys = goog.structs.getKeys(col);
+ var values = goog.structs.getValues(col);
+ var l = values.length;
+ for (var i = 0; i < l; i++) {
+ if (f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Calls f for each value in a collection. If all calls return true this return
+ * true this returns true. If any returns false this returns false at this point
+ * and does not continue to check the remaining values.
+ *
+ * @param {S} col The collection-like object.
+ * @param {function(this:T,?,?,S):boolean} f The function to call for every
+ * value. This function takes 3 arguments (the value, the key or
+ * undefined if the collection has no notion of keys, and the collection)
+ * and should return a boolean.
+ * @param {T=} opt_obj The object to be used as the value of 'this'
+ * within {@code f}.
+ * @return {boolean} True if all key-value pairs pass the test.
+ * @template T,S
+ */
+goog.structs.every = function(col, f, opt_obj) {
+ if (typeof col.every == 'function') {
+ return col.every(f, opt_obj);
+ }
+ if (goog.isArrayLike(col) || goog.isString(col)) {
+ return goog.array.every(/** @type {!Array<?>} */ (col), f, opt_obj);
+ }
+ var keys = goog.structs.getKeys(col);
+ var values = goog.structs.getValues(col);
+ var l = values.length;
+ for (var i = 0; i < l; i++) {
+ if (!f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Python style iteration utilities.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.iter');
+goog.provide('goog.iter.Iterable');
+goog.provide('goog.iter.Iterator');
+goog.provide('goog.iter.StopIteration');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.functions');
+goog.require('goog.math');
+
+
+/**
+ * @typedef {goog.iter.Iterator|{length:number}|{__iterator__}}
+ */
+goog.iter.Iterable;
+
+
+/**
+ * Singleton Error object that is used to terminate iterations.
+ * @const {!Error}
+ */
+goog.iter.StopIteration = ('StopIteration' in goog.global) ?
+ // For script engines that support legacy iterators.
+ goog.global['StopIteration'] :
+ {message: 'StopIteration', stack: ''};
+
+
+
+/**
+ * Class/interface for iterators. An iterator needs to implement a {@code next}
+ * method and it needs to throw a {@code goog.iter.StopIteration} when the
+ * iteration passes beyond the end. Iterators have no {@code hasNext} method.
+ * It is recommended to always use the helper functions to iterate over the
+ * iterator or in case you are only targeting JavaScript 1.7 for in loops.
+ * @constructor
+ * @template VALUE
+ */
+goog.iter.Iterator = function() {};
+
+
+/**
+ * Returns the next value of the iteration. This will throw the object
+ * {@see goog.iter#StopIteration} when the iteration passes the end.
+ * @return {VALUE} Any object or value.
+ */
+goog.iter.Iterator.prototype.next = function() {
+ throw goog.iter.StopIteration;
+};
+
+
+/**
+ * Returns the {@code Iterator} object itself. This is used to implement
+ * the iterator protocol in JavaScript 1.7
+ * @param {boolean=} opt_keys Whether to return the keys or values. Default is
+ * to only return the values. This is being used by the for-in loop (true)
+ * and the for-each-in loop (false). Even though the param gives a hint
+ * about what the iterator will return there is no guarantee that it will
+ * return the keys when true is passed.
+ * @return {!goog.iter.Iterator<VALUE>} The object itself.
+ */
+goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) {
+ return this;
+};
+
+
+/**
+ * Returns an iterator that knows how to iterate over the values in the object.
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable If the
+ * object is an iterator it will be returned as is. If the object has an
+ * {@code __iterator__} method that will be called to get the value
+ * iterator. If the object is an array-like object we create an iterator
+ * for that.
+ * @return {!goog.iter.Iterator<VALUE>} An iterator that knows how to iterate
+ * over the values in {@code iterable}.
+ * @template VALUE
+ */
+goog.iter.toIterator = function(iterable) {
+ if (iterable instanceof goog.iter.Iterator) {
+ return iterable;
+ }
+ if (typeof iterable.__iterator__ == 'function') {
+ return iterable.__iterator__(false);
+ }
+ if (goog.isArrayLike(iterable)) {
+ var i = 0;
+ var newIter = new goog.iter.Iterator;
+ newIter.next = function() {
+ while (true) {
+ if (i >= iterable.length) {
+ throw goog.iter.StopIteration;
+ }
+ // Don't include deleted elements.
+ if (!(i in iterable)) {
+ i++;
+ continue;
+ }
+ return iterable[i++];
+ }
+ };
+ return newIter;
+ }
+
+
+ // TODO(arv): Should we fall back on goog.structs.getValues()?
+ throw Error('Not implemented');
+};
+
+
+/**
+ * Calls a function for each element in the iterator with the element of the
+ * iterator passed as argument.
+ *
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * to iterate over. If the iterable is an object {@code toIterator} will be
+ * called on it.
+ * @param {function(this:THIS,VALUE,?,!goog.iter.Iterator<VALUE>)} f
+ * The function to call for every element. This function takes 3 arguments
+ * (the element, undefined, and the iterator) and the return value is
+ * irrelevant. The reason for passing undefined as the second argument is
+ * so that the same function can be used in {@see goog.array#forEach} as
+ * well as others. The third parameter is of type "number" for
+ * arraylike objects, undefined, otherwise.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @template THIS, VALUE
+ */
+goog.iter.forEach = function(iterable, f, opt_obj) {
+ if (goog.isArrayLike(iterable)) {
+ /** @preserveTry */
+ try {
+ // NOTES: this passes the index number to the second parameter
+ // of the callback contrary to the documentation above.
+ goog.array.forEach(
+ /** @type {IArrayLike<?>} */ (iterable), f, opt_obj);
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ }
+ } else {
+ iterable = goog.iter.toIterator(iterable);
+ /** @preserveTry */
+ try {
+ while (true) {
+ f.call(opt_obj, iterable.next(), undefined, iterable);
+ }
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ }
+ }
+};
+
+
+/**
+ * Calls a function for every element in the iterator, and if the function
+ * returns true adds the element to a new iterator.
+ *
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * to iterate over.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f
+ * The function to call for every element. This function takes 3 arguments
+ * (the element, undefined, and the iterator) and should return a boolean.
+ * If the return value is true the element will be included in the returned
+ * iterator. If it is false the element is not included.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements
+ * that passed the test are present.
+ * @template THIS, VALUE
+ */
+goog.iter.filter = function(iterable, f, opt_obj) {
+ var iterator = goog.iter.toIterator(iterable);
+ var newIter = new goog.iter.Iterator;
+ newIter.next = function() {
+ while (true) {
+ var val = iterator.next();
+ if (f.call(opt_obj, val, undefined, iterator)) {
+ return val;
+ }
+ }
+ };
+ return newIter;
+};
+
+
+/**
+ * Calls a function for every element in the iterator, and if the function
+ * returns false adds the element to a new iterator.
+ *
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * to iterate over.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f
+ * The function to call for every element. This function takes 3 arguments
+ * (the element, undefined, and the iterator) and should return a boolean.
+ * If the return value is false the element will be included in the returned
+ * iterator. If it is true the element is not included.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements
+ * that did not pass the test are present.
+ * @template THIS, VALUE
+ */
+goog.iter.filterFalse = function(iterable, f, opt_obj) {
+ return goog.iter.filter(iterable, goog.functions.not(f), opt_obj);
+};
+
+
+/**
+ * Creates a new iterator that returns the values in a range. This function
+ * can take 1, 2 or 3 arguments:
+ * <pre>
+ * range(5) same as range(0, 5, 1)
+ * range(2, 5) same as range(2, 5, 1)
+ * </pre>
+ *
+ * @param {number} startOrStop The stop value if only one argument is provided.
+ * The start value if 2 or more arguments are provided. If only one
+ * argument is used the start value is 0.
+ * @param {number=} opt_stop The stop value. If left out then the first
+ * argument is used as the stop value.
+ * @param {number=} opt_step The number to increment with between each call to
+ * next. This can be negative.
+ * @return {!goog.iter.Iterator<number>} A new iterator that returns the values
+ * in the range.
+ */
+goog.iter.range = function(startOrStop, opt_stop, opt_step) {
+ var start = 0;
+ var stop = startOrStop;
+ var step = opt_step || 1;
+ if (arguments.length > 1) {
+ start = startOrStop;
+ stop = opt_stop;
+ }
+ if (step == 0) {
+ throw Error('Range step argument must not be zero');
+ }
+
+ var newIter = new goog.iter.Iterator;
+ newIter.next = function() {
+ if (step > 0 && start >= stop || step < 0 && start <= stop) {
+ throw goog.iter.StopIteration;
+ }
+ var rv = start;
+ start += step;
+ return rv;
+ };
+ return newIter;
+};
+
+
+/**
+ * Joins the values in a iterator with a delimiter.
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * to get the values from.
+ * @param {string} deliminator The text to put between the values.
+ * @return {string} The joined value string.
+ * @template VALUE
+ */
+goog.iter.join = function(iterable, deliminator) {
+ return goog.iter.toArray(iterable).join(deliminator);
+};
+
+
+/**
+ * For every element in the iterator call a function and return a new iterator
+ * with that value.
+ *
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterator to iterate over.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):RESULT} f
+ * The function to call for every element. This function takes 3 arguments
+ * (the element, undefined, and the iterator) and should return a new value.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the
+ * results of applying the function to each element in the original
+ * iterator.
+ * @template THIS, VALUE, RESULT
+ */
+goog.iter.map = function(iterable, f, opt_obj) {
+ var iterator = goog.iter.toIterator(iterable);
+ var newIter = new goog.iter.Iterator;
+ newIter.next = function() {
+ var val = iterator.next();
+ return f.call(opt_obj, val, undefined, iterator);
+ };
+ return newIter;
+};
+
+
+/**
+ * Passes every element of an iterator into a function and accumulates the
+ * result.
+ *
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * to iterate over.
+ * @param {function(this:THIS,VALUE,VALUE):VALUE} f The function to call for
+ * every element. This function takes 2 arguments (the function's previous
+ * result or the initial value, and the value of the current element).
+ * function(previousValue, currentElement) : newValue.
+ * @param {VALUE} val The initial value to pass into the function on the first
+ * call.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * f.
+ * @return {VALUE} Result of evaluating f repeatedly across the values of
+ * the iterator.
+ * @template THIS, VALUE
+ */
+goog.iter.reduce = function(iterable, f, val, opt_obj) {
+ var rval = val;
+ goog.iter.forEach(
+ iterable, function(val) { rval = f.call(opt_obj, rval, val); });
+ return rval;
+};
+
+
+/**
+ * Goes through the values in the iterator. Calls f for each of these, and if
+ * any of them returns true, this returns true (without checking the rest). If
+ * all return false this will return false.
+ *
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * object.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f
+ * The function to call for every value. This function takes 3 arguments
+ * (the value, undefined, and the iterator) and should return a boolean.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {boolean} true if any value passes the test.
+ * @template THIS, VALUE
+ */
+goog.iter.some = function(iterable, f, opt_obj) {
+ iterable = goog.iter.toIterator(iterable);
+ /** @preserveTry */
+ try {
+ while (true) {
+ if (f.call(opt_obj, iterable.next(), undefined, iterable)) {
+ return true;
+ }
+ }
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Goes through the values in the iterator. Calls f for each of these and if any
+ * of them returns false this returns false (without checking the rest). If all
+ * return true this will return true.
+ *
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * object.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f
+ * The function to call for every value. This function takes 3 arguments
+ * (the value, undefined, and the iterator) and should return a boolean.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {boolean} true if every value passes the test.
+ * @template THIS, VALUE
+ */
+goog.iter.every = function(iterable, f, opt_obj) {
+ iterable = goog.iter.toIterator(iterable);
+ /** @preserveTry */
+ try {
+ while (true) {
+ if (!f.call(opt_obj, iterable.next(), undefined, iterable)) {
+ return false;
+ }
+ }
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Takes zero or more iterables and returns one iterator that will iterate over
+ * them in the order chained.
+ * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any
+ * number of iterable objects.
+ * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will
+ * iterate over all the given iterables' contents.
+ * @template VALUE
+ */
+goog.iter.chain = function(var_args) {
+ return goog.iter.chainFromIterable(arguments);
+};
+
+
+/**
+ * Takes a single iterable containing zero or more iterables and returns one
+ * iterator that will iterate over each one in the order given.
+ * @see https://goo.gl/5NRp5d
+ * @param {goog.iter.Iterable} iterable The iterable of iterables to chain.
+ * @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will
+ * iterate over all the contents of the iterables contained within
+ * {@code iterable}.
+ * @template VALUE
+ */
+goog.iter.chainFromIterable = function(iterable) {
+ var iterator = goog.iter.toIterator(iterable);
+ var iter = new goog.iter.Iterator();
+ var current = null;
+
+ iter.next = function() {
+ while (true) {
+ if (current == null) {
+ var it = iterator.next();
+ current = goog.iter.toIterator(it);
+ }
+ try {
+ return current.next();
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ current = null;
+ }
+ }
+ };
+
+ return iter;
+};
+
+
+/**
+ * Builds a new iterator that iterates over the original, but skips elements as
+ * long as a supplied function returns true.
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * object.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f
+ * The function to call for every value. This function takes 3 arguments
+ * (the value, undefined, and the iterator) and should return a boolean.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator that drops elements from
+ * the original iterator as long as {@code f} is true.
+ * @template THIS, VALUE
+ */
+goog.iter.dropWhile = function(iterable, f, opt_obj) {
+ var iterator = goog.iter.toIterator(iterable);
+ var newIter = new goog.iter.Iterator;
+ var dropping = true;
+ newIter.next = function() {
+ while (true) {
+ var val = iterator.next();
+ if (dropping && f.call(opt_obj, val, undefined, iterator)) {
+ continue;
+ } else {
+ dropping = false;
+ }
+ return val;
+ }
+ };
+ return newIter;
+};
+
+
+/**
+ * Builds a new iterator that iterates over the original, but only as long as a
+ * supplied function returns true.
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * object.
+ * @param {
+ * function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f
+ * The function to call for every value. This function takes 3 arguments
+ * (the value, undefined, and the iterator) and should return a boolean.
+ * @param {THIS=} opt_obj This is used as the 'this' object in f when called.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator that keeps elements in
+ * the original iterator as long as the function is true.
+ * @template THIS, VALUE
+ */
+goog.iter.takeWhile = function(iterable, f, opt_obj) {
+ var iterator = goog.iter.toIterator(iterable);
+ var iter = new goog.iter.Iterator();
+ iter.next = function() {
+ var val = iterator.next();
+ if (f.call(opt_obj, val, undefined, iterator)) {
+ return val;
+ }
+ throw goog.iter.StopIteration;
+ };
+ return iter;
+};
+
+
+/**
+ * Converts the iterator to an array
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator
+ * to convert to an array.
+ * @return {!Array<VALUE>} An array of the elements the iterator iterates over.
+ * @template VALUE
+ */
+goog.iter.toArray = function(iterable) {
+ // Fast path for array-like.
+ if (goog.isArrayLike(iterable)) {
+ return goog.array.toArray(/** @type {!IArrayLike<?>} */ (iterable));
+ }
+ iterable = goog.iter.toIterator(iterable);
+ var array = [];
+ goog.iter.forEach(iterable, function(val) { array.push(val); });
+ return array;
+};
+
+
+/**
+ * Iterates over two iterables and returns true if they contain the same
+ * sequence of elements and have the same length.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable1 The first
+ * iterable object.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable2 The second
+ * iterable object.
+ * @param {function(VALUE,VALUE):boolean=} opt_equalsFn Optional comparison
+ * function.
+ * Should take two arguments to compare, and return true if the arguments
+ * are equal. Defaults to {@link goog.array.defaultCompareEquality} which
+ * compares the elements using the built-in '===' operator.
+ * @return {boolean} true if the iterables contain the same sequence of elements
+ * and have the same length.
+ * @template VALUE
+ */
+goog.iter.equals = function(iterable1, iterable2, opt_equalsFn) {
+ var fillValue = {};
+ var pairs = goog.iter.zipLongest(fillValue, iterable1, iterable2);
+ var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality;
+ return goog.iter.every(
+ pairs, function(pair) { return equalsFn(pair[0], pair[1]); });
+};
+
+
+/**
+ * Advances the iterator to the next position, returning the given default value
+ * instead of throwing an exception if the iterator has no more entries.
+ * @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterable
+ * object.
+ * @param {VALUE} defaultValue The value to return if the iterator is empty.
+ * @return {VALUE} The next item in the iteration, or defaultValue if the
+ * iterator was empty.
+ * @template VALUE
+ */
+goog.iter.nextOrValue = function(iterable, defaultValue) {
+ try {
+ return goog.iter.toIterator(iterable).next();
+ } catch (e) {
+ if (e != goog.iter.StopIteration) {
+ throw e;
+ }
+ return defaultValue;
+ }
+};
+
+
+/**
+ * Cartesian product of zero or more sets. Gives an iterator that gives every
+ * combination of one element chosen from each set. For example,
+ * ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]).
+ * @see http://docs.python.org/library/itertools.html#itertools.product
+ * @param {...!IArrayLike<VALUE>} var_args Zero or more sets, as
+ * arrays.
+ * @return {!goog.iter.Iterator<!Array<VALUE>>} An iterator that gives each
+ * n-tuple (as an array).
+ * @template VALUE
+ */
+goog.iter.product = function(var_args) {
+ var someArrayEmpty =
+ goog.array.some(arguments, function(arr) { return !arr.length; });
+
+ // An empty set in a cartesian product gives an empty set.
+ if (someArrayEmpty || !arguments.length) {
+ return new goog.iter.Iterator();
+ }
+
+ var iter = new goog.iter.Iterator();
+ var arrays = arguments;
+
+ // The first indices are [0, 0, ...]
+ var indicies = goog.array.repeat(0, arrays.length);
+
+ iter.next = function() {
+
+ if (indicies) {
+ var retVal = goog.array.map(indicies, function(valueIndex, arrayIndex) {
+ return arrays[arrayIndex][valueIndex];
+ });
+
+ // Generate the next-largest indices for the next call.
+ // Increase the rightmost index. If it goes over, increase the next
+ // rightmost (like carry-over addition).
+ for (var i = indicies.length - 1; i >= 0; i--) {
+ // Assertion prevents compiler warning below.
+ goog.asserts.assert(indicies);
+ if (indicies[i] < arrays[i].length - 1) {
+ indicies[i]++;
+ break;
+ }
+
+ // We're at the last indices (the last element of every array), so
+ // the iteration is over on the next call.
+ if (i == 0) {
+ indicies = null;
+ break;
+ }
+ // Reset the index in this column and loop back to increment the
+ // next one.
+ indicies[i] = 0;
+ }
+ return retVal;
+ }
+
+ throw goog.iter.StopIteration;
+ };
+
+ return iter;
+};
+
+
+/**
+ * Create an iterator to cycle over the iterable's elements indefinitely.
+ * For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ...
+ * @see: http://docs.python.org/library/itertools.html#itertools.cycle.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable object.
+ * @return {!goog.iter.Iterator<VALUE>} An iterator that iterates indefinitely
+ * over the values in {@code iterable}.
+ * @template VALUE
+ */
+goog.iter.cycle = function(iterable) {
+ var baseIterator = goog.iter.toIterator(iterable);
+
+ // We maintain a cache to store the iterable elements as we iterate
+ // over them. The cache is used to return elements once we have
+ // iterated over the iterable once.
+ var cache = [];
+ var cacheIndex = 0;
+
+ var iter = new goog.iter.Iterator();
+
+ // This flag is set after the iterable is iterated over once
+ var useCache = false;
+
+ iter.next = function() {
+ var returnElement = null;
+
+ // Pull elements off the original iterator if not using cache
+ if (!useCache) {
+ try {
+ // Return the element from the iterable
+ returnElement = baseIterator.next();
+ cache.push(returnElement);
+ return returnElement;
+ } catch (e) {
+ // If an exception other than StopIteration is thrown
+ // or if there are no elements to iterate over (the iterable was empty)
+ // throw an exception
+ if (e != goog.iter.StopIteration || goog.array.isEmpty(cache)) {
+ throw e;
+ }
+ // set useCache to true after we know that a 'StopIteration' exception
+ // was thrown and the cache is not empty (to handle the 'empty iterable'
+ // use case)
+ useCache = true;
+ }
+ }
+
+ returnElement = cache[cacheIndex];
+ cacheIndex = (cacheIndex + 1) % cache.length;
+
+ return returnElement;
+ };
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that counts indefinitely from a starting value.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.count
+ * @param {number=} opt_start The starting value. Default is 0.
+ * @param {number=} opt_step The number to increment with between each call to
+ * next. Negative and floating point numbers are allowed. Default is 1.
+ * @return {!goog.iter.Iterator<number>} A new iterator that returns the values
+ * in the series.
+ */
+goog.iter.count = function(opt_start, opt_step) {
+ var counter = opt_start || 0;
+ var step = goog.isDef(opt_step) ? opt_step : 1;
+ var iter = new goog.iter.Iterator();
+
+ iter.next = function() {
+ var returnValue = counter;
+ counter += step;
+ return returnValue;
+ };
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that returns the same object or value repeatedly.
+ * @param {VALUE} value Any object or value to repeat.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the
+ * repeated value.
+ * @template VALUE
+ */
+goog.iter.repeat = function(value) {
+ var iter = new goog.iter.Iterator();
+
+ iter.next = goog.functions.constant(value);
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that returns running totals from the numbers in
+ * {@code iterable}. For example, the array {@code [1, 2, 3, 4, 5]} yields
+ * {@code 1 -> 3 -> 6 -> 10 -> 15}.
+ * @see http://docs.python.org/3.2/library/itertools.html#itertools.accumulate
+ * @param {!goog.iter.Iterable<number>} iterable The iterable of numbers to
+ * accumulate.
+ * @return {!goog.iter.Iterator<number>} A new iterator that returns the
+ * numbers in the series.
+ */
+goog.iter.accumulate = function(iterable) {
+ var iterator = goog.iter.toIterator(iterable);
+ var total = 0;
+ var iter = new goog.iter.Iterator();
+
+ iter.next = function() {
+ total += iterator.next();
+ return total;
+ };
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that returns arrays containing the ith elements from the
+ * provided iterables. The returned arrays will be the same size as the number
+ * of iterables given in {@code var_args}. Once the shortest iterable is
+ * exhausted, subsequent calls to {@code next()} will throw
+ * {@code goog.iter.StopIteration}.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.izip
+ * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any
+ * number of iterable objects.
+ * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns
+ * arrays of elements from the provided iterables.
+ * @template VALUE
+ */
+goog.iter.zip = function(var_args) {
+ var args = arguments;
+ var iter = new goog.iter.Iterator();
+
+ if (args.length > 0) {
+ var iterators = goog.array.map(args, goog.iter.toIterator);
+ iter.next = function() {
+ var arr = goog.array.map(iterators, function(it) { return it.next(); });
+ return arr;
+ };
+ }
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that returns arrays containing the ith elements from the
+ * provided iterables. The returned arrays will be the same size as the number
+ * of iterables given in {@code var_args}. Shorter iterables will be extended
+ * with {@code fillValue}. Once the longest iterable is exhausted, subsequent
+ * calls to {@code next()} will throw {@code goog.iter.StopIteration}.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.izip_longest
+ * @param {VALUE} fillValue The object or value used to fill shorter iterables.
+ * @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any
+ * number of iterable objects.
+ * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns
+ * arrays of elements from the provided iterables.
+ * @template VALUE
+ */
+goog.iter.zipLongest = function(fillValue, var_args) {
+ var args = goog.array.slice(arguments, 1);
+ var iter = new goog.iter.Iterator();
+
+ if (args.length > 0) {
+ var iterators = goog.array.map(args, goog.iter.toIterator);
+
+ iter.next = function() {
+ var iteratorsHaveValues = false; // false when all iterators are empty.
+ var arr = goog.array.map(iterators, function(it) {
+ var returnValue;
+ try {
+ returnValue = it.next();
+ // Iterator had a value, so we've not exhausted the iterators.
+ // Set flag accordingly.
+ iteratorsHaveValues = true;
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ returnValue = fillValue;
+ }
+ return returnValue;
+ });
+
+ if (!iteratorsHaveValues) {
+ throw goog.iter.StopIteration;
+ }
+ return arr;
+ };
+ }
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that filters {@code iterable} based on a series of
+ * {@code selectors}. On each call to {@code next()}, one item is taken from
+ * both the {@code iterable} and {@code selectors} iterators. If the item from
+ * {@code selectors} evaluates to true, the item from {@code iterable} is given.
+ * Otherwise, it is skipped. Once either {@code iterable} or {@code selectors}
+ * is exhausted, subsequent calls to {@code next()} will throw
+ * {@code goog.iter.StopIteration}.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.compress
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to filter.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} selectors An
+ * iterable of items to be evaluated in a boolean context to determine if
+ * the corresponding element in {@code iterable} should be included in the
+ * result.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the
+ * filtered values.
+ * @template VALUE
+ */
+goog.iter.compress = function(iterable, selectors) {
+ var selectorIterator = goog.iter.toIterator(selectors);
+
+ return goog.iter.filter(
+ iterable, function() { return !!selectorIterator.next(); });
+};
+
+
+
+/**
+ * Implements the {@code goog.iter.groupBy} iterator.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to group.
+ * @param {function(VALUE): KEY=} opt_keyFunc Optional function for
+ * determining the key value for each group in the {@code iterable}. Default
+ * is the identity function.
+ * @constructor
+ * @extends {goog.iter.Iterator<!Array<?>>}
+ * @template KEY, VALUE
+ * @private
+ */
+goog.iter.GroupByIterator_ = function(iterable, opt_keyFunc) {
+
+ /**
+ * The iterable to group, coerced to an iterator.
+ * @type {!goog.iter.Iterator}
+ */
+ this.iterator = goog.iter.toIterator(iterable);
+
+ /**
+ * A function for determining the key value for each element in the iterable.
+ * If no function is provided, the identity function is used and returns the
+ * element unchanged.
+ * @type {function(VALUE): KEY}
+ */
+ this.keyFunc = opt_keyFunc || goog.functions.identity;
+
+ /**
+ * The target key for determining the start of a group.
+ * @type {KEY}
+ */
+ this.targetKey;
+
+ /**
+ * The current key visited during iteration.
+ * @type {KEY}
+ */
+ this.currentKey;
+
+ /**
+ * The current value being added to the group.
+ * @type {VALUE}
+ */
+ this.currentValue;
+};
+goog.inherits(goog.iter.GroupByIterator_, goog.iter.Iterator);
+
+
+/** @override */
+goog.iter.GroupByIterator_.prototype.next = function() {
+ while (this.currentKey == this.targetKey) {
+ this.currentValue = this.iterator.next(); // Exits on StopIteration
+ this.currentKey = this.keyFunc(this.currentValue);
+ }
+ this.targetKey = this.currentKey;
+ return [this.currentKey, this.groupItems_(this.targetKey)];
+};
+
+
+/**
+ * Performs the grouping of objects using the given key.
+ * @param {KEY} targetKey The target key object for the group.
+ * @return {!Array<VALUE>} An array of grouped objects.
+ * @private
+ */
+goog.iter.GroupByIterator_.prototype.groupItems_ = function(targetKey) {
+ var arr = [];
+ while (this.currentKey == targetKey) {
+ arr.push(this.currentValue);
+ try {
+ this.currentValue = this.iterator.next();
+ } catch (ex) {
+ if (ex !== goog.iter.StopIteration) {
+ throw ex;
+ }
+ break;
+ }
+ this.currentKey = this.keyFunc(this.currentValue);
+ }
+ return arr;
+};
+
+
+/**
+ * Creates an iterator that returns arrays containing elements from the
+ * {@code iterable} grouped by a key value. For iterables with repeated
+ * elements (i.e. sorted according to a particular key function), this function
+ * has a {@code uniq}-like effect. For example, grouping the array:
+ * {@code [A, B, B, C, C, A]} produces
+ * {@code [A, [A]], [B, [B, B]], [C, [C, C]], [A, [A]]}.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.groupby
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to group.
+ * @param {function(VALUE): KEY=} opt_keyFunc Optional function for
+ * determining the key value for each group in the {@code iterable}. Default
+ * is the identity function.
+ * @return {!goog.iter.Iterator<!Array<?>>} A new iterator that returns
+ * arrays of consecutive key and groups.
+ * @template KEY, VALUE
+ */
+goog.iter.groupBy = function(iterable, opt_keyFunc) {
+ return new goog.iter.GroupByIterator_(iterable, opt_keyFunc);
+};
+
+
+/**
+ * Gives an iterator that gives the result of calling the given function
+ * <code>f</code> with the arguments taken from the next element from
+ * <code>iterable</code> (the elements are expected to also be iterables).
+ *
+ * Similar to {@see goog.iter#map} but allows the function to accept multiple
+ * arguments from the iterable.
+ *
+ * @param {!goog.iter.Iterable<!goog.iter.Iterable>} iterable The iterable of
+ * iterables to iterate over.
+ * @param {function(this:THIS,...*):RESULT} f The function to call for every
+ * element. This function takes N+2 arguments, where N represents the
+ * number of items from the next element of the iterable. The two
+ * additional arguments passed to the function are undefined and the
+ * iterator itself. The function should return a new value.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within
+ * {@code f}.
+ * @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the
+ * results of applying the function to each element in the original
+ * iterator.
+ * @template THIS, RESULT
+ */
+goog.iter.starMap = function(iterable, f, opt_obj) {
+ var iterator = goog.iter.toIterator(iterable);
+ var iter = new goog.iter.Iterator();
+
+ iter.next = function() {
+ var args = goog.iter.toArray(iterator.next());
+ return f.apply(opt_obj, goog.array.concat(args, undefined, iterator));
+ };
+
+ return iter;
+};
+
+
+/**
+ * Returns an array of iterators each of which can iterate over the values in
+ * {@code iterable} without advancing the others.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.tee
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to tee.
+ * @param {number=} opt_num The number of iterators to create. Default is 2.
+ * @return {!Array<goog.iter.Iterator<VALUE>>} An array of iterators.
+ * @template VALUE
+ */
+goog.iter.tee = function(iterable, opt_num) {
+ var iterator = goog.iter.toIterator(iterable);
+ var num = goog.isNumber(opt_num) ? opt_num : 2;
+ var buffers =
+ goog.array.map(goog.array.range(num), function() { return []; });
+
+ var addNextIteratorValueToBuffers = function() {
+ var val = iterator.next();
+ goog.array.forEach(buffers, function(buffer) { buffer.push(val); });
+ };
+
+ var createIterator = function(buffer) {
+ // Each tee'd iterator has an associated buffer (initially empty). When a
+ // tee'd iterator's buffer is empty, it calls
+ // addNextIteratorValueToBuffers(), adding the next value to all tee'd
+ // iterators' buffers, and then returns that value. This allows each
+ // iterator to be advanced independently.
+ var iter = new goog.iter.Iterator();
+
+ iter.next = function() {
+ if (goog.array.isEmpty(buffer)) {
+ addNextIteratorValueToBuffers();
+ }
+ goog.asserts.assert(!goog.array.isEmpty(buffer));
+ return buffer.shift();
+ };
+
+ return iter;
+ };
+
+ return goog.array.map(buffers, createIterator);
+};
+
+
+/**
+ * Creates an iterator that returns arrays containing a count and an element
+ * obtained from the given {@code iterable}.
+ * @see http://docs.python.org/2/library/functions.html#enumerate
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to enumerate.
+ * @param {number=} opt_start Optional starting value. Default is 0.
+ * @return {!goog.iter.Iterator<!Array<?>>} A new iterator containing
+ * count/item pairs.
+ * @template VALUE
+ */
+goog.iter.enumerate = function(iterable, opt_start) {
+ return goog.iter.zip(goog.iter.count(opt_start), iterable);
+};
+
+
+/**
+ * Creates an iterator that returns the first {@code limitSize} elements from an
+ * iterable. If this number is greater than the number of elements in the
+ * iterable, all the elements are returned.
+ * @see http://goo.gl/V0sihp Inspired by the limit iterator in Guava.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to limit.
+ * @param {number} limitSize The maximum number of elements to return.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator containing
+ * {@code limitSize} elements.
+ * @template VALUE
+ */
+goog.iter.limit = function(iterable, limitSize) {
+ goog.asserts.assert(goog.math.isInt(limitSize) && limitSize >= 0);
+
+ var iterator = goog.iter.toIterator(iterable);
+
+ var iter = new goog.iter.Iterator();
+ var remaining = limitSize;
+
+ iter.next = function() {
+ if (remaining-- > 0) {
+ return iterator.next();
+ }
+ throw goog.iter.StopIteration;
+ };
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that is advanced {@code count} steps ahead. Consumed
+ * values are silently discarded. If {@code count} is greater than the number
+ * of elements in {@code iterable}, an empty iterator is returned. Subsequent
+ * calls to {@code next()} will throw {@code goog.iter.StopIteration}.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to consume.
+ * @param {number} count The number of elements to consume from the iterator.
+ * @return {!goog.iter.Iterator<VALUE>} An iterator advanced zero or more steps
+ * ahead.
+ * @template VALUE
+ */
+goog.iter.consume = function(iterable, count) {
+ goog.asserts.assert(goog.math.isInt(count) && count >= 0);
+
+ var iterator = goog.iter.toIterator(iterable);
+
+ while (count-- > 0) {
+ goog.iter.nextOrValue(iterator, null);
+ }
+
+ return iterator;
+};
+
+
+/**
+ * Creates an iterator that returns a range of elements from an iterable.
+ * Similar to {@see goog.array#slice} but does not support negative indexes.
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to slice.
+ * @param {number} start The index of the first element to return.
+ * @param {number=} opt_end The index after the last element to return. If
+ * defined, must be greater than or equal to {@code start}.
+ * @return {!goog.iter.Iterator<VALUE>} A new iterator containing a slice of
+ * the original.
+ * @template VALUE
+ */
+goog.iter.slice = function(iterable, start, opt_end) {
+ goog.asserts.assert(goog.math.isInt(start) && start >= 0);
+
+ var iterator = goog.iter.consume(iterable, start);
+
+ if (goog.isNumber(opt_end)) {
+ goog.asserts.assert(goog.math.isInt(opt_end) && opt_end >= start);
+ iterator = goog.iter.limit(iterator, opt_end - start /* limitSize */);
+ }
+
+ return iterator;
+};
+
+
+/**
+ * Checks an array for duplicate elements.
+ * @param {?IArrayLike<VALUE>} arr The array to check for
+ * duplicates.
+ * @return {boolean} True, if the array contains duplicates, false otherwise.
+ * @private
+ * @template VALUE
+ */
+// TODO(user): Consider moving this into goog.array as a public function.
+goog.iter.hasDuplicates_ = function(arr) {
+ var deduped = [];
+ goog.array.removeDuplicates(arr, deduped);
+ return arr.length != deduped.length;
+};
+
+
+/**
+ * Creates an iterator that returns permutations of elements in
+ * {@code iterable}.
+ *
+ * Permutations are obtained by taking the Cartesian product of
+ * {@code opt_length} iterables and filtering out those with repeated
+ * elements. For example, the permutations of {@code [1,2,3]} are
+ * {@code [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]}.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.permutations
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable from which to generate permutations.
+ * @param {number=} opt_length Length of each permutation. If omitted, defaults
+ * to the length of {@code iterable}.
+ * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing the
+ * permutations of {@code iterable}.
+ * @template VALUE
+ */
+goog.iter.permutations = function(iterable, opt_length) {
+ var elements = goog.iter.toArray(iterable);
+ var length = goog.isNumber(opt_length) ? opt_length : elements.length;
+
+ var sets = goog.array.repeat(elements, length);
+ var product = goog.iter.product.apply(undefined, sets);
+
+ return goog.iter.filter(
+ product, function(arr) { return !goog.iter.hasDuplicates_(arr); });
+};
+
+
+/**
+ * Creates an iterator that returns combinations of elements from
+ * {@code iterable}.
+ *
+ * Combinations are obtained by taking the {@see goog.iter#permutations} of
+ * {@code iterable} and filtering those whose elements appear in the order they
+ * are encountered in {@code iterable}. For example, the 3-length combinations
+ * of {@code [0,1,2,3]} are {@code [[0,1,2], [0,1,3], [0,2,3], [1,2,3]]}.
+ * @see http://docs.python.org/2/library/itertools.html#itertools.combinations
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable from which to generate combinations.
+ * @param {number} length The length of each combination.
+ * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing
+ * combinations from the {@code iterable}.
+ * @template VALUE
+ */
+goog.iter.combinations = function(iterable, length) {
+ var elements = goog.iter.toArray(iterable);
+ var indexes = goog.iter.range(elements.length);
+ var indexIterator = goog.iter.permutations(indexes, length);
+ // sortedIndexIterator will now give arrays of with the given length that
+ // indicate what indexes into "elements" should be returned on each iteration.
+ var sortedIndexIterator = goog.iter.filter(
+ indexIterator, function(arr) { return goog.array.isSorted(arr); });
+
+ var iter = new goog.iter.Iterator();
+
+ function getIndexFromElements(index) { return elements[index]; }
+
+ iter.next = function() {
+ return goog.array.map(sortedIndexIterator.next(), getIndexFromElements);
+ };
+
+ return iter;
+};
+
+
+/**
+ * Creates an iterator that returns combinations of elements from
+ * {@code iterable}, with repeated elements possible.
+ *
+ * Combinations are obtained by taking the Cartesian product of {@code length}
+ * iterables and filtering those whose elements appear in the order they are
+ * encountered in {@code iterable}. For example, the 2-length combinations of
+ * {@code [1,2,3]} are {@code [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]}.
+ * @see https://goo.gl/C0yXe4
+ * @see https://goo.gl/djOCsk
+ * @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The
+ * iterable to combine.
+ * @param {number} length The length of each combination.
+ * @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing
+ * combinations from the {@code iterable}.
+ * @template VALUE
+ */
+goog.iter.combinationsWithReplacement = function(iterable, length) {
+ var elements = goog.iter.toArray(iterable);
+ var indexes = goog.array.range(elements.length);
+ var sets = goog.array.repeat(indexes, length);
+ var indexIterator = goog.iter.product.apply(undefined, sets);
+ // sortedIndexIterator will now give arrays of with the given length that
+ // indicate what indexes into "elements" should be returned on each iteration.
+ var sortedIndexIterator = goog.iter.filter(
+ indexIterator, function(arr) { return goog.array.isSorted(arr); });
+
+ var iter = new goog.iter.Iterator();
+
+ function getIndexFromElements(index) { return elements[index]; }
+
+ iter.next = function() {
+ return goog.array.map(
+ /** @type {!Array<number>} */
+ (sortedIndexIterator.next()), getIndexFromElements);
+ };
+
+ return iter;
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Datastructure: Hash Map.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ *
+ * This file contains an implementation of a Map structure. It implements a lot
+ * of the methods used in goog.structs so those functions work on hashes. This
+ * is best suited for complex key types. For simple keys such as numbers and
+ * strings consider using the lighter-weight utilities in goog.object.
+ */
+
+
+goog.provide('goog.structs.Map');
+
+goog.require('goog.iter.Iterator');
+goog.require('goog.iter.StopIteration');
+goog.require('goog.object');
+
+
+
+/**
+ * Class for Hash Map datastructure.
+ * @param {*=} opt_map Map or Object to initialize the map with.
+ * @param {...*} var_args If 2 or more arguments are present then they
+ * will be used as key-value pairs.
+ * @constructor
+ * @template K, V
+ */
+goog.structs.Map = function(opt_map, var_args) {
+
+ /**
+ * Underlying JS object used to implement the map.
+ * @private {!Object}
+ */
+ this.map_ = {};
+
+ /**
+ * An array of keys. This is necessary for two reasons:
+ * 1. Iterating the keys using for (var key in this.map_) allocates an
+ * object for every key in IE which is really bad for IE6 GC perf.
+ * 2. Without a side data structure, we would need to escape all the keys
+ * as that would be the only way we could tell during iteration if the
+ * key was an internal key or a property of the object.
+ *
+ * This array can contain deleted keys so it's necessary to check the map
+ * as well to see if the key is still in the map (this doesn't require a
+ * memory allocation in IE).
+ * @private {!Array<string>}
+ */
+ this.keys_ = [];
+
+ /**
+ * The number of key value pairs in the map.
+ * @private {number}
+ */
+ this.count_ = 0;
+
+ /**
+ * Version used to detect changes while iterating.
+ * @private {number}
+ */
+ this.version_ = 0;
+
+ var argLength = arguments.length;
+
+ if (argLength > 1) {
+ if (argLength % 2) {
+ throw Error('Uneven number of arguments');
+ }
+ for (var i = 0; i < argLength; i += 2) {
+ this.set(arguments[i], arguments[i + 1]);
+ }
+ } else if (opt_map) {
+ this.addAll(/** @type {Object} */ (opt_map));
+ }
+};
+
+
+/**
+ * @return {number} The number of key-value pairs in the map.
+ */
+goog.structs.Map.prototype.getCount = function() {
+ return this.count_;
+};
+
+
+/**
+ * Returns the values of the map.
+ * @return {!Array<V>} The values in the map.
+ */
+goog.structs.Map.prototype.getValues = function() {
+ this.cleanupKeysArray_();
+
+ var rv = [];
+ for (var i = 0; i < this.keys_.length; i++) {
+ var key = this.keys_[i];
+ rv.push(this.map_[key]);
+ }
+ return rv;
+};
+
+
+/**
+ * Returns the keys of the map.
+ * @return {!Array<string>} Array of string values.
+ */
+goog.structs.Map.prototype.getKeys = function() {
+ this.cleanupKeysArray_();
+ return /** @type {!Array<string>} */ (this.keys_.concat());
+};
+
+
+/**
+ * Whether the map contains the given key.
+ * @param {*} key The key to check for.
+ * @return {boolean} Whether the map contains the key.
+ */
+goog.structs.Map.prototype.containsKey = function(key) {
+ return goog.structs.Map.hasKey_(this.map_, key);
+};
+
+
+/**
+ * Whether the map contains the given value. This is O(n).
+ * @param {V} val The value to check for.
+ * @return {boolean} Whether the map contains the value.
+ */
+goog.structs.Map.prototype.containsValue = function(val) {
+ for (var i = 0; i < this.keys_.length; i++) {
+ var key = this.keys_[i];
+ if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) {
+ return true;
+ }
+ }
+ return false;
+};
+
+
+/**
+ * Whether this map is equal to the argument map.
+ * @param {goog.structs.Map} otherMap The map against which to test equality.
+ * @param {function(V, V): boolean=} opt_equalityFn Optional equality function
+ * to test equality of values. If not specified, this will test whether
+ * the values contained in each map are identical objects.
+ * @return {boolean} Whether the maps are equal.
+ */
+goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) {
+ if (this === otherMap) {
+ return true;
+ }
+
+ if (this.count_ != otherMap.getCount()) {
+ return false;
+ }
+
+ var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals;
+
+ this.cleanupKeysArray_();
+ for (var key, i = 0; key = this.keys_[i]; i++) {
+ if (!equalityFn(this.get(key), otherMap.get(key))) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+
+/**
+ * Default equality test for values.
+ * @param {*} a The first value.
+ * @param {*} b The second value.
+ * @return {boolean} Whether a and b reference the same object.
+ */
+goog.structs.Map.defaultEquals = function(a, b) {
+ return a === b;
+};
+
+
+/**
+ * @return {boolean} Whether the map is empty.
+ */
+goog.structs.Map.prototype.isEmpty = function() {
+ return this.count_ == 0;
+};
+
+
+/**
+ * Removes all key-value pairs from the map.
+ */
+goog.structs.Map.prototype.clear = function() {
+ this.map_ = {};
+ this.keys_.length = 0;
+ this.count_ = 0;
+ this.version_ = 0;
+};
+
+
+/**
+ * Removes a key-value pair based on the key. This is O(logN) amortized due to
+ * updating the keys array whenever the count becomes half the size of the keys
+ * in the keys array.
+ * @param {*} key The key to remove.
+ * @return {boolean} Whether object was removed.
+ */
+goog.structs.Map.prototype.remove = function(key) {
+ if (goog.structs.Map.hasKey_(this.map_, key)) {
+ delete this.map_[key];
+ this.count_--;
+ this.version_++;
+
+ // clean up the keys array if the threshold is hit
+ if (this.keys_.length > 2 * this.count_) {
+ this.cleanupKeysArray_();
+ }
+
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * Cleans up the temp keys array by removing entries that are no longer in the
+ * map.
+ * @private
+ */
+goog.structs.Map.prototype.cleanupKeysArray_ = function() {
+ if (this.count_ != this.keys_.length) {
+ // First remove keys that are no longer in the map.
+ var srcIndex = 0;
+ var destIndex = 0;
+ while (srcIndex < this.keys_.length) {
+ var key = this.keys_[srcIndex];
+ if (goog.structs.Map.hasKey_(this.map_, key)) {
+ this.keys_[destIndex++] = key;
+ }
+ srcIndex++;
+ }
+ this.keys_.length = destIndex;
+ }
+
+ if (this.count_ != this.keys_.length) {
+ // If the count still isn't correct, that means we have duplicates. This can
+ // happen when the same key is added and removed multiple times. Now we have
+ // to allocate one extra Object to remove the duplicates. This could have
+ // been done in the first pass, but in the common case, we can avoid
+ // allocating an extra object by only doing this when necessary.
+ var seen = {};
+ var srcIndex = 0;
+ var destIndex = 0;
+ while (srcIndex < this.keys_.length) {
+ var key = this.keys_[srcIndex];
+ if (!(goog.structs.Map.hasKey_(seen, key))) {
+ this.keys_[destIndex++] = key;
+ seen[key] = 1;
+ }
+ srcIndex++;
+ }
+ this.keys_.length = destIndex;
+ }
+};
+
+
+/**
+ * Returns the value for the given key. If the key is not found and the default
+ * value is not given this will return {@code undefined}.
+ * @param {*} key The key to get the value for.
+ * @param {DEFAULT=} opt_val The value to return if no item is found for the
+ * given key, defaults to undefined.
+ * @return {V|DEFAULT} The value for the given key.
+ * @template DEFAULT
+ */
+goog.structs.Map.prototype.get = function(key, opt_val) {
+ if (goog.structs.Map.hasKey_(this.map_, key)) {
+ return this.map_[key];
+ }
+ return opt_val;
+};
+
+
+/**
+ * Adds a key-value pair to the map.
+ * @param {*} key The key.
+ * @param {V} value The value to add.
+ * @return {*} Some subclasses return a value.
+ */
+goog.structs.Map.prototype.set = function(key, value) {
+ if (!(goog.structs.Map.hasKey_(this.map_, key))) {
+ this.count_++;
+ // TODO(johnlenz): This class lies, it claims to return an array of string
+ // keys, but instead returns the original object used.
+ this.keys_.push(/** @type {?} */ (key));
+ // Only change the version if we add a new key.
+ this.version_++;
+ }
+ this.map_[key] = value;
+};
+
+
+/**
+ * Adds multiple key-value pairs from another goog.structs.Map or Object.
+ * @param {Object} map Object containing the data to add.
+ */
+goog.structs.Map.prototype.addAll = function(map) {
+ var keys, values;
+ if (map instanceof goog.structs.Map) {
+ keys = map.getKeys();
+ values = map.getValues();
+ } else {
+ keys = goog.object.getKeys(map);
+ values = goog.object.getValues(map);
+ }
+ // we could use goog.array.forEach here but I don't want to introduce that
+ // dependency just for this.
+ for (var i = 0; i < keys.length; i++) {
+ this.set(keys[i], values[i]);
+ }
+};
+
+
+/**
+ * Calls the given function on each entry in the map.
+ * @param {function(this:T, V, K, goog.structs.Map<K,V>)} f
+ * @param {T=} opt_obj The value of "this" inside f.
+ * @template T
+ */
+goog.structs.Map.prototype.forEach = function(f, opt_obj) {
+ var keys = this.getKeys();
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ var value = this.get(key);
+ f.call(opt_obj, value, key, this);
+ }
+};
+
+
+/**
+ * Clones a map and returns a new map.
+ * @return {!goog.structs.Map} A new map with the same key-value pairs.
+ */
+goog.structs.Map.prototype.clone = function() {
+ return new goog.structs.Map(this);
+};
+
+
+/**
+ * Returns a new map in which all the keys and values are interchanged
+ * (keys become values and values become keys). If multiple keys map to the
+ * same value, the chosen transposed value is implementation-dependent.
+ *
+ * It acts very similarly to {goog.object.transpose(Object)}.
+ *
+ * @return {!goog.structs.Map} The transposed map.
+ */
+goog.structs.Map.prototype.transpose = function() {
+ var transposed = new goog.structs.Map();
+ for (var i = 0; i < this.keys_.length; i++) {
+ var key = this.keys_[i];
+ var value = this.map_[key];
+ transposed.set(value, key);
+ }
+
+ return transposed;
+};
+
+
+/**
+ * @return {!Object} Object representation of the map.
+ */
+goog.structs.Map.prototype.toObject = function() {
+ this.cleanupKeysArray_();
+ var obj = {};
+ for (var i = 0; i < this.keys_.length; i++) {
+ var key = this.keys_[i];
+ obj[key] = this.map_[key];
+ }
+ return obj;
+};
+
+
+/**
+ * Returns an iterator that iterates over the keys in the map. Removal of keys
+ * while iterating might have undesired side effects.
+ * @return {!goog.iter.Iterator} An iterator over the keys in the map.
+ */
+goog.structs.Map.prototype.getKeyIterator = function() {
+ return this.__iterator__(true);
+};
+
+
+/**
+ * Returns an iterator that iterates over the values in the map. Removal of
+ * keys while iterating might have undesired side effects.
+ * @return {!goog.iter.Iterator} An iterator over the values in the map.
+ */
+goog.structs.Map.prototype.getValueIterator = function() {
+ return this.__iterator__(false);
+};
+
+
+/**
+ * Returns an iterator that iterates over the values or the keys in the map.
+ * This throws an exception if the map was mutated since the iterator was
+ * created.
+ * @param {boolean=} opt_keys True to iterate over the keys. False to iterate
+ * over the values. The default value is false.
+ * @return {!goog.iter.Iterator} An iterator over the values or keys in the map.
+ */
+goog.structs.Map.prototype.__iterator__ = function(opt_keys) {
+ // Clean up keys to minimize the risk of iterating over dead keys.
+ this.cleanupKeysArray_();
+
+ var i = 0;
+ var version = this.version_;
+ var selfObj = this;
+
+ var newIter = new goog.iter.Iterator;
+ newIter.next = function() {
+ if (version != selfObj.version_) {
+ throw Error('The map has changed since the iterator was created');
+ }
+ if (i >= selfObj.keys_.length) {
+ throw goog.iter.StopIteration;
+ }
+ var key = selfObj.keys_[i++];
+ return opt_keys ? key : selfObj.map_[key];
+ };
+ return newIter;
+};
+
+
+/**
+ * Safe way to test for hasOwnProperty. It even allows testing for
+ * 'hasOwnProperty'.
+ * @param {Object} obj The object to test for presence of the given key.
+ * @param {*} key The key to check for.
+ * @return {boolean} Whether the object has the key.
+ * @private
+ */
+goog.structs.Map.hasKey_ = function(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+};
+
+// Copyright 2008 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Simple utilities for dealing with URI strings.
+ *
+ * This is intended to be a lightweight alternative to constructing goog.Uri
+ * objects. Whereas goog.Uri adds several kilobytes to the binary regardless
+ * of how much of its functionality you use, this is designed to be a set of
+ * mostly-independent utilities so that the compiler includes only what is
+ * necessary for the task. Estimated savings of porting is 5k pre-gzip and
+ * 1.5k post-gzip. To ensure the savings remain, future developers should
+ * avoid adding new functionality to existing functions, but instead create
+ * new ones and factor out shared code.
+ *
+ * Many of these utilities have limited functionality, tailored to common
+ * cases. The query parameter utilities assume that the parameter keys are
+ * already encoded, since most keys are compile-time alphanumeric strings. The
+ * query parameter mutation utilities also do not tolerate fragment identifiers.
+ *
+ * By design, these functions can be slower than goog.Uri equivalents.
+ * Repeated calls to some of functions may be quadratic in behavior for IE,
+ * although the effect is somewhat limited given the 2kb limit.
+ *
+ * One advantage of the limited functionality here is that this approach is
+ * less sensitive to differences in URI encodings than goog.Uri, since these
+ * functions operate on strings directly, rather than decoding them and
+ * then re-encoding.
+ *
+ * Uses features of RFC 3986 for parsing/formatting URIs:
+ * http://www.ietf.org/rfc/rfc3986.txt
+ *
+ * @author gboyer@google.com (Garrett Boyer) - The "lightened" design.
+ */
+
+goog.provide('goog.uri.utils');
+goog.provide('goog.uri.utils.ComponentIndex');
+goog.provide('goog.uri.utils.QueryArray');
+goog.provide('goog.uri.utils.QueryValue');
+goog.provide('goog.uri.utils.StandardQueryParam');
+
+goog.require('goog.asserts');
+goog.require('goog.string');
+
+
+/**
+ * Character codes inlined to avoid object allocations due to charCode.
+ * @enum {number}
+ * @private
+ */
+goog.uri.utils.CharCode_ = {
+ AMPERSAND: 38,
+ EQUAL: 61,
+ HASH: 35,
+ QUESTION: 63
+};
+
+
+/**
+ * Builds a URI string from already-encoded parts.
+ *
+ * No encoding is performed. Any component may be omitted as either null or
+ * undefined.
+ *
+ * @param {?string=} opt_scheme The scheme such as 'http'.
+ * @param {?string=} opt_userInfo The user name before the '@'.
+ * @param {?string=} opt_domain The domain such as 'www.google.com', already
+ * URI-encoded.
+ * @param {(string|number|null)=} opt_port The port number.
+ * @param {?string=} opt_path The path, already URI-encoded. If it is not
+ * empty, it must begin with a slash.
+ * @param {?string=} opt_queryData The URI-encoded query data.
+ * @param {?string=} opt_fragment The URI-encoded fragment identifier.
+ * @return {string} The fully combined URI.
+ */
+goog.uri.utils.buildFromEncodedParts = function(
+ opt_scheme, opt_userInfo, opt_domain, opt_port, opt_path, opt_queryData,
+ opt_fragment) {
+ var out = '';
+
+ if (opt_scheme) {
+ out += opt_scheme + ':';
+ }
+
+ if (opt_domain) {
+ out += '//';
+
+ if (opt_userInfo) {
+ out += opt_userInfo + '@';
+ }
+
+ out += opt_domain;
+
+ if (opt_port) {
+ out += ':' + opt_port;
+ }
+ }
+
+ if (opt_path) {
+ out += opt_path;
+ }
+
+ if (opt_queryData) {
+ out += '?' + opt_queryData;
+ }
+
+ if (opt_fragment) {
+ out += '#' + opt_fragment;
+ }
+
+ return out;
+};
+
+
+/**
+ * A regular expression for breaking a URI into its component parts.
+ *
+ * {@link http://www.ietf.org/rfc/rfc3986.txt} says in Appendix B
+ * As the "first-match-wins" algorithm is identical to the "greedy"
+ * disambiguation method used by POSIX regular expressions, it is natural and
+ * commonplace to use a regular expression for parsing the potential five
+ * components of a URI reference.
+ *
+ * The following line is the regular expression for breaking-down a
+ * well-formed URI reference into its components.
+ *
+ * <pre>
+ * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ * 12 3 4 5 6 7 8 9
+ * </pre>
+ *
+ * The numbers in the second line above are only to assist readability; they
+ * indicate the reference points for each subexpression (i.e., each paired
+ * parenthesis). We refer to the value matched for subexpression <n> as $<n>.
+ * For example, matching the above expression to
+ * <pre>
+ * http://www.ics.uci.edu/pub/ietf/uri/#Related
+ * </pre>
+ * results in the following subexpression matches:
+ * <pre>
+ * $1 = http:
+ * $2 = http
+ * $3 = //www.ics.uci.edu
+ * $4 = www.ics.uci.edu
+ * $5 = /pub/ietf/uri/
+ * $6 = <undefined>
+ * $7 = <undefined>
+ * $8 = #Related
+ * $9 = Related
+ * </pre>
+ * where <undefined> indicates that the component is not present, as is the
+ * case for the query component in the above example. Therefore, we can
+ * determine the value of the five components as
+ * <pre>
+ * scheme = $2
+ * authority = $4
+ * path = $5
+ * query = $7
+ * fragment = $9
+ * </pre>
+ *
+ * The regular expression has been modified slightly to expose the
+ * userInfo, domain, and port separately from the authority.
+ * The modified version yields
+ * <pre>
+ * $1 = http scheme
+ * $2 = <undefined> userInfo -\
+ * $3 = www.ics.uci.edu domain | authority
+ * $4 = <undefined> port -/
+ * $5 = /pub/ietf/uri/ path
+ * $6 = <undefined> query without ?
+ * $7 = Related fragment without #
+ * </pre>
+ * @type {!RegExp}
+ * @private
+ */
+goog.uri.utils.splitRe_ = new RegExp(
+ '^' +
+ '(?:' +
+ '([^:/?#.]+)' + // scheme - ignore special characters
+ // used by other URL parts such as :,
+ // ?, /, #, and .
+ ':)?' +
+ '(?://' +
+ '(?:([^/?#]*)@)?' + // userInfo
+ '([^/#?]*?)' + // domain
+ '(?::([0-9]+))?' + // port
+ '(?=[/#?]|$)' + // authority-terminating character
+ ')?' +
+ '([^?#]+)?' + // path
+ '(?:\\?([^#]*))?' + // query
+ '(?:#(.*))?' + // fragment
+ '$');
+
+
+/**
+ * The index of each URI component in the return value of goog.uri.utils.split.
+ * @enum {number}
+ */
+goog.uri.utils.ComponentIndex = {
+ SCHEME: 1,
+ USER_INFO: 2,
+ DOMAIN: 3,
+ PORT: 4,
+ PATH: 5,
+ QUERY_DATA: 6,
+ FRAGMENT: 7
+};
+
+
+/**
+ * Splits a URI into its component parts.
+ *
+ * Each component can be accessed via the component indices; for example:
+ * <pre>
+ * goog.uri.utils.split(someStr)[goog.uri.utils.CompontentIndex.QUERY_DATA];
+ * </pre>
+ *
+ * @param {string} uri The URI string to examine.
+ * @return {!Array<string|undefined>} Each component still URI-encoded.
+ * Each component that is present will contain the encoded value, whereas
+ * components that are not present will be undefined or empty, depending
+ * on the browser's regular expression implementation. Never null, since
+ * arbitrary strings may still look like path names.
+ */
+goog.uri.utils.split = function(uri) {
+ // See @return comment -- never null.
+ return /** @type {!Array<string|undefined>} */ (
+ uri.match(goog.uri.utils.splitRe_));
+};
+
+
+/**
+ * @param {?string} uri A possibly null string.
+ * @param {boolean=} opt_preserveReserved If true, percent-encoding of RFC-3986
+ * reserved characters will not be removed.
+ * @return {?string} The string URI-decoded, or null if uri is null.
+ * @private
+ */
+goog.uri.utils.decodeIfPossible_ = function(uri, opt_preserveReserved) {
+ if (!uri) {
+ return uri;
+ }
+
+ return opt_preserveReserved ? decodeURI(uri) : decodeURIComponent(uri);
+};
+
+
+/**
+ * Gets a URI component by index.
+ *
+ * It is preferred to use the getPathEncoded() variety of functions ahead,
+ * since they are more readable.
+ *
+ * @param {goog.uri.utils.ComponentIndex} componentIndex The component index.
+ * @param {string} uri The URI to examine.
+ * @return {?string} The still-encoded component, or null if the component
+ * is not present.
+ * @private
+ */
+goog.uri.utils.getComponentByIndex_ = function(componentIndex, uri) {
+ // Convert undefined, null, and empty string into null.
+ return goog.uri.utils.split(uri)[componentIndex] || null;
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The protocol or scheme, or null if none. Does not
+ * include trailing colons or slashes.
+ */
+goog.uri.utils.getScheme = function(uri) {
+ return goog.uri.utils.getComponentByIndex_(
+ goog.uri.utils.ComponentIndex.SCHEME, uri);
+};
+
+
+/**
+ * Gets the effective scheme for the URL. If the URL is relative then the
+ * scheme is derived from the page's location.
+ * @param {string} uri The URI to examine.
+ * @return {string} The protocol or scheme, always lower case.
+ */
+goog.uri.utils.getEffectiveScheme = function(uri) {
+ var scheme = goog.uri.utils.getScheme(uri);
+ if (!scheme && goog.global.self && goog.global.self.location) {
+ var protocol = goog.global.self.location.protocol;
+ scheme = protocol.substr(0, protocol.length - 1);
+ }
+ // NOTE: When called from a web worker in Firefox 3.5, location maybe null.
+ // All other browsers with web workers support self.location from the worker.
+ return scheme ? scheme.toLowerCase() : '';
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The user name still encoded, or null if none.
+ */
+goog.uri.utils.getUserInfoEncoded = function(uri) {
+ return goog.uri.utils.getComponentByIndex_(
+ goog.uri.utils.ComponentIndex.USER_INFO, uri);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The decoded user info, or null if none.
+ */
+goog.uri.utils.getUserInfo = function(uri) {
+ return goog.uri.utils.decodeIfPossible_(
+ goog.uri.utils.getUserInfoEncoded(uri));
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The domain name still encoded, or null if none.
+ */
+goog.uri.utils.getDomainEncoded = function(uri) {
+ return goog.uri.utils.getComponentByIndex_(
+ goog.uri.utils.ComponentIndex.DOMAIN, uri);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The decoded domain, or null if none.
+ */
+goog.uri.utils.getDomain = function(uri) {
+ return goog.uri.utils.decodeIfPossible_(
+ goog.uri.utils.getDomainEncoded(uri), true /* opt_preserveReserved */);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?number} The port number, or null if none.
+ */
+goog.uri.utils.getPort = function(uri) {
+ // Coerce to a number. If the result of getComponentByIndex_ is null or
+ // non-numeric, the number coersion yields NaN. This will then return
+ // null for all non-numeric cases (though also zero, which isn't a relevant
+ // port number).
+ return Number(
+ goog.uri.utils.getComponentByIndex_(
+ goog.uri.utils.ComponentIndex.PORT, uri)) ||
+ null;
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The path still encoded, or null if none. Includes the
+ * leading slash, if any.
+ */
+goog.uri.utils.getPathEncoded = function(uri) {
+ return goog.uri.utils.getComponentByIndex_(
+ goog.uri.utils.ComponentIndex.PATH, uri);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The decoded path, or null if none. Includes the leading
+ * slash, if any.
+ */
+goog.uri.utils.getPath = function(uri) {
+ return goog.uri.utils.decodeIfPossible_(
+ goog.uri.utils.getPathEncoded(uri), true /* opt_preserveReserved */);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The query data still encoded, or null if none. Does not
+ * include the question mark itself.
+ */
+goog.uri.utils.getQueryData = function(uri) {
+ return goog.uri.utils.getComponentByIndex_(
+ goog.uri.utils.ComponentIndex.QUERY_DATA, uri);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The fragment identifier, or null if none. Does not
+ * include the hash mark itself.
+ */
+goog.uri.utils.getFragmentEncoded = function(uri) {
+ // The hash mark may not appear in any other part of the URL.
+ var hashIndex = uri.indexOf('#');
+ return hashIndex < 0 ? null : uri.substr(hashIndex + 1);
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @param {?string} fragment The encoded fragment identifier, or null if none.
+ * Does not include the hash mark itself.
+ * @return {string} The URI with the fragment set.
+ */
+goog.uri.utils.setFragmentEncoded = function(uri, fragment) {
+ return goog.uri.utils.removeFragment(uri) + (fragment ? '#' + fragment : '');
+};
+
+
+/**
+ * @param {string} uri The URI to examine.
+ * @return {?string} The decoded fragment identifier, or null if none. Does
+ * not include the hash mark.
+ */
+goog.uri.utils.getFragment = function(uri) {
+ return goog.uri.utils.decodeIfPossible_(
+ goog.uri.utils.getFragmentEncoded(uri));
+};
+
+
+/**
+ * Extracts everything up to the port of the URI.
+ * @param {string} uri The URI string.
+ * @return {string} Everything up to and including the port.
+ */
+goog.uri.utils.getHost = function(uri) {
+ var pieces = goog.uri.utils.split(uri);
+ return goog.uri.utils.buildFromEncodedParts(
+ pieces[goog.uri.utils.ComponentIndex.SCHEME],
+ pieces[goog.uri.utils.ComponentIndex.USER_INFO],
+ pieces[goog.uri.utils.ComponentIndex.DOMAIN],
+ pieces[goog.uri.utils.ComponentIndex.PORT]);
+};
+
+
+/**
+ * Extracts the path of the URL and everything after.
+ * @param {string} uri The URI string.
+ * @return {string} The URI, starting at the path and including the query
+ * parameters and fragment identifier.
+ */
+goog.uri.utils.getPathAndAfter = function(uri) {
+ var pieces = goog.uri.utils.split(uri);
+ return goog.uri.utils.buildFromEncodedParts(
+ null, null, null, null, pieces[goog.uri.utils.ComponentIndex.PATH],
+ pieces[goog.uri.utils.ComponentIndex.QUERY_DATA],
+ pieces[goog.uri.utils.ComponentIndex.FRAGMENT]);
+};
+
+
+/**
+ * Gets the URI with the fragment identifier removed.
+ * @param {string} uri The URI to examine.
+ * @return {string} Everything preceding the hash mark.
+ */
+goog.uri.utils.removeFragment = function(uri) {
+ // The hash mark may not appear in any other part of the URL.
+ var hashIndex = uri.indexOf('#');
+ return hashIndex < 0 ? uri : uri.substr(0, hashIndex);
+};
+
+
+/**
+ * Ensures that two URI's have the exact same domain, scheme, and port.
+ *
+ * Unlike the version in goog.Uri, this checks protocol, and therefore is
+ * suitable for checking against the browser's same-origin policy.
+ *
+ * @param {string} uri1 The first URI.
+ * @param {string} uri2 The second URI.
+ * @return {boolean} Whether they have the same scheme, domain and port.
+ */
+goog.uri.utils.haveSameDomain = function(uri1, uri2) {
+ var pieces1 = goog.uri.utils.split(uri1);
+ var pieces2 = goog.uri.utils.split(uri2);
+ return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] ==
+ pieces2[goog.uri.utils.ComponentIndex.DOMAIN] &&
+ pieces1[goog.uri.utils.ComponentIndex.SCHEME] ==
+ pieces2[goog.uri.utils.ComponentIndex.SCHEME] &&
+ pieces1[goog.uri.utils.ComponentIndex.PORT] ==
+ pieces2[goog.uri.utils.ComponentIndex.PORT];
+};
+
+
+/**
+ * Asserts that there are no fragment or query identifiers, only in uncompiled
+ * mode.
+ * @param {string} uri The URI to examine.
+ * @private
+ */
+goog.uri.utils.assertNoFragmentsOrQueries_ = function(uri) {
+ // NOTE: would use goog.asserts here, but jscompiler doesn't know that
+ // indexOf has no side effects.
+ if (goog.DEBUG && (uri.indexOf('#') >= 0 || uri.indexOf('?') >= 0)) {
+ throw Error(
+ 'goog.uri.utils: Fragment or query identifiers are not ' +
+ 'supported: [' + uri + ']');
+ }
+};
+
+
+/**
+ * Supported query parameter values by the parameter serializing utilities.
+ *
+ * If a value is null or undefined, the key-value pair is skipped, as an easy
+ * way to omit parameters conditionally. Non-array parameters are converted
+ * to a string and URI encoded. Array values are expanded into multiple
+ * &key=value pairs, with each element stringized and URI-encoded.
+ *
+ * @typedef {*}
+ */
+goog.uri.utils.QueryValue;
+
+
+/**
+ * An array representing a set of query parameters with alternating keys
+ * and values.
+ *
+ * Keys are assumed to be URI encoded already and live at even indices. See
+ * goog.uri.utils.QueryValue for details on how parameter values are encoded.
+ *
+ * Example:
+ * <pre>
+ * var data = [
+ * // Simple param: ?name=BobBarker
+ * 'name', 'BobBarker',
+ * // Conditional param -- may be omitted entirely.
+ * 'specialDietaryNeeds', hasDietaryNeeds() ? getDietaryNeeds() : null,
+ * // Multi-valued param: &house=LosAngeles&house=NewYork&house=null
+ * 'house', ['LosAngeles', 'NewYork', null]
+ * ];
+ * </pre>
+ *
+ * @typedef {!Array<string|goog.uri.utils.QueryValue>}
+ */
+goog.uri.utils.QueryArray;
+
+
+/**
+ * Parses encoded query parameters and calls callback function for every
+ * parameter found in the string.
+ *
+ * Missing value of parameter (e.g. “…&key&…”) is treated as if the value was an
+ * empty string. Keys may be empty strings (e.g. “…&=value&…”) which also means
+ * that “…&=&…” and “…&&…” will result in an empty key and value.
+ *
+ * @param {string} encodedQuery Encoded query string excluding question mark at
+ * the beginning.
+ * @param {function(string, string)} callback Function called for every
+ * parameter found in query string. The first argument (name) will not be
+ * urldecoded (so the function is consistent with buildQueryData), but the
+ * second will. If the parameter has no value (i.e. “=” was not present)
+ * the second argument (value) will be an empty string.
+ */
+goog.uri.utils.parseQueryData = function(encodedQuery, callback) {
+ if (!encodedQuery) {
+ return;
+ }
+ var pairs = encodedQuery.split('&');
+ for (var i = 0; i < pairs.length; i++) {
+ var indexOfEquals = pairs[i].indexOf('=');
+ var name = null;
+ var value = null;
+ if (indexOfEquals >= 0) {
+ name = pairs[i].substring(0, indexOfEquals);
+ value = pairs[i].substring(indexOfEquals + 1);
+ } else {
+ name = pairs[i];
+ }
+ callback(name, value ? goog.string.urlDecode(value) : '');
+ }
+};
+
+
+/**
+ * Appends a URI and query data in a string buffer with special preconditions.
+ *
+ * Internal implementation utility, performing very few object allocations.
+ *
+ * @param {!Array<string|undefined>} buffer A string buffer. The first element
+ * must be the base URI, and may have a fragment identifier. If the array
+ * contains more than one element, the second element must be an ampersand,
+ * and may be overwritten, depending on the base URI. Undefined elements
+ * are treated as empty-string.
+ * @return {string} The concatenated URI and query data.
+ * @private
+ */
+goog.uri.utils.appendQueryData_ = function(buffer) {
+ if (buffer[1]) {
+ // At least one query parameter was added. We need to check the
+ // punctuation mark, which is currently an ampersand, and also make sure
+ // there aren't any interfering fragment identifiers.
+ var baseUri = /** @type {string} */ (buffer[0]);
+ var hashIndex = baseUri.indexOf('#');
+ if (hashIndex >= 0) {
+ // Move the fragment off the base part of the URI into the end.
+ buffer.push(baseUri.substr(hashIndex));
+ buffer[0] = baseUri = baseUri.substr(0, hashIndex);
+ }
+ var questionIndex = baseUri.indexOf('?');
+ if (questionIndex < 0) {
+ // No question mark, so we need a question mark instead of an ampersand.
+ buffer[1] = '?';
+ } else if (questionIndex == baseUri.length - 1) {
+ // Question mark is the very last character of the existing URI, so don't
+ // append an additional delimiter.
+ buffer[1] = undefined;
+ }
+ }
+
+ return buffer.join('');
+};
+
+
+/**
+ * Appends key=value pairs to an array, supporting multi-valued objects.
+ * @param {string} key The key prefix.
+ * @param {goog.uri.utils.QueryValue} value The value to serialize.
+ * @param {!Array<string>} pairs The array to which the 'key=value' strings
+ * should be appended.
+ * @private
+ */
+goog.uri.utils.appendKeyValuePairs_ = function(key, value, pairs) {
+ if (goog.isArray(value)) {
+ // Convince the compiler it's an array.
+ goog.asserts.assertArray(value);
+ for (var j = 0; j < value.length; j++) {
+ // Convert to string explicitly, to short circuit the null and array
+ // logic in this function -- this ensures that null and undefined get
+ // written as literal 'null' and 'undefined', and arrays don't get
+ // expanded out but instead encoded in the default way.
+ goog.uri.utils.appendKeyValuePairs_(key, String(value[j]), pairs);
+ }
+ } else if (value != null) {
+ // Skip a top-level null or undefined entirely.
+ pairs.push(
+ '&', key,
+ // Check for empty string. Zero gets encoded into the url as literal
+ // strings. For empty string, skip the equal sign, to be consistent
+ // with UriBuilder.java.
+ value === '' ? '' : '=', goog.string.urlEncode(value));
+ }
+};
+
+
+/**
+ * Builds a buffer of query data from a sequence of alternating keys and values.
+ *
+ * @param {!Array<string|undefined>} buffer A string buffer to append to. The
+ * first element appended will be an '&', and may be replaced by the caller.
+ * @param {!goog.uri.utils.QueryArray|!Arguments} keysAndValues An array with
+ * alternating keys and values -- see the typedef.
+ * @param {number=} opt_startIndex A start offset into the arary, defaults to 0.
+ * @return {!Array<string|undefined>} The buffer argument.
+ * @private
+ */
+goog.uri.utils.buildQueryDataBuffer_ = function(
+ buffer, keysAndValues, opt_startIndex) {
+ goog.asserts.assert(
+ Math.max(keysAndValues.length - (opt_startIndex || 0), 0) % 2 == 0,
+ 'goog.uri.utils: Key/value lists must be even in length.');
+
+ for (var i = opt_startIndex || 0; i < keysAndValues.length; i += 2) {
+ goog.uri.utils.appendKeyValuePairs_(
+ keysAndValues[i], keysAndValues[i + 1], buffer);
+ }
+
+ return buffer;
+};
+
+
+/**
+ * Builds a query data string from a sequence of alternating keys and values.
+ * Currently generates "&key&" for empty args.
+ *
+ * @param {goog.uri.utils.QueryArray} keysAndValues Alternating keys and
+ * values. See the typedef.
+ * @param {number=} opt_startIndex A start offset into the arary, defaults to 0.
+ * @return {string} The encoded query string, in the form 'a=1&b=2'.
+ */
+goog.uri.utils.buildQueryData = function(keysAndValues, opt_startIndex) {
+ var buffer =
+ goog.uri.utils.buildQueryDataBuffer_([], keysAndValues, opt_startIndex);
+ buffer[0] = ''; // Remove the leading ampersand.
+ return buffer.join('');
+};
+
+
+/**
+ * Builds a buffer of query data from a map.
+ *
+ * @param {!Array<string|undefined>} buffer A string buffer to append to. The
+ * first element appended will be an '&', and may be replaced by the caller.
+ * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys
+ * are URI-encoded parameter keys, and the values conform to the contract
+ * specified in the goog.uri.utils.QueryValue typedef.
+ * @return {!Array<string|undefined>} The buffer argument.
+ * @private
+ */
+goog.uri.utils.buildQueryDataBufferFromMap_ = function(buffer, map) {
+ for (var key in map) {
+ goog.uri.utils.appendKeyValuePairs_(key, map[key], buffer);
+ }
+
+ return buffer;
+};
+
+
+/**
+ * Builds a query data string from a map.
+ * Currently generates "&key&" for empty args.
+ *
+ * @param {!Object<string, goog.uri.utils.QueryValue>} map An object where keys
+ * are URI-encoded parameter keys, and the values are arbitrary types
+ * or arrays. Keys with a null value are dropped.
+ * @return {string} The encoded query string, in the form 'a=1&b=2'.
+ */
+goog.uri.utils.buildQueryDataFromMap = function(map) {
+ var buffer = goog.uri.utils.buildQueryDataBufferFromMap_([], map);
+ buffer[0] = '';
+ return buffer.join('');
+};
+
+
+/**
+ * Appends URI parameters to an existing URI.
+ *
+ * The variable arguments may contain alternating keys and values. Keys are
+ * assumed to be already URI encoded. The values should not be URI-encoded,
+ * and will instead be encoded by this function.
+ * <pre>
+ * appendParams('http://www.foo.com?existing=true',
+ * 'key1', 'value1',
+ * 'key2', 'value?willBeEncoded',
+ * 'key3', ['valueA', 'valueB', 'valueC'],
+ * 'key4', null);
+ * result: 'http://www.foo.com?existing=true&' +
+ * 'key1=value1&' +
+ * 'key2=value%3FwillBeEncoded&' +
+ * 'key3=valueA&key3=valueB&key3=valueC'
+ * </pre>
+ *
+ * A single call to this function will not exhibit quadratic behavior in IE,
+ * whereas multiple repeated calls may, although the effect is limited by
+ * fact that URL's generally can't exceed 2kb.
+ *
+ * @param {string} uri The original URI, which may already have query data.
+ * @param {...(goog.uri.utils.QueryArray|string|goog.uri.utils.QueryValue)}
+ * var_args
+ * An array or argument list conforming to goog.uri.utils.QueryArray.
+ * @return {string} The URI with all query parameters added.
+ */
+goog.uri.utils.appendParams = function(uri, var_args) {
+ return goog.uri.utils.appendQueryData_(
+ arguments.length == 2 ?
+ goog.uri.utils.buildQueryDataBuffer_([uri], arguments[1], 0) :
+ goog.uri.utils.buildQueryDataBuffer_([uri], arguments, 1));
+};
+
+
+/**
+ * Appends query parameters from a map.
+ *
+ * @param {string} uri The original URI, which may already have query data.
+ * @param {!Object<goog.uri.utils.QueryValue>} map An object where keys are
+ * URI-encoded parameter keys, and the values are arbitrary types or arrays.
+ * Keys with a null value are dropped.
+ * @return {string} The new parameters.
+ */
+goog.uri.utils.appendParamsFromMap = function(uri, map) {
+ return goog.uri.utils.appendQueryData_(
+ goog.uri.utils.buildQueryDataBufferFromMap_([uri], map));
+};
+
+
+/**
+ * Appends a single URI parameter.
+ *
+ * Repeated calls to this can exhibit quadratic behavior in IE6 due to the
+ * way string append works, though it should be limited given the 2kb limit.
+ *
+ * @param {string} uri The original URI, which may already have query data.
+ * @param {string} key The key, which must already be URI encoded.
+ * @param {*=} opt_value The value, which will be stringized and encoded
+ * (assumed not already to be encoded). If omitted, undefined, or null, the
+ * key will be added as a valueless parameter.
+ * @return {string} The URI with the query parameter added.
+ */
+goog.uri.utils.appendParam = function(uri, key, opt_value) {
+ var paramArr = [uri, '&', key];
+ if (goog.isDefAndNotNull(opt_value)) {
+ paramArr.push('=', goog.string.urlEncode(opt_value));
+ }
+ return goog.uri.utils.appendQueryData_(paramArr);
+};
+
+
+/**
+ * Finds the next instance of a query parameter with the specified name.
+ *
+ * Does not instantiate any objects.
+ *
+ * @param {string} uri The URI to search. May contain a fragment identifier
+ * if opt_hashIndex is specified.
+ * @param {number} startIndex The index to begin searching for the key at. A
+ * match may be found even if this is one character after the ampersand.
+ * @param {string} keyEncoded The URI-encoded key.
+ * @param {number} hashOrEndIndex Index to stop looking at. If a hash
+ * mark is present, it should be its index, otherwise it should be the
+ * length of the string.
+ * @return {number} The position of the first character in the key's name,
+ * immediately after either a question mark or a dot.
+ * @private
+ */
+goog.uri.utils.findParam_ = function(
+ uri, startIndex, keyEncoded, hashOrEndIndex) {
+ var index = startIndex;
+ var keyLength = keyEncoded.length;
+
+ // Search for the key itself and post-filter for surronuding punctuation,
+ // rather than expensively building a regexp.
+ while ((index = uri.indexOf(keyEncoded, index)) >= 0 &&
+ index < hashOrEndIndex) {
+ var precedingChar = uri.charCodeAt(index - 1);
+ // Ensure that the preceding character is '&' or '?'.
+ if (precedingChar == goog.uri.utils.CharCode_.AMPERSAND ||
+ precedingChar == goog.uri.utils.CharCode_.QUESTION) {
+ // Ensure the following character is '&', '=', '#', or NaN
+ // (end of string).
+ var followingChar = uri.charCodeAt(index + keyLength);
+ if (!followingChar || followingChar == goog.uri.utils.CharCode_.EQUAL ||
+ followingChar == goog.uri.utils.CharCode_.AMPERSAND ||
+ followingChar == goog.uri.utils.CharCode_.HASH) {
+ return index;
+ }
+ }
+ index += keyLength + 1;
+ }
+
+ return -1;
+};
+
+
+/**
+ * Regular expression for finding a hash mark or end of string.
+ * @type {RegExp}
+ * @private
+ */
+goog.uri.utils.hashOrEndRe_ = /#|$/;
+
+
+/**
+ * Determines if the URI contains a specific key.
+ *
+ * Performs no object instantiations.
+ *
+ * @param {string} uri The URI to process. May contain a fragment
+ * identifier.
+ * @param {string} keyEncoded The URI-encoded key. Case-sensitive.
+ * @return {boolean} Whether the key is present.
+ */
+goog.uri.utils.hasParam = function(uri, keyEncoded) {
+ return goog.uri.utils.findParam_(
+ uri, 0, keyEncoded, uri.search(goog.uri.utils.hashOrEndRe_)) >= 0;
+};
+
+
+/**
+ * Gets the first value of a query parameter.
+ * @param {string} uri The URI to process. May contain a fragment.
+ * @param {string} keyEncoded The URI-encoded key. Case-sensitive.
+ * @return {?string} The first value of the parameter (URI-decoded), or null
+ * if the parameter is not found.
+ */
+goog.uri.utils.getParamValue = function(uri, keyEncoded) {
+ var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_);
+ var foundIndex =
+ goog.uri.utils.findParam_(uri, 0, keyEncoded, hashOrEndIndex);
+
+ if (foundIndex < 0) {
+ return null;
+ } else {
+ var endPosition = uri.indexOf('&', foundIndex);
+ if (endPosition < 0 || endPosition > hashOrEndIndex) {
+ endPosition = hashOrEndIndex;
+ }
+ // Progress forth to the end of the "key=" or "key&" substring.
+ foundIndex += keyEncoded.length + 1;
+ // Use substr, because it (unlike substring) will return empty string
+ // if foundIndex > endPosition.
+ return goog.string.urlDecode(
+ uri.substr(foundIndex, endPosition - foundIndex));
+ }
+};
+
+
+/**
+ * Gets all values of a query parameter.
+ * @param {string} uri The URI to process. May contain a fragment.
+ * @param {string} keyEncoded The URI-encoded key. Case-sensitive.
+ * @return {!Array<string>} All URI-decoded values with the given key.
+ * If the key is not found, this will have length 0, but never be null.
+ */
+goog.uri.utils.getParamValues = function(uri, keyEncoded) {
+ var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_);
+ var position = 0;
+ var foundIndex;
+ var result = [];
+
+ while ((foundIndex = goog.uri.utils.findParam_(
+ uri, position, keyEncoded, hashOrEndIndex)) >= 0) {
+ // Find where this parameter ends, either the '&' or the end of the
+ // query parameters.
+ position = uri.indexOf('&', foundIndex);
+ if (position < 0 || position > hashOrEndIndex) {
+ position = hashOrEndIndex;
+ }
+
+ // Progress forth to the end of the "key=" or "key&" substring.
+ foundIndex += keyEncoded.length + 1;
+ // Use substr, because it (unlike substring) will return empty string
+ // if foundIndex > position.
+ result.push(
+ goog.string.urlDecode(uri.substr(foundIndex, position - foundIndex)));
+ }
+
+ return result;
+};
+
+
+/**
+ * Regexp to find trailing question marks and ampersands.
+ * @type {RegExp}
+ * @private
+ */
+goog.uri.utils.trailingQueryPunctuationRe_ = /[?&]($|#)/;
+
+
+/**
+ * Removes all instances of a query parameter.
+ * @param {string} uri The URI to process. Must not contain a fragment.
+ * @param {string} keyEncoded The URI-encoded key.
+ * @return {string} The URI with all instances of the parameter removed.
+ */
+goog.uri.utils.removeParam = function(uri, keyEncoded) {
+ var hashOrEndIndex = uri.search(goog.uri.utils.hashOrEndRe_);
+ var position = 0;
+ var foundIndex;
+ var buffer = [];
+
+ // Look for a query parameter.
+ while ((foundIndex = goog.uri.utils.findParam_(
+ uri, position, keyEncoded, hashOrEndIndex)) >= 0) {
+ // Get the portion of the query string up to, but not including, the ?
+ // or & starting the parameter.
+ buffer.push(uri.substring(position, foundIndex));
+ // Progress to immediately after the '&'. If not found, go to the end.
+ // Avoid including the hash mark.
+ position = Math.min(
+ (uri.indexOf('&', foundIndex) + 1) || hashOrEndIndex, hashOrEndIndex);
+ }
+
+ // Append everything that is remaining.
+ buffer.push(uri.substr(position));
+
+ // Join the buffer, and remove trailing punctuation that remains.
+ return buffer.join('').replace(
+ goog.uri.utils.trailingQueryPunctuationRe_, '$1');
+};
+
+
+/**
+ * Replaces all existing definitions of a parameter with a single definition.
+ *
+ * Repeated calls to this can exhibit quadratic behavior due to the need to
+ * find existing instances and reconstruct the string, though it should be
+ * limited given the 2kb limit. Consider using appendParams to append multiple
+ * parameters in bulk.
+ *
+ * @param {string} uri The original URI, which may already have query data.
+ * @param {string} keyEncoded The key, which must already be URI encoded.
+ * @param {*} value The value, which will be stringized and encoded (assumed
+ * not already to be encoded).
+ * @return {string} The URI with the query parameter added.
+ */
+goog.uri.utils.setParam = function(uri, keyEncoded, value) {
+ return goog.uri.utils.appendParam(
+ goog.uri.utils.removeParam(uri, keyEncoded), keyEncoded, value);
+};
+
+
+/**
+ * Generates a URI path using a given URI and a path with checks to
+ * prevent consecutive "//". The baseUri passed in must not contain
+ * query or fragment identifiers. The path to append may not contain query or
+ * fragment identifiers.
+ *
+ * @param {string} baseUri URI to use as the base.
+ * @param {string} path Path to append.
+ * @return {string} Updated URI.
+ */
+goog.uri.utils.appendPath = function(baseUri, path) {
+ goog.uri.utils.assertNoFragmentsOrQueries_(baseUri);
+
+ // Remove any trailing '/'
+ if (goog.string.endsWith(baseUri, '/')) {
+ baseUri = baseUri.substr(0, baseUri.length - 1);
+ }
+ // Remove any leading '/'
+ if (goog.string.startsWith(path, '/')) {
+ path = path.substr(1);
+ }
+ return goog.string.buildString(baseUri, '/', path);
+};
+
+
+/**
+ * Replaces the path.
+ * @param {string} uri URI to use as the base.
+ * @param {string} path New path.
+ * @return {string} Updated URI.
+ */
+goog.uri.utils.setPath = function(uri, path) {
+ // Add any missing '/'.
+ if (!goog.string.startsWith(path, '/')) {
+ path = '/' + path;
+ }
+ var parts = goog.uri.utils.split(uri);
+ return goog.uri.utils.buildFromEncodedParts(
+ parts[goog.uri.utils.ComponentIndex.SCHEME],
+ parts[goog.uri.utils.ComponentIndex.USER_INFO],
+ parts[goog.uri.utils.ComponentIndex.DOMAIN],
+ parts[goog.uri.utils.ComponentIndex.PORT], path,
+ parts[goog.uri.utils.ComponentIndex.QUERY_DATA],
+ parts[goog.uri.utils.ComponentIndex.FRAGMENT]);
+};
+
+
+/**
+ * Standard supported query parameters.
+ * @enum {string}
+ */
+goog.uri.utils.StandardQueryParam = {
+
+ /** Unused parameter for unique-ifying. */
+ RANDOM: 'zx'
+};
+
+
+/**
+ * Sets the zx parameter of a URI to a random value.
+ * @param {string} uri Any URI.
+ * @return {string} That URI with the "zx" parameter added or replaced to
+ * contain a random string.
+ */
+goog.uri.utils.makeUnique = function(uri) {
+ return goog.uri.utils.setParam(
+ uri, goog.uri.utils.StandardQueryParam.RANDOM,
+ goog.string.getRandomString());
+};
+
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @fileoverview Class for parsing and formatting URIs.
+ *
+ * Use goog.Uri(string) to parse a URI string. Use goog.Uri.create(...) to
+ * create a new instance of the goog.Uri object from Uri parts.
+ *
+ * e.g: <code>var myUri = new goog.Uri(window.location);</code>
+ *
+ * Implements RFC 3986 for parsing/formatting URIs.
+ * http://www.ietf.org/rfc/rfc3986.txt
+ *
+ * Some changes have been made to the interface (more like .NETs), though the
+ * internal representation is now of un-encoded parts, this will change the
+ * behavior slightly.
+ *
+ */
+
+goog.provide('goog.Uri');
+goog.provide('goog.Uri.QueryData');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.string');
+goog.require('goog.structs');
+goog.require('goog.structs.Map');
+goog.require('goog.uri.utils');
+goog.require('goog.uri.utils.ComponentIndex');
+goog.require('goog.uri.utils.StandardQueryParam');
+
+
+
+/**
+ * This class contains setters and getters for the parts of the URI.
+ * The <code>getXyz</code>/<code>setXyz</code> methods return the decoded part
+ * -- so<code>goog.Uri.parse('/foo%20bar').getPath()</code> will return the
+ * decoded path, <code>/foo bar</code>.
+ *
+ * Reserved characters (see RFC 3986 section 2.2) can be present in
+ * their percent-encoded form in scheme, domain, and path URI components and
+ * will not be auto-decoded. For example:
+ * <code>goog.Uri.parse('rel%61tive/path%2fto/resource').getPath()</code> will
+ * return <code>relative/path%2fto/resource</code>.
+ *
+ * The constructor accepts an optional unparsed, raw URI string. The parser
+ * is relaxed, so special characters that aren't escaped but don't cause
+ * ambiguities will not cause parse failures.
+ *
+ * All setters return <code>this</code> and so may be chained, a la
+ * <code>goog.Uri.parse('/foo').setFragment('part').toString()</code>.
+ *
+ * @param {*=} opt_uri Optional string URI to parse
+ * (use goog.Uri.create() to create a URI from parts), or if
+ * a goog.Uri is passed, a clone is created.
+ * @param {boolean=} opt_ignoreCase If true, #getParameterValue will ignore
+ * the case of the parameter name.
+ *
+ * @throws URIError If opt_uri is provided and URI is malformed (that is,
+ * if decodeURIComponent fails on any of the URI components).
+ * @constructor
+ * @struct
+ */
+goog.Uri = function(opt_uri, opt_ignoreCase) {
+ /**
+ * Scheme such as "http".
+ * @private {string}
+ */
+ this.scheme_ = '';
+
+ /**
+ * User credentials in the form "username:password".
+ * @private {string}
+ */
+ this.userInfo_ = '';
+
+ /**
+ * Domain part, e.g. "www.google.com".
+ * @private {string}
+ */
+ this.domain_ = '';
+
+ /**
+ * Port, e.g. 8080.
+ * @private {?number}
+ */
+ this.port_ = null;
+
+ /**
+ * Path, e.g. "/tests/img.png".
+ * @private {string}
+ */
+ this.path_ = '';
+
+ /**
+ * The fragment without the #.
+ * @private {string}
+ */
+ this.fragment_ = '';
+
+ /**
+ * Whether or not this Uri should be treated as Read Only.
+ * @private {boolean}
+ */
+ this.isReadOnly_ = false;
+
+ /**
+ * Whether or not to ignore case when comparing query params.
+ * @private {boolean}
+ */
+ this.ignoreCase_ = false;
+
+ /**
+ * Object representing query data.
+ * @private {!goog.Uri.QueryData}
+ */
+ this.queryData_;
+
+ // Parse in the uri string
+ var m;
+ if (opt_uri instanceof goog.Uri) {
+ this.ignoreCase_ =
+ goog.isDef(opt_ignoreCase) ? opt_ignoreCase : opt_uri.getIgnoreCase();
+ this.setScheme(opt_uri.getScheme());
+ this.setUserInfo(opt_uri.getUserInfo());
+ this.setDomain(opt_uri.getDomain());
+ this.setPort(opt_uri.getPort());
+ this.setPath(opt_uri.getPath());
+ this.setQueryData(opt_uri.getQueryData().clone());
+ this.setFragment(opt_uri.getFragment());
+ } else if (opt_uri && (m = goog.uri.utils.split(String(opt_uri)))) {
+ this.ignoreCase_ = !!opt_ignoreCase;
+
+ // Set the parts -- decoding as we do so.
+ // COMPATIBILITY NOTE - In IE, unmatched fields may be empty strings,
+ // whereas in other browsers they will be undefined.
+ this.setScheme(m[goog.uri.utils.ComponentIndex.SCHEME] || '', true);
+ this.setUserInfo(m[goog.uri.utils.ComponentIndex.USER_INFO] || '', true);
+ this.setDomain(m[goog.uri.utils.ComponentIndex.DOMAIN] || '', true);
+ this.setPort(m[goog.uri.utils.ComponentIndex.PORT]);
+ this.setPath(m[goog.uri.utils.ComponentIndex.PATH] || '', true);
+ this.setQueryData(m[goog.uri.utils.ComponentIndex.QUERY_DATA] || '', true);
+ this.setFragment(m[goog.uri.utils.ComponentIndex.FRAGMENT] || '', true);
+
+ } else {
+ this.ignoreCase_ = !!opt_ignoreCase;
+ this.queryData_ = new goog.Uri.QueryData(null, null, this.ignoreCase_);
+ }
+};
+
+
+/**
+ * If true, we preserve the type of query parameters set programmatically.
+ *
+ * This means that if you set a parameter to a boolean, and then call
+ * getParameterValue, you will get a boolean back.
+ *
+ * If false, we will coerce parameters to strings, just as they would
+ * appear in real URIs.
+ *
+ * TODO(nicksantos): Remove this once people have time to fix all tests.
+ *
+ * @type {boolean}
+ */
+goog.Uri.preserveParameterTypesCompatibilityFlag = false;
+
+
+/**
+ * Parameter name added to stop caching.
+ * @type {string}
+ */
+goog.Uri.RANDOM_PARAM = goog.uri.utils.StandardQueryParam.RANDOM;
+
+
+/**
+ * @return {string} The string form of the url.
+ * @override
+ */
+goog.Uri.prototype.toString = function() {
+ var out = [];
+
+ var scheme = this.getScheme();
+ if (scheme) {
+ out.push(
+ goog.Uri.encodeSpecialChars_(
+ scheme, goog.Uri.reDisallowedInSchemeOrUserInfo_, true),
+ ':');
+ }
+
+ var domain = this.getDomain();
+ if (domain || scheme == 'file') {
+ out.push('//');
+
+ var userInfo = this.getUserInfo();
+ if (userInfo) {
+ out.push(
+ goog.Uri.encodeSpecialChars_(
+ userInfo, goog.Uri.reDisallowedInSchemeOrUserInfo_, true),
+ '@');
+ }
+
+ out.push(goog.Uri.removeDoubleEncoding_(goog.string.urlEncode(domain)));
+
+ var port = this.getPort();
+ if (port != null) {
+ out.push(':', String(port));
+ }
+ }
+
+ var path = this.getPath();
+ if (path) {
+ if (this.hasDomain() && path.charAt(0) != '/') {
+ out.push('/');
+ }
+ out.push(
+ goog.Uri.encodeSpecialChars_(
+ path, path.charAt(0) == '/' ? goog.Uri.reDisallowedInAbsolutePath_ :
+ goog.Uri.reDisallowedInRelativePath_,
+ true));
+ }
+
+ var query = this.getEncodedQuery();
+ if (query) {
+ out.push('?', query);
+ }
+
+ var fragment = this.getFragment();
+ if (fragment) {
+ out.push(
+ '#', goog.Uri.encodeSpecialChars_(
+ fragment, goog.Uri.reDisallowedInFragment_));
+ }
+ return out.join('');
+};
+
+
+/**
+ * Resolves the given relative URI (a goog.Uri object), using the URI
+ * represented by this instance as the base URI.
+ *
+ * There are several kinds of relative URIs:<br>
+ * 1. foo - replaces the last part of the path, the whole query and fragment<br>
+ * 2. /foo - replaces the the path, the query and fragment<br>
+ * 3. //foo - replaces everything from the domain on. foo is a domain name<br>
+ * 4. ?foo - replace the query and fragment<br>
+ * 5. #foo - replace the fragment only
+ *
+ * Additionally, if relative URI has a non-empty path, all ".." and "."
+ * segments will be resolved, as described in RFC 3986.
+ *
+ * @param {!goog.Uri} relativeUri The relative URI to resolve.
+ * @return {!goog.Uri} The resolved URI.
+ */
+goog.Uri.prototype.resolve = function(relativeUri) {
+
+ var absoluteUri = this.clone();
+
+ // we satisfy these conditions by looking for the first part of relativeUri
+ // that is not blank and applying defaults to the rest
+
+ var overridden = relativeUri.hasScheme();
+
+ if (overridden) {
+ absoluteUri.setScheme(relativeUri.getScheme());
+ } else {
+ overridden = relativeUri.hasUserInfo();
+ }
+
+ if (overridden) {
+ absoluteUri.setUserInfo(relativeUri.getUserInfo());
+ } else {
+ overridden = relativeUri.hasDomain();
+ }
+
+ if (overridden) {
+ absoluteUri.setDomain(relativeUri.getDomain());
+ } else {
+ overridden = relativeUri.hasPort();
+ }
+
+ var path = relativeUri.getPath();
+ if (overridden) {
+ absoluteUri.setPort(relativeUri.getPort());
+ } else {
+ overridden = relativeUri.hasPath();
+ if (overridden) {
+ // resolve path properly
+ if (path.charAt(0) != '/') {
+ // path is relative
+ if (this.hasDomain() && !this.hasPath()) {
+ // RFC 3986, section 5.2.3, case 1
+ path = '/' + path;
+ } else {
+ // RFC 3986, section 5.2.3, case 2
+ var lastSlashIndex = absoluteUri.getPath().lastIndexOf('/');
+ if (lastSlashIndex != -1) {
+ path = absoluteUri.getPath().substr(0, lastSlashIndex + 1) + path;
+ }
+ }
+ }
+ path = goog.Uri.removeDotSegments(path);
+ }
+ }
+
+ if (overridden) {
+ absoluteUri.setPath(path);
+ } else {
+ overridden = relativeUri.hasQuery();
+ }
+
+ if (overridden) {
+ absoluteUri.setQueryData(relativeUri.getDecodedQuery());
+ } else {
+ overridden = relativeUri.hasFragment();
+ }
+
+ if (overridden) {
+ absoluteUri.setFragment(relativeUri.getFragment());
+ }
+
+ return absoluteUri;
+};
+
+
+/**
+ * Clones the URI instance.
+ * @return {!goog.Uri} New instance of the URI object.
+ */
+goog.Uri.prototype.clone = function() {
+ return new goog.Uri(this);
+};
+
+
+/**
+ * @return {string} The encoded scheme/protocol for the URI.
+ */
+goog.Uri.prototype.getScheme = function() {
+ return this.scheme_;
+};
+
+
+/**
+ * Sets the scheme/protocol.
+ * @throws URIError If opt_decode is true and newScheme is malformed (that is,
+ * if decodeURIComponent fails).
+ * @param {string} newScheme New scheme value.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setScheme = function(newScheme, opt_decode) {
+ this.enforceReadOnly();
+ this.scheme_ =
+ opt_decode ? goog.Uri.decodeOrEmpty_(newScheme, true) : newScheme;
+
+ // remove an : at the end of the scheme so somebody can pass in
+ // window.location.protocol
+ if (this.scheme_) {
+ this.scheme_ = this.scheme_.replace(/:$/, '');
+ }
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the scheme has been set.
+ */
+goog.Uri.prototype.hasScheme = function() {
+ return !!this.scheme_;
+};
+
+
+/**
+ * @return {string} The decoded user info.
+ */
+goog.Uri.prototype.getUserInfo = function() {
+ return this.userInfo_;
+};
+
+
+/**
+ * Sets the userInfo.
+ * @throws URIError If opt_decode is true and newUserInfo is malformed (that is,
+ * if decodeURIComponent fails).
+ * @param {string} newUserInfo New userInfo value.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setUserInfo = function(newUserInfo, opt_decode) {
+ this.enforceReadOnly();
+ this.userInfo_ =
+ opt_decode ? goog.Uri.decodeOrEmpty_(newUserInfo) : newUserInfo;
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the user info has been set.
+ */
+goog.Uri.prototype.hasUserInfo = function() {
+ return !!this.userInfo_;
+};
+
+
+/**
+ * @return {string} The decoded domain.
+ */
+goog.Uri.prototype.getDomain = function() {
+ return this.domain_;
+};
+
+
+/**
+ * Sets the domain.
+ * @throws URIError If opt_decode is true and newDomain is malformed (that is,
+ * if decodeURIComponent fails).
+ * @param {string} newDomain New domain value.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setDomain = function(newDomain, opt_decode) {
+ this.enforceReadOnly();
+ this.domain_ =
+ opt_decode ? goog.Uri.decodeOrEmpty_(newDomain, true) : newDomain;
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the domain has been set.
+ */
+goog.Uri.prototype.hasDomain = function() {
+ return !!this.domain_;
+};
+
+
+/**
+ * @return {?number} The port number.
+ */
+goog.Uri.prototype.getPort = function() {
+ return this.port_;
+};
+
+
+/**
+ * Sets the port number.
+ * @param {*} newPort Port number. Will be explicitly casted to a number.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setPort = function(newPort) {
+ this.enforceReadOnly();
+
+ if (newPort) {
+ newPort = Number(newPort);
+ if (isNaN(newPort) || newPort < 0) {
+ throw Error('Bad port number ' + newPort);
+ }
+ this.port_ = newPort;
+ } else {
+ this.port_ = null;
+ }
+
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the port has been set.
+ */
+goog.Uri.prototype.hasPort = function() {
+ return this.port_ != null;
+};
+
+
+/**
+ * @return {string} The decoded path.
+ */
+goog.Uri.prototype.getPath = function() {
+ return this.path_;
+};
+
+
+/**
+ * Sets the path.
+ * @throws URIError If opt_decode is true and newPath is malformed (that is,
+ * if decodeURIComponent fails).
+ * @param {string} newPath New path value.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setPath = function(newPath, opt_decode) {
+ this.enforceReadOnly();
+ this.path_ = opt_decode ? goog.Uri.decodeOrEmpty_(newPath, true) : newPath;
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the path has been set.
+ */
+goog.Uri.prototype.hasPath = function() {
+ return !!this.path_;
+};
+
+
+/**
+ * @return {boolean} Whether the query string has been set.
+ */
+goog.Uri.prototype.hasQuery = function() {
+ return this.queryData_.toString() !== '';
+};
+
+
+/**
+ * Sets the query data.
+ * @param {goog.Uri.QueryData|string|undefined} queryData QueryData object.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * Applies only if queryData is a string.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setQueryData = function(queryData, opt_decode) {
+ this.enforceReadOnly();
+
+ if (queryData instanceof goog.Uri.QueryData) {
+ this.queryData_ = queryData;
+ this.queryData_.setIgnoreCase(this.ignoreCase_);
+ } else {
+ if (!opt_decode) {
+ // QueryData accepts encoded query string, so encode it if
+ // opt_decode flag is not true.
+ queryData = goog.Uri.encodeSpecialChars_(
+ queryData, goog.Uri.reDisallowedInQuery_);
+ }
+ this.queryData_ = new goog.Uri.QueryData(queryData, null, this.ignoreCase_);
+ }
+
+ return this;
+};
+
+
+/**
+ * Sets the URI query.
+ * @param {string} newQuery New query value.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setQuery = function(newQuery, opt_decode) {
+ return this.setQueryData(newQuery, opt_decode);
+};
+
+
+/**
+ * @return {string} The encoded URI query, not including the ?.
+ */
+goog.Uri.prototype.getEncodedQuery = function() {
+ return this.queryData_.toString();
+};
+
+
+/**
+ * @return {string} The decoded URI query, not including the ?.
+ */
+goog.Uri.prototype.getDecodedQuery = function() {
+ return this.queryData_.toDecodedString();
+};
+
+
+/**
+ * Returns the query data.
+ * @return {!goog.Uri.QueryData} QueryData object.
+ */
+goog.Uri.prototype.getQueryData = function() {
+ return this.queryData_;
+};
+
+
+/**
+ * @return {string} The encoded URI query, not including the ?.
+ *
+ * Warning: This method, unlike other getter methods, returns encoded
+ * value, instead of decoded one.
+ */
+goog.Uri.prototype.getQuery = function() {
+ return this.getEncodedQuery();
+};
+
+
+/**
+ * Sets the value of the named query parameters, clearing previous values for
+ * that key.
+ *
+ * @param {string} key The parameter to set.
+ * @param {*} value The new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setParameterValue = function(key, value) {
+ this.enforceReadOnly();
+ this.queryData_.set(key, value);
+ return this;
+};
+
+
+/**
+ * Sets the values of the named query parameters, clearing previous values for
+ * that key. Not new values will currently be moved to the end of the query
+ * string.
+ *
+ * So, <code>goog.Uri.parse('foo?a=b&c=d&e=f').setParameterValues('c', ['new'])
+ * </code> yields <tt>foo?a=b&e=f&c=new</tt>.</p>
+ *
+ * @param {string} key The parameter to set.
+ * @param {*} values The new values. If values is a single
+ * string then it will be treated as the sole value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setParameterValues = function(key, values) {
+ this.enforceReadOnly();
+
+ if (!goog.isArray(values)) {
+ values = [String(values)];
+ }
+
+ this.queryData_.setValues(key, values);
+
+ return this;
+};
+
+
+/**
+ * Returns the value<b>s</b> for a given cgi parameter as a list of decoded
+ * query parameter values.
+ * @param {string} name The parameter to get values for.
+ * @return {!Array<?>} The values for a given cgi parameter as a list of
+ * decoded query parameter values.
+ */
+goog.Uri.prototype.getParameterValues = function(name) {
+ return this.queryData_.getValues(name);
+};
+
+
+/**
+ * Returns the first value for a given cgi parameter or undefined if the given
+ * parameter name does not appear in the query string.
+ * @param {string} paramName Unescaped parameter name.
+ * @return {string|undefined} The first value for a given cgi parameter or
+ * undefined if the given parameter name does not appear in the query
+ * string.
+ */
+goog.Uri.prototype.getParameterValue = function(paramName) {
+ // NOTE(nicksantos): This type-cast is a lie when
+ // preserveParameterTypesCompatibilityFlag is set to true.
+ // But this should only be set to true in tests.
+ return /** @type {string|undefined} */ (this.queryData_.get(paramName));
+};
+
+
+/**
+ * @return {string} The URI fragment, not including the #.
+ */
+goog.Uri.prototype.getFragment = function() {
+ return this.fragment_;
+};
+
+
+/**
+ * Sets the URI fragment.
+ * @throws URIError If opt_decode is true and newFragment is malformed (that is,
+ * if decodeURIComponent fails).
+ * @param {string} newFragment New fragment value.
+ * @param {boolean=} opt_decode Optional param for whether to decode new value.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.setFragment = function(newFragment, opt_decode) {
+ this.enforceReadOnly();
+ this.fragment_ =
+ opt_decode ? goog.Uri.decodeOrEmpty_(newFragment) : newFragment;
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the URI has a fragment set.
+ */
+goog.Uri.prototype.hasFragment = function() {
+ return !!this.fragment_;
+};
+
+
+/**
+ * Returns true if this has the same domain as that of uri2.
+ * @param {!goog.Uri} uri2 The URI object to compare to.
+ * @return {boolean} true if same domain; false otherwise.
+ */
+goog.Uri.prototype.hasSameDomainAs = function(uri2) {
+ return ((!this.hasDomain() && !uri2.hasDomain()) ||
+ this.getDomain() == uri2.getDomain()) &&
+ ((!this.hasPort() && !uri2.hasPort()) ||
+ this.getPort() == uri2.getPort());
+};
+
+
+/**
+ * Adds a random parameter to the Uri.
+ * @return {!goog.Uri} Reference to this Uri object.
+ */
+goog.Uri.prototype.makeUnique = function() {
+ this.enforceReadOnly();
+ this.setParameterValue(goog.Uri.RANDOM_PARAM, goog.string.getRandomString());
+
+ return this;
+};
+
+
+/**
+ * Removes the named query parameter.
+ *
+ * @param {string} key The parameter to remove.
+ * @return {!goog.Uri} Reference to this URI object.
+ */
+goog.Uri.prototype.removeParameter = function(key) {
+ this.enforceReadOnly();
+ this.queryData_.remove(key);
+ return this;
+};
+
+
+/**
+ * Sets whether Uri is read only. If this goog.Uri is read-only,
+ * enforceReadOnly_ will be called at the start of any function that may modify
+ * this Uri.
+ * @param {boolean} isReadOnly whether this goog.Uri should be read only.
+ * @return {!goog.Uri} Reference to this Uri object.
+ */
+goog.Uri.prototype.setReadOnly = function(isReadOnly) {
+ this.isReadOnly_ = isReadOnly;
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether the URI is read only.
+ */
+goog.Uri.prototype.isReadOnly = function() {
+ return this.isReadOnly_;
+};
+
+
+/**
+ * Checks if this Uri has been marked as read only, and if so, throws an error.
+ * This should be called whenever any modifying function is called.
+ */
+goog.Uri.prototype.enforceReadOnly = function() {
+ if (this.isReadOnly_) {
+ throw Error('Tried to modify a read-only Uri');
+ }
+};
+
+
+/**
+ * Sets whether to ignore case.
+ * NOTE: If there are already key/value pairs in the QueryData, and
+ * ignoreCase_ is set to false, the keys will all be lower-cased.
+ * @param {boolean} ignoreCase whether this goog.Uri should ignore case.
+ * @return {!goog.Uri} Reference to this Uri object.
+ */
+goog.Uri.prototype.setIgnoreCase = function(ignoreCase) {
+ this.ignoreCase_ = ignoreCase;
+ if (this.queryData_) {
+ this.queryData_.setIgnoreCase(ignoreCase);
+ }
+ return this;
+};
+
+
+/**
+ * @return {boolean} Whether to ignore case.
+ */
+goog.Uri.prototype.getIgnoreCase = function() {
+ return this.ignoreCase_;
+};
+
+
+//==============================================================================
+// Static members
+//==============================================================================
+
+
+/**
+ * Creates a uri from the string form. Basically an alias of new goog.Uri().
+ * If a Uri object is passed to parse then it will return a clone of the object.
+ *
+ * @throws URIError If parsing the URI is malformed. The passed URI components
+ * should all be parseable by decodeURIComponent.
+ * @param {*} uri Raw URI string or instance of Uri
+ * object.
+ * @param {boolean=} opt_ignoreCase Whether to ignore the case of parameter
+ * names in #getParameterValue.
+ * @return {!goog.Uri} The new URI object.
+ */
+goog.Uri.parse = function(uri, opt_ignoreCase) {
+ return uri instanceof goog.Uri ? uri.clone() :
+ new goog.Uri(uri, opt_ignoreCase);
+};
+
+
+/**
+ * Creates a new goog.Uri object from unencoded parts.
+ *
+ * @param {?string=} opt_scheme Scheme/protocol or full URI to parse.
+ * @param {?string=} opt_userInfo username:password.
+ * @param {?string=} opt_domain www.google.com.
+ * @param {?number=} opt_port 9830.
+ * @param {?string=} opt_path /some/path/to/a/file.html.
+ * @param {string|goog.Uri.QueryData=} opt_query a=1&b=2.
+ * @param {?string=} opt_fragment The fragment without the #.
+ * @param {boolean=} opt_ignoreCase Whether to ignore parameter name case in
+ * #getParameterValue.
+ *
+ * @return {!goog.Uri} The new URI object.
+ */
+goog.Uri.create = function(
+ opt_scheme, opt_userInfo, opt_domain, opt_port, opt_path, opt_query,
+ opt_fragment, opt_ignoreCase) {
+
+ var uri = new goog.Uri(null, opt_ignoreCase);
+
+ // Only set the parts if they are defined and not empty strings.
+ opt_scheme && uri.setScheme(opt_scheme);
+ opt_userInfo && uri.setUserInfo(opt_userInfo);
+ opt_domain && uri.setDomain(opt_domain);
+ opt_port && uri.setPort(opt_port);
+ opt_path && uri.setPath(opt_path);
+ opt_query && uri.setQueryData(opt_query);
+ opt_fragment && uri.setFragment(opt_fragment);
+
+ return uri;
+};
+
+
+/**
+ * Resolves a relative Uri against a base Uri, accepting both strings and
+ * Uri objects.
+ *
+ * @param {*} base Base Uri.
+ * @param {*} rel Relative Uri.
+ * @return {!goog.Uri} Resolved uri.
+ */
+goog.Uri.resolve = function(base, rel) {
+ if (!(base instanceof goog.Uri)) {
+ base = goog.Uri.parse(base);
+ }
+
+ if (!(rel instanceof goog.Uri)) {
+ rel = goog.Uri.parse(rel);
+ }
+
+ return base.resolve(rel);
+};
+
+
+/**
+ * Removes dot segments in given path component, as described in
+ * RFC 3986, section 5.2.4.
+ *
+ * @param {string} path A non-empty path component.
+ * @return {string} Path component with removed dot segments.
+ */
+goog.Uri.removeDotSegments = function(path) {
+ if (path == '..' || path == '.') {
+ return '';
+
+ } else if (
+ !goog.string.contains(path, './') && !goog.string.contains(path, '/.')) {
+ // This optimization detects uris which do not contain dot-segments,
+ // and as a consequence do not require any processing.
+ return path;
+
+ } else {
+ var leadingSlash = goog.string.startsWith(path, '/');
+ var segments = path.split('/');
+ var out = [];
+
+ for (var pos = 0; pos < segments.length;) {
+ var segment = segments[pos++];
+
+ if (segment == '.') {
+ if (leadingSlash && pos == segments.length) {
+ out.push('');
+ }
+ } else if (segment == '..') {
+ if (out.length > 1 || out.length == 1 && out[0] != '') {
+ out.pop();
+ }
+ if (leadingSlash && pos == segments.length) {
+ out.push('');
+ }
+ } else {
+ out.push(segment);
+ leadingSlash = true;
+ }
+ }
+
+ return out.join('/');
+ }
+};
+
+
+/**
+ * Decodes a value or returns the empty string if it isn't defined or empty.
+ * @throws URIError If decodeURIComponent fails to decode val.
+ * @param {string|undefined} val Value to decode.
+ * @param {boolean=} opt_preserveReserved If true, restricted characters will
+ * not be decoded.
+ * @return {string} Decoded value.
+ * @private
+ */
+goog.Uri.decodeOrEmpty_ = function(val, opt_preserveReserved) {
+ // Don't use UrlDecode() here because val is not a query parameter.
+ if (!val) {
+ return '';
+ }
+
+ // decodeURI has the same output for '%2f' and '%252f'. We double encode %25
+ // so that we can distinguish between the 2 inputs. This is later undone by
+ // removeDoubleEncoding_.
+ return opt_preserveReserved ? decodeURI(val.replace(/%25/g, '%2525')) :
+ decodeURIComponent(val);
+};
+
+
+/**
+ * If unescapedPart is non null, then escapes any characters in it that aren't
+ * valid characters in a url and also escapes any special characters that
+ * appear in extra.
+ *
+ * @param {*} unescapedPart The string to encode.
+ * @param {RegExp} extra A character set of characters in [\01-\177].
+ * @param {boolean=} opt_removeDoubleEncoding If true, remove double percent
+ * encoding.
+ * @return {?string} null iff unescapedPart == null.
+ * @private
+ */
+goog.Uri.encodeSpecialChars_ = function(
+ unescapedPart, extra, opt_removeDoubleEncoding) {
+ if (goog.isString(unescapedPart)) {
+ var encoded = encodeURI(unescapedPart).replace(extra, goog.Uri.encodeChar_);
+ if (opt_removeDoubleEncoding) {
+ // encodeURI double-escapes %XX sequences used to represent restricted
+ // characters in some URI components, remove the double escaping here.
+ encoded = goog.Uri.removeDoubleEncoding_(encoded);
+ }
+ return encoded;
+ }
+ return null;
+};
+
+
+/**
+ * Converts a character in [\01-\177] to its unicode character equivalent.
+ * @param {string} ch One character string.
+ * @return {string} Encoded string.
+ * @private
+ */
+goog.Uri.encodeChar_ = function(ch) {
+ var n = ch.charCodeAt(0);
+ return '%' + ((n >> 4) & 0xf).toString(16) + (n & 0xf).toString(16);
+};
+
+
+/**
+ * Removes double percent-encoding from a string.
+ * @param {string} doubleEncodedString String
+ * @return {string} String with double encoding removed.
+ * @private
+ */
+goog.Uri.removeDoubleEncoding_ = function(doubleEncodedString) {
+ return doubleEncodedString.replace(/%25([0-9a-fA-F]{2})/g, '%$1');
+};
+
+
+/**
+ * Regular expression for characters that are disallowed in the scheme or
+ * userInfo part of the URI.
+ * @type {RegExp}
+ * @private
+ */
+goog.Uri.reDisallowedInSchemeOrUserInfo_ = /[#\/\?@]/g;
+
+
+/**
+ * Regular expression for characters that are disallowed in a relative path.
+ * Colon is included due to RFC 3986 3.3.
+ * @type {RegExp}
+ * @private
+ */
+goog.Uri.reDisallowedInRelativePath_ = /[\#\?:]/g;
+
+
+/**
+ * Regular expression for characters that are disallowed in an absolute path.
+ * @type {RegExp}
+ * @private
+ */
+goog.Uri.reDisallowedInAbsolutePath_ = /[\#\?]/g;
+
+
+/**
+ * Regular expression for characters that are disallowed in the query.
+ * @type {RegExp}
+ * @private
+ */
+goog.Uri.reDisallowedInQuery_ = /[\#\?@]/g;
+
+
+/**
+ * Regular expression for characters that are disallowed in the fragment.
+ * @type {RegExp}
+ * @private
+ */
+goog.Uri.reDisallowedInFragment_ = /#/g;
+
+
+/**
+ * Checks whether two URIs have the same domain.
+ * @param {string} uri1String First URI string.
+ * @param {string} uri2String Second URI string.
+ * @return {boolean} true if the two URIs have the same domain; false otherwise.
+ */
+goog.Uri.haveSameDomain = function(uri1String, uri2String) {
+ // Differs from goog.uri.utils.haveSameDomain, since this ignores scheme.
+ // TODO(gboyer): Have this just call goog.uri.util.haveSameDomain.
+ var pieces1 = goog.uri.utils.split(uri1String);
+ var pieces2 = goog.uri.utils.split(uri2String);
+ return pieces1[goog.uri.utils.ComponentIndex.DOMAIN] ==
+ pieces2[goog.uri.utils.ComponentIndex.DOMAIN] &&
+ pieces1[goog.uri.utils.ComponentIndex.PORT] ==
+ pieces2[goog.uri.utils.ComponentIndex.PORT];
+};
+
+
+
+/**
+ * Class used to represent URI query parameters. It is essentially a hash of
+ * name-value pairs, though a name can be present more than once.
+ *
+ * Has the same interface as the collections in goog.structs.
+ *
+ * @param {?string=} opt_query Optional encoded query string to parse into
+ * the object.
+ * @param {goog.Uri=} opt_uri Optional uri object that should have its
+ * cache invalidated when this object updates. Deprecated -- this
+ * is no longer required.
+ * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter
+ * name in #get.
+ * @constructor
+ * @struct
+ * @final
+ */
+goog.Uri.QueryData = function(opt_query, opt_uri, opt_ignoreCase) {
+ /**
+ * The map containing name/value or name/array-of-values pairs.
+ * May be null if it requires parsing from the query string.
+ *
+ * We need to use a Map because we cannot guarantee that the key names will
+ * not be problematic for IE.
+ *
+ * @private {goog.structs.Map<string, !Array<*>>}
+ */
+ this.keyMap_ = null;
+
+ /**
+ * The number of params, or null if it requires computing.
+ * @private {?number}
+ */
+ this.count_ = null;
+
+ /**
+ * Encoded query string, or null if it requires computing from the key map.
+ * @private {?string}
+ */
+ this.encodedQuery_ = opt_query || null;
+
+ /**
+ * If true, ignore the case of the parameter name in #get.
+ * @private {boolean}
+ */
+ this.ignoreCase_ = !!opt_ignoreCase;
+};
+
+
+/**
+ * If the underlying key map is not yet initialized, it parses the
+ * query string and fills the map with parsed data.
+ * @private
+ */
+goog.Uri.QueryData.prototype.ensureKeyMapInitialized_ = function() {
+ if (!this.keyMap_) {
+ this.keyMap_ = new goog.structs.Map();
+ this.count_ = 0;
+ if (this.encodedQuery_) {
+ var self = this;
+ goog.uri.utils.parseQueryData(this.encodedQuery_, function(name, value) {
+ self.add(goog.string.urlDecode(name), value);
+ });
+ }
+ }
+};
+
+
+/**
+ * Creates a new query data instance from a map of names and values.
+ *
+ * @param {!goog.structs.Map<string, ?>|!Object} map Map of string parameter
+ * names to parameter value. If parameter value is an array, it is
+ * treated as if the key maps to each individual value in the
+ * array.
+ * @param {goog.Uri=} opt_uri URI object that should have its cache
+ * invalidated when this object updates.
+ * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter
+ * name in #get.
+ * @return {!goog.Uri.QueryData} The populated query data instance.
+ */
+goog.Uri.QueryData.createFromMap = function(map, opt_uri, opt_ignoreCase) {
+ var keys = goog.structs.getKeys(map);
+ if (typeof keys == 'undefined') {
+ throw Error('Keys are undefined');
+ }
+
+ var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase);
+ var values = goog.structs.getValues(map);
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ var value = values[i];
+ if (!goog.isArray(value)) {
+ queryData.add(key, value);
+ } else {
+ queryData.setValues(key, value);
+ }
+ }
+ return queryData;
+};
+
+
+/**
+ * Creates a new query data instance from parallel arrays of parameter names
+ * and values. Allows for duplicate parameter names. Throws an error if the
+ * lengths of the arrays differ.
+ *
+ * @param {!Array<string>} keys Parameter names.
+ * @param {!Array<?>} values Parameter values.
+ * @param {goog.Uri=} opt_uri URI object that should have its cache
+ * invalidated when this object updates.
+ * @param {boolean=} opt_ignoreCase If true, ignore the case of the parameter
+ * name in #get.
+ * @return {!goog.Uri.QueryData} The populated query data instance.
+ */
+goog.Uri.QueryData.createFromKeysValues = function(
+ keys, values, opt_uri, opt_ignoreCase) {
+ if (keys.length != values.length) {
+ throw Error('Mismatched lengths for keys/values');
+ }
+ var queryData = new goog.Uri.QueryData(null, null, opt_ignoreCase);
+ for (var i = 0; i < keys.length; i++) {
+ queryData.add(keys[i], values[i]);
+ }
+ return queryData;
+};
+
+
+/**
+ * @return {?number} The number of parameters.
+ */
+goog.Uri.QueryData.prototype.getCount = function() {
+ this.ensureKeyMapInitialized_();
+ return this.count_;
+};
+
+
+/**
+ * Adds a key value pair.
+ * @param {string} key Name.
+ * @param {*} value Value.
+ * @return {!goog.Uri.QueryData} Instance of this object.
+ */
+goog.Uri.QueryData.prototype.add = function(key, value) {
+ this.ensureKeyMapInitialized_();
+ this.invalidateCache_();
+
+ key = this.getKeyName_(key);
+ var values = this.keyMap_.get(key);
+ if (!values) {
+ this.keyMap_.set(key, (values = []));
+ }
+ values.push(value);
+ this.count_ = goog.asserts.assertNumber(this.count_) + 1;
+ return this;
+};
+
+
+/**
+ * Removes all the params with the given key.
+ * @param {string} key Name.
+ * @return {boolean} Whether any parameter was removed.
+ */
+goog.Uri.QueryData.prototype.remove = function(key) {
+ this.ensureKeyMapInitialized_();
+
+ key = this.getKeyName_(key);
+ if (this.keyMap_.containsKey(key)) {
+ this.invalidateCache_();
+
+ // Decrement parameter count.
+ this.count_ =
+ goog.asserts.assertNumber(this.count_) - this.keyMap_.get(key).length;
+ return this.keyMap_.remove(key);
+ }
+ return false;
+};
+
+
+/**
+ * Clears the parameters.
+ */
+goog.Uri.QueryData.prototype.clear = function() {
+ this.invalidateCache_();
+ this.keyMap_ = null;
+ this.count_ = 0;
+};
+
+
+/**
+ * @return {boolean} Whether we have any parameters.
+ */
+goog.Uri.QueryData.prototype.isEmpty = function() {
+ this.ensureKeyMapInitialized_();
+ return this.count_ == 0;
+};
+
+
+/**
+ * Whether there is a parameter with the given name
+ * @param {string} key The parameter name to check for.
+ * @return {boolean} Whether there is a parameter with the given name.
+ */
+goog.Uri.QueryData.prototype.containsKey = function(key) {
+ this.ensureKeyMapInitialized_();
+ key = this.getKeyName_(key);
+ return this.keyMap_.containsKey(key);
+};
+
+
+/**
+ * Whether there is a parameter with the given value.
+ * @param {*} value The value to check for.
+ * @return {boolean} Whether there is a parameter with the given value.
+ */
+goog.Uri.QueryData.prototype.containsValue = function(value) {
+ // NOTE(arv): This solution goes through all the params even if it was the
+ // first param. We can get around this by not reusing code or by switching to
+ // iterators.
+ var vals = this.getValues();
+ return goog.array.contains(vals, value);
+};
+
+
+/**
+ * Returns all the keys of the parameters. If a key is used multiple times
+ * it will be included multiple times in the returned array
+ * @return {!Array<string>} All the keys of the parameters.
+ */
+goog.Uri.QueryData.prototype.getKeys = function() {
+ this.ensureKeyMapInitialized_();
+ // We need to get the values to know how many keys to add.
+ var vals = this.keyMap_.getValues();
+ var keys = this.keyMap_.getKeys();
+ var rv = [];
+ for (var i = 0; i < keys.length; i++) {
+ var val = vals[i];
+ for (var j = 0; j < val.length; j++) {
+ rv.push(keys[i]);
+ }
+ }
+ return rv;
+};
+
+
+/**
+ * Returns all the values of the parameters with the given name. If the query
+ * data has no such key this will return an empty array. If no key is given
+ * all values wil be returned.
+ * @param {string=} opt_key The name of the parameter to get the values for.
+ * @return {!Array<?>} All the values of the parameters with the given name.
+ */
+goog.Uri.QueryData.prototype.getValues = function(opt_key) {
+ this.ensureKeyMapInitialized_();
+ var rv = [];
+ if (goog.isString(opt_key)) {
+ if (this.containsKey(opt_key)) {
+ rv = goog.array.concat(rv, this.keyMap_.get(this.getKeyName_(opt_key)));
+ }
+ } else {
+ // Return all values.
+ var values = this.keyMap_.getValues();
+ for (var i = 0; i < values.length; i++) {
+ rv = goog.array.concat(rv, values[i]);
+ }
+ }
+ return rv;
+};
+
+
+/**
+ * Sets a key value pair and removes all other keys with the same value.
+ *
+ * @param {string} key Name.
+ * @param {*} value Value.
+ * @return {!goog.Uri.QueryData} Instance of this object.
+ */
+goog.Uri.QueryData.prototype.set = function(key, value) {
+ this.ensureKeyMapInitialized_();
+ this.invalidateCache_();
+
+ // TODO(chrishenry): This could be better written as
+ // this.remove(key), this.add(key, value), but that would reorder
+ // the key (since the key is first removed and then added at the
+ // end) and we would have to fix unit tests that depend on key
+ // ordering.
+ key = this.getKeyName_(key);
+ if (this.containsKey(key)) {
+ this.count_ =
+ goog.asserts.assertNumber(this.count_) - this.keyMap_.get(key).length;
+ }
+ this.keyMap_.set(key, [value]);
+ this.count_ = goog.asserts.assertNumber(this.count_) + 1;
+ return this;
+};
+
+
+/**
+ * Returns the first value associated with the key. If the query data has no
+ * such key this will return undefined or the optional default.
+ * @param {string} key The name of the parameter to get the value for.
+ * @param {*=} opt_default The default value to return if the query data
+ * has no such key.
+ * @return {*} The first string value associated with the key, or opt_default
+ * if there's no value.
+ */
+goog.Uri.QueryData.prototype.get = function(key, opt_default) {
+ var values = key ? this.getValues(key) : [];
+ if (goog.Uri.preserveParameterTypesCompatibilityFlag) {
+ return values.length > 0 ? values[0] : opt_default;
+ } else {
+ return values.length > 0 ? String(values[0]) : opt_default;
+ }
+};
+
+
+/**
+ * Sets the values for a key. If the key already exists, this will
+ * override all of the existing values that correspond to the key.
+ * @param {string} key The key to set values for.
+ * @param {!Array<?>} values The values to set.
+ */
+goog.Uri.QueryData.prototype.setValues = function(key, values) {
+ this.remove(key);
+
+ if (values.length > 0) {
+ this.invalidateCache_();
+ this.keyMap_.set(this.getKeyName_(key), goog.array.clone(values));
+ this.count_ = goog.asserts.assertNumber(this.count_) + values.length;
+ }
+};
+
+
+/**
+ * @return {string} Encoded query string.
+ * @override
+ */
+goog.Uri.QueryData.prototype.toString = function() {
+ if (this.encodedQuery_) {
+ return this.encodedQuery_;
+ }
+
+ if (!this.keyMap_) {
+ return '';
+ }
+
+ var sb = [];
+
+ // In the past, we use this.getKeys() and this.getVals(), but that
+ // generates a lot of allocations as compared to simply iterating
+ // over the keys.
+ var keys = this.keyMap_.getKeys();
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ var encodedKey = goog.string.urlEncode(key);
+ var val = this.getValues(key);
+ for (var j = 0; j < val.length; j++) {
+ var param = encodedKey;
+ // Ensure that null and undefined are encoded into the url as
+ // literal strings.
+ if (val[j] !== '') {
+ param += '=' + goog.string.urlEncode(val[j]);
+ }
+ sb.push(param);
+ }
+ }
+
+ return this.encodedQuery_ = sb.join('&');
+};
+
+
+/**
+ * @throws URIError If URI is malformed (that is, if decodeURIComponent fails on
+ * any of the URI components).
+ * @return {string} Decoded query string.
+ */
+goog.Uri.QueryData.prototype.toDecodedString = function() {
+ return goog.Uri.decodeOrEmpty_(this.toString());
+};
+
+
+/**
+ * Invalidate the cache.
+ * @private
+ */
+goog.Uri.QueryData.prototype.invalidateCache_ = function() {
+ this.encodedQuery_ = null;
+};
+
+
+/**
+ * Removes all keys that are not in the provided list. (Modifies this object.)
+ * @param {Array<string>} keys The desired keys.
+ * @return {!goog.Uri.QueryData} a reference to this object.
+ */
+goog.Uri.QueryData.prototype.filterKeys = function(keys) {
+ this.ensureKeyMapInitialized_();
+ this.keyMap_.forEach(function(value, key) {
+ if (!goog.array.contains(keys, key)) {
+ this.remove(key);
+ }
+ }, this);
+ return this;
+};
+
+
+/**
+ * Clone the query data instance.
+ * @return {!goog.Uri.QueryData} New instance of the QueryData object.
+ */
+goog.Uri.QueryData.prototype.clone = function() {
+ var rv = new goog.Uri.QueryData();
+ rv.encodedQuery_ = this.encodedQuery_;
+ if (this.keyMap_) {
+ rv.keyMap_ = this.keyMap_.clone();
+ rv.count_ = this.count_;
+ }
+ return rv;
+};
+
+
+/**
+ * Helper function to get the key name from a JavaScript object. Converts
+ * the object to a string, and to lower case if necessary.
+ * @private
+ * @param {*} arg The object to get a key name from.
+ * @return {string} valid key name which can be looked up in #keyMap_.
+ */
+goog.Uri.QueryData.prototype.getKeyName_ = function(arg) {
+ var keyName = String(arg);
+ if (this.ignoreCase_) {
+ keyName = keyName.toLowerCase();
+ }
+ return keyName;
+};
+
+
+/**
+ * Ignore case in parameter names.
+ * NOTE: If there are already key/value pairs in the QueryData, and
+ * ignoreCase_ is set to false, the keys will all be lower-cased.
+ * @param {boolean} ignoreCase whether this goog.Uri should ignore case.
+ */
+goog.Uri.QueryData.prototype.setIgnoreCase = function(ignoreCase) {
+ var resetKeys = ignoreCase && !this.ignoreCase_;
+ if (resetKeys) {
+ this.ensureKeyMapInitialized_();
+ this.invalidateCache_();
+ this.keyMap_.forEach(function(value, key) {
+ var lowerCase = key.toLowerCase();
+ if (key != lowerCase) {
+ this.remove(key);
+ this.setValues(lowerCase, value);
+ }
+ }, this);
+ }
+ this.ignoreCase_ = ignoreCase;
+};
+
+
+/**
+ * Extends a query data object with another query data or map like object. This
+ * operates 'in-place', it does not create a new QueryData object.
+ *
+ * @param {...(goog.Uri.QueryData|goog.structs.Map<?, ?>|Object)} var_args
+ * The object from which key value pairs will be copied.
+ */
+goog.Uri.QueryData.prototype.extend = function(var_args) {
+ for (var i = 0; i < arguments.length; i++) {
+ var data = arguments[i];
+ goog.structs.forEach(
+ data, function(value, key) { this.add(key, value); }, this);
+ }
+};
+
+goog.provide('ol.style.Text');
+
+
+goog.require('ol.style.Fill');
+
+
+/**
+ * @classdesc
+ * Set text style for vector features.
+ *
+ * @constructor
+ * @param {olx.style.TextOptions=} opt_options Options.
+ * @api
+ */
+ol.style.Text = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.font_ = options.font;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.rotation_ = options.rotation;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.scale_ = options.scale;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.text_ = options.text;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.textAlign_ = options.textAlign;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.textBaseline_ = options.textBaseline;
+
+ /**
+ * @private
+ * @type {ol.style.Fill}
+ */
+ this.fill_ = options.fill !== undefined ? options.fill :
+ new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_});
+
+ /**
+ * @private
+ * @type {ol.style.Stroke}
+ */
+ this.stroke_ = options.stroke !== undefined ? options.stroke : null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0;
+};
+
+
+/**
+ * The default fill color to use if no fill was set at construction time; a
+ * blackish `#333`.
+ *
+ * @const {string}
+ * @private
+ */
+ol.style.Text.DEFAULT_FILL_COLOR_ = '#333';
+
+
+/**
+ * Get the font name.
+ * @return {string|undefined} Font.
+ * @api
+ */
+ol.style.Text.prototype.getFont = function() {
+ return this.font_;
+};
+
+
+/**
+ * Get the x-offset for the text.
+ * @return {number} Horizontal text offset.
+ * @api
+ */
+ol.style.Text.prototype.getOffsetX = function() {
+ return this.offsetX_;
+};
+
+
+/**
+ * Get the y-offset for the text.
+ * @return {number} Vertical text offset.
+ * @api
+ */
+ol.style.Text.prototype.getOffsetY = function() {
+ return this.offsetY_;
+};
+
+
+/**
+ * Get the fill style for the text.
+ * @return {ol.style.Fill} Fill style.
+ * @api
+ */
+ol.style.Text.prototype.getFill = function() {
+ return this.fill_;
+};
+
+
+/**
+ * Get the text rotation.
+ * @return {number|undefined} Rotation.
+ * @api
+ */
+ol.style.Text.prototype.getRotation = function() {
+ return this.rotation_;
+};
+
+
+/**
+ * Get the text scale.
+ * @return {number|undefined} Scale.
+ * @api
+ */
+ol.style.Text.prototype.getScale = function() {
+ return this.scale_;
+};
+
+
+/**
+ * Get the stroke style for the text.
+ * @return {ol.style.Stroke} Stroke style.
+ * @api
+ */
+ol.style.Text.prototype.getStroke = function() {
+ return this.stroke_;
+};
+
+
+/**
+ * Get the text to be rendered.
+ * @return {string|undefined} Text.
+ * @api
+ */
+ol.style.Text.prototype.getText = function() {
+ return this.text_;
+};
+
+
+/**
+ * Get the text alignment.
+ * @return {string|undefined} Text align.
+ * @api
+ */
+ol.style.Text.prototype.getTextAlign = function() {
+ return this.textAlign_;
+};
+
+
+/**
+ * Get the text baseline.
+ * @return {string|undefined} Text baseline.
+ * @api
+ */
+ol.style.Text.prototype.getTextBaseline = function() {
+ return this.textBaseline_;
+};
+
+
+/**
+ * Set the font.
+ *
+ * @param {string|undefined} font Font.
+ * @api
+ */
+ol.style.Text.prototype.setFont = function(font) {
+ this.font_ = font;
+};
+
+
+/**
+ * Set the x offset.
+ *
+ * @param {number} offsetX Horizontal text offset.
+ * @api
+ */
+ol.style.Text.prototype.setOffsetX = function(offsetX) {
+ this.offsetX_ = offsetX;
+};
+
+
+/**
+ * Set the y offset.
+ *
+ * @param {number} offsetY Vertical text offset.
+ * @api
+ */
+ol.style.Text.prototype.setOffsetY = function(offsetY) {
+ this.offsetY_ = offsetY;
+};
+
+
+/**
+ * Set the fill.
+ *
+ * @param {ol.style.Fill} fill Fill style.
+ * @api
+ */
+ol.style.Text.prototype.setFill = function(fill) {
+ this.fill_ = fill;
+};
+
+
+/**
+ * Set the rotation.
+ *
+ * @param {number|undefined} rotation Rotation.
+ * @api
+ */
+ol.style.Text.prototype.setRotation = function(rotation) {
+ this.rotation_ = rotation;
+};
+
+
+/**
+ * Set the scale.
+ *
+ * @param {number|undefined} scale Scale.
+ * @api
+ */
+ol.style.Text.prototype.setScale = function(scale) {
+ this.scale_ = scale;
+};
+
+
+/**
+ * Set the stroke.
+ *
+ * @param {ol.style.Stroke} stroke Stroke style.
+ * @api
+ */
+ol.style.Text.prototype.setStroke = function(stroke) {
+ this.stroke_ = stroke;
+};
+
+
+/**
+ * Set the text.
+ *
+ * @param {string|undefined} text Text.
+ * @api
+ */
+ol.style.Text.prototype.setText = function(text) {
+ this.text_ = text;
+};
+
+
+/**
+ * Set the text alignment.
+ *
+ * @param {string|undefined} textAlign Text align.
+ * @api
+ */
+ol.style.Text.prototype.setTextAlign = function(textAlign) {
+ this.textAlign_ = textAlign;
+};
+
+
+/**
+ * Set the text baseline.
+ *
+ * @param {string|undefined} textBaseline Text baseline.
+ * @api
+ */
+ol.style.Text.prototype.setTextBaseline = function(textBaseline) {
+ this.textBaseline_ = textBaseline;
+};
+
+// FIXME http://earth.google.com/kml/1.0 namespace?
+// FIXME why does node.getAttribute return an unknown type?
+// FIXME serialize arbitrary feature properties
+// FIXME don't parse style if extractStyles is false
+
+goog.provide('ol.format.KML');
+
+goog.require('goog.Uri');
+goog.require('goog.asserts');
+goog.require('goog.object');
+goog.require('ol');
+goog.require('ol.Feature');
+goog.require('ol.array');
+goog.require('ol.color');
+goog.require('ol.format.Feature');
+goog.require('ol.format.XMLFeature');
+goog.require('ol.format.XSD');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryCollection');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.LinearRing');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.math');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.style.Fill');
+goog.require('ol.style.Icon');
+goog.require('ol.style.IconAnchorUnits');
+goog.require('ol.style.IconOrigin');
+goog.require('ol.style.Image');
+goog.require('ol.style.Stroke');
+goog.require('ol.style.Style');
+goog.require('ol.style.Text');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the KML format.
+ *
+ * @constructor
+ * @extends {ol.format.XMLFeature}
+ * @param {olx.format.KMLOptions=} opt_options Options.
+ * @api stable
+ */
+ol.format.KML = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.XMLFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get('EPSG:4326');
+
+ /**
+ * @private
+ * @type {Array.<ol.style.Style>}
+ */
+ this.defaultStyle_ = options.defaultStyle ?
+ options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.extractStyles_ = options.extractStyles !== undefined ?
+ options.extractStyles : true;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.writeStyles_ = options.writeStyles !== undefined ?
+ options.writeStyles : true;
+
+ /**
+ * @private
+ * @type {Object.<string, (Array.<ol.style.Style>|string)>}
+ */
+ this.sharedStyles_ = {};
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.showPointNames_ = options.showPointNames !== undefined ?
+ options.showPointNames : true;
+
+};
+ol.inherits(ol.format.KML, ol.format.XMLFeature);
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.KML.EXTENSIONS_ = ['.kml'];
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.KML.GX_NAMESPACE_URIS_ = [
+ 'http://www.google.com/kml/ext/2.2'
+];
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.KML.NAMESPACE_URIS_ = [
+ null,
+ 'http://earth.google.com/kml/2.0',
+ 'http://earth.google.com/kml/2.1',
+ 'http://earth.google.com/kml/2.2',
+ 'http://www.opengis.net/kml/2.2'
+];
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.KML.SCHEMA_LOCATION_ = 'http://www.opengis.net/kml/2.2 ' +
+ 'https://developers.google.com/kml/schema/kml22gx.xsd';
+
+
+/**
+ * @const
+ * @type {ol.Color}
+ * @private
+ */
+ol.format.KML.DEFAULT_COLOR_ = [255, 255, 255, 1];
+
+
+/**
+ * @const
+ * @type {ol.style.Fill}
+ * @private
+ */
+ol.format.KML.DEFAULT_FILL_STYLE_ = new ol.style.Fill({
+ color: ol.format.KML.DEFAULT_COLOR_
+});
+
+
+/**
+ * @const
+ * @type {ol.Size}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_ = [20, 2]; // FIXME maybe [8, 32] ?
+
+
+/**
+ * @const
+ * @type {ol.style.IconAnchorUnits}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ =
+ ol.style.IconAnchorUnits.PIXELS;
+
+
+/**
+ * @const
+ * @type {ol.style.IconAnchorUnits}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ =
+ ol.style.IconAnchorUnits.PIXELS;
+
+
+/**
+ * @const
+ * @type {ol.Size}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_ = [64, 64];
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ =
+ 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png';
+
+
+/**
+ * @const
+ * @type {number}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_ = 0.5;
+
+
+/**
+ * @const
+ * @type {ol.style.Image}
+ * @private
+ */
+ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({
+ anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_,
+ anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT,
+ anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_,
+ anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_,
+ crossOrigin: 'anonymous',
+ rotation: 0,
+ scale: ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_,
+ size: ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_,
+ src: ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_
+});
+
+
+/**
+ * @const
+ * @type {ol.style.Stroke}
+ * @private
+ */
+ol.format.KML.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({
+ color: ol.format.KML.DEFAULT_COLOR_,
+ width: 1
+});
+
+
+/**
+ * @const
+ * @type {ol.style.Stroke}
+ * @private
+ */
+ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_ = new ol.style.Stroke({
+ color: [51, 51, 51, 1],
+ width: 2
+});
+
+
+/**
+ * @const
+ * @type {ol.style.Text}
+ * @private
+ */
+ol.format.KML.DEFAULT_TEXT_STYLE_ = new ol.style.Text({
+ font: 'bold 16px Helvetica',
+ fill: ol.format.KML.DEFAULT_FILL_STYLE_,
+ stroke: ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_,
+ scale: 0.8
+});
+
+
+/**
+ * @const
+ * @type {ol.style.Style}
+ * @private
+ */
+ol.format.KML.DEFAULT_STYLE_ = new ol.style.Style({
+ fill: ol.format.KML.DEFAULT_FILL_STYLE_,
+ image: ol.format.KML.DEFAULT_IMAGE_STYLE_,
+ text: ol.format.KML.DEFAULT_TEXT_STYLE_,
+ stroke: ol.format.KML.DEFAULT_STROKE_STYLE_,
+ zIndex: 0
+});
+
+
+/**
+ * @const
+ * @type {Array.<ol.style.Style>}
+ * @private
+ */
+ol.format.KML.DEFAULT_STYLE_ARRAY_ = [ol.format.KML.DEFAULT_STYLE_];
+
+
+/**
+ * @const
+ * @type {Object.<string, ol.style.IconAnchorUnits>}
+ * @private
+ */
+ol.format.KML.ICON_ANCHOR_UNITS_MAP_ = {
+ 'fraction': ol.style.IconAnchorUnits.FRACTION,
+ 'pixels': ol.style.IconAnchorUnits.PIXELS
+};
+
+
+/**
+ * @param {ol.style.Style|undefined} foundStyle Style.
+ * @param {string} name Name.
+ * @return {ol.style.Style} style Style.
+ * @private
+ */
+ol.format.KML.createNameStyleFunction_ = function(foundStyle, name) {
+ var textStyle = null;
+ var textOffset = [0, 0];
+ var textAlign = 'start';
+ if (foundStyle.getImage()) {
+ var imageSize = foundStyle.getImage().getImageSize();
+ if (imageSize && imageSize.length == 2) {
+ // Offset the label to be centered to the right of the icon, if there is
+ // one.
+ textOffset[0] = foundStyle.getImage().getScale() * imageSize[0] / 2;
+ textOffset[1] = -foundStyle.getImage().getScale() * imageSize[1] / 2;
+ textAlign = 'left';
+ }
+ }
+ if (!ol.object.isEmpty(foundStyle.getText())) {
+ textStyle = /** @type {ol.style.Text} */
+ (goog.object.clone(foundStyle.getText()));
+ textStyle.setText(name);
+ textStyle.setTextAlign(textAlign);
+ textStyle.setOffsetX(textOffset[0]);
+ textStyle.setOffsetY(textOffset[1]);
+ } else {
+ textStyle = new ol.style.Text({
+ text: name,
+ offsetX: textOffset[0],
+ offsetY: textOffset[1],
+ textAlign: textAlign
+ });
+ }
+ var nameStyle = new ol.style.Style({
+ text: textStyle
+ });
+ return nameStyle;
+};
+
+
+/**
+ * @param {Array.<ol.style.Style>|undefined} style Style.
+ * @param {string} styleUrl Style URL.
+ * @param {Array.<ol.style.Style>} defaultStyle Default style.
+ * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles Shared
+ * styles.
+ * @param {boolean|undefined} showPointNames true to show names for point
+ * placemarks.
+ * @return {ol.FeatureStyleFunction} Feature style function.
+ * @private
+ */
+ol.format.KML.createFeatureStyleFunction_ = function(style, styleUrl,
+ defaultStyle, sharedStyles, showPointNames) {
+
+ return (
+ /**
+ * @param {number} resolution Resolution.
+ * @return {Array.<ol.style.Style>} Style.
+ * @this {ol.Feature}
+ */
+ function(resolution) {
+ var drawName = showPointNames;
+ /** @type {ol.style.Style|undefined} */
+ var nameStyle;
+ var name = '';
+ if (drawName) {
+ if (this.getGeometry()) {
+ drawName = (this.getGeometry().getType() ===
+ ol.geom.GeometryType.POINT);
+ }
+ }
+
+ if (drawName) {
+ name = /** @type {string} */ (this.get('name'));
+ drawName = drawName && name;
+ }
+
+ if (style) {
+ if (drawName) {
+ nameStyle = ol.format.KML.createNameStyleFunction_(style[0],
+ name);
+ return style.concat(nameStyle);
+ }
+ return style;
+ }
+ if (styleUrl) {
+ var foundStyle = ol.format.KML.findStyle_(styleUrl, defaultStyle,
+ sharedStyles);
+ if (drawName) {
+ nameStyle = ol.format.KML.createNameStyleFunction_(foundStyle[0],
+ name);
+ return foundStyle.concat(nameStyle);
+ }
+ return foundStyle;
+ }
+ if (drawName) {
+ nameStyle = ol.format.KML.createNameStyleFunction_(defaultStyle[0],
+ name);
+ return defaultStyle.concat(nameStyle);
+ }
+ return defaultStyle;
+ });
+};
+
+
+/**
+ * @param {Array.<ol.style.Style>|string|undefined} styleValue Style value.
+ * @param {Array.<ol.style.Style>} defaultStyle Default style.
+ * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles
+ * Shared styles.
+ * @return {Array.<ol.style.Style>} Style.
+ * @private
+ */
+ol.format.KML.findStyle_ = function(styleValue, defaultStyle, sharedStyles) {
+ if (Array.isArray(styleValue)) {
+ return styleValue;
+ } else if (typeof styleValue === 'string') {
+ // KML files in the wild occasionally forget the leading `#` on styleUrls
+ // defined in the same document. Add a leading `#` if it enables to find
+ // a style.
+ if (!(styleValue in sharedStyles) && ('#' + styleValue in sharedStyles)) {
+ styleValue = '#' + styleValue;
+ }
+ return ol.format.KML.findStyle_(
+ sharedStyles[styleValue], defaultStyle, sharedStyles);
+ } else {
+ return defaultStyle;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @private
+ * @return {ol.Color|undefined} Color.
+ */
+ol.format.KML.readColor_ = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ // The KML specification states that colors should not include a leading `#`
+ // but we tolerate them.
+ var m = /^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(s);
+ if (m) {
+ var hexColor = m[1];
+ return [
+ parseInt(hexColor.substr(6, 2), 16),
+ parseInt(hexColor.substr(4, 2), 16),
+ parseInt(hexColor.substr(2, 2), 16),
+ parseInt(hexColor.substr(0, 2), 16) / 255
+ ];
+
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @private
+ * @return {Array.<number>|undefined} Flat coordinates.
+ */
+ol.format.KML.readFlatCoordinates_ = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ var flatCoordinates = [];
+ // The KML specification states that coordinate tuples should not include
+ // spaces, but we tolerate them.
+ var re =
+ /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i;
+ var m;
+ while ((m = re.exec(s))) {
+ var x = parseFloat(m[1]);
+ var y = parseFloat(m[2]);
+ var z = m[3] ? parseFloat(m[3]) : 0;
+ flatCoordinates.push(x, y, z);
+ s = s.substr(m[0].length);
+ }
+ if (s !== '') {
+ return undefined;
+ }
+ return flatCoordinates;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @private
+ * @return {string|undefined} Style URL.
+ */
+ol.format.KML.readStyleUrl_ = function(node) {
+ var s = ol.xml.getAllTextContent(node, false).trim();
+ if (node.baseURI) {
+ return goog.Uri.resolve(node.baseURI, s).toString();
+ } else {
+ return s;
+ }
+
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @private
+ * @return {string} URI.
+ */
+ol.format.KML.readURI_ = function(node) {
+ var s = ol.xml.getAllTextContent(node, false);
+ if (node.baseURI) {
+ return goog.Uri.resolve(node.baseURI, s.trim()).toString();
+ } else {
+ return s.trim();
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @private
+ * @return {ol.KMLVec2_} Vec2.
+ */
+ol.format.KML.readVec2_ = function(node) {
+ var xunits = node.getAttribute('xunits');
+ var yunits = node.getAttribute('yunits');
+ return {
+ x: parseFloat(node.getAttribute('x')),
+ xunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[xunits],
+ y: parseFloat(node.getAttribute('y')),
+ yunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[yunits]
+ };
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @private
+ * @return {number|undefined} Scale.
+ */
+ol.format.KML.readScale_ = function(node) {
+ var number = ol.format.XSD.readDecimal(node);
+ if (number !== undefined) {
+ return Math.sqrt(number);
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<ol.style.Style>|string|undefined} StyleMap.
+ */
+ol.format.KML.readStyleMapValue_ = function(node, objectStack) {
+ return ol.xml.pushParseAndPop(undefined,
+ ol.format.KML.STYLE_MAP_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.IconStyleParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be an ELEMENT');
+ goog.asserts.assert(node.localName == 'IconStyle',
+ 'localName should be IconStyle');
+ // FIXME refreshMode
+ // FIXME refreshInterval
+ // FIXME viewRefreshTime
+ // FIXME viewBoundScale
+ // FIXME viewFormat
+ // FIXME httpQuery
+ var object = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.ICON_STYLE_PARSERS_, node, objectStack);
+ if (!object) {
+ return;
+ }
+ var styleObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(goog.isObject(styleObject),
+ 'styleObject should be an Object');
+ var IconObject = 'Icon' in object ? object['Icon'] : {};
+ var src;
+ var href = /** @type {string|undefined} */
+ (IconObject['href']);
+ if (href) {
+ src = href;
+ } else {
+ src = ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_;
+ }
+ var anchor, anchorXUnits, anchorYUnits;
+ var hotSpot = /** @type {ol.KMLVec2_|undefined} */
+ (object['hotSpot']);
+ if (hotSpot) {
+ anchor = [hotSpot.x, hotSpot.y];
+ anchorXUnits = hotSpot.xunits;
+ anchorYUnits = hotSpot.yunits;
+ } else if (src === ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) {
+ anchor = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_;
+ anchorXUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_;
+ anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_;
+ } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) {
+ anchor = [0.5, 0];
+ anchorXUnits = ol.style.IconAnchorUnits.FRACTION;
+ anchorYUnits = ol.style.IconAnchorUnits.FRACTION;
+ }
+
+ var offset;
+ var x = /** @type {number|undefined} */
+ (IconObject['x']);
+ var y = /** @type {number|undefined} */
+ (IconObject['y']);
+ if (x !== undefined && y !== undefined) {
+ offset = [x, y];
+ }
+
+ var size;
+ var w = /** @type {number|undefined} */
+ (IconObject['w']);
+ var h = /** @type {number|undefined} */
+ (IconObject['h']);
+ if (w !== undefined && h !== undefined) {
+ size = [w, h];
+ }
+
+ var rotation;
+ var heading = /** @type {number} */
+ (object['heading']);
+ if (heading !== undefined) {
+ rotation = ol.math.toRadians(heading);
+ }
+
+ var scale = /** @type {number|undefined} */
+ (object['scale']);
+ if (src == ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) {
+ size = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_;
+ if (scale === undefined) {
+ scale = ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_;
+ }
+ }
+
+ var imageStyle = new ol.style.Icon({
+ anchor: anchor,
+ anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT,
+ anchorXUnits: anchorXUnits,
+ anchorYUnits: anchorYUnits,
+ crossOrigin: 'anonymous', // FIXME should this be configurable?
+ offset: offset,
+ offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT,
+ rotation: rotation,
+ scale: scale,
+ size: size,
+ src: src
+ });
+ styleObject['imageStyle'] = imageStyle;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.LabelStyleParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LabelStyle',
+ 'localName should be LabelStyle');
+ // FIXME colorMode
+ var object = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.LABEL_STYLE_PARSERS_, node, objectStack);
+ if (!object) {
+ return;
+ }
+ var styleObject = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(styleObject),
+ 'styleObject should be an Object');
+ var textStyle = new ol.style.Text({
+ fill: new ol.style.Fill({
+ color: /** @type {ol.Color} */
+ ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_)
+ }),
+ scale: /** @type {number|undefined} */
+ (object['scale'])
+ });
+ styleObject['textStyle'] = textStyle;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.LineStyleParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LineStyle',
+ 'localName should be LineStyle');
+ // FIXME colorMode
+ // FIXME gx:outerColor
+ // FIXME gx:outerWidth
+ // FIXME gx:physicalWidth
+ // FIXME gx:labelVisibility
+ var object = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.LINE_STYLE_PARSERS_, node, objectStack);
+ if (!object) {
+ return;
+ }
+ var styleObject = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(styleObject),
+ 'styleObject should be an Object');
+ var strokeStyle = new ol.style.Stroke({
+ color: /** @type {ol.Color} */
+ ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_),
+ width: /** @type {number} */ ('width' in object ? object['width'] : 1)
+ });
+ styleObject['strokeStyle'] = strokeStyle;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.PolyStyleParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'PolyStyle',
+ 'localName should be PolyStyle');
+ // FIXME colorMode
+ var object = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.POLY_STYLE_PARSERS_, node, objectStack);
+ if (!object) {
+ return;
+ }
+ var styleObject = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(styleObject),
+ 'styleObject should be an Object');
+ var fillStyle = new ol.style.Fill({
+ color: /** @type {ol.Color} */
+ ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_)
+ });
+ styleObject['fillStyle'] = fillStyle;
+ var fill = /** @type {boolean|undefined} */ (object['fill']);
+ if (fill !== undefined) {
+ styleObject['fill'] = fill;
+ }
+ var outline =
+ /** @type {boolean|undefined} */ (object['outline']);
+ if (outline !== undefined) {
+ styleObject['outline'] = outline;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>} LinearRing flat coordinates.
+ */
+ol.format.KML.readFlatLinearRing_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LinearRing',
+ 'localName should be LinearRing');
+ return ol.xml.pushParseAndPop(null,
+ ol.format.KML.FLAT_LINEAR_RING_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.gxCoordParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(ol.array.includes(
+ ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI),
+ 'namespaceURI of the node should be known to the KML parser');
+ goog.asserts.assert(node.localName == 'coord', 'localName should be coord');
+ var gxTrackObject = /** @type {ol.KMLGxTrackObject_} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(goog.isObject(gxTrackObject),
+ 'gxTrackObject should be an Object');
+ var flatCoordinates = gxTrackObject.flatCoordinates;
+ var s = ol.xml.getAllTextContent(node, false);
+ var re =
+ /^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i;
+ var m = re.exec(s);
+ if (m) {
+ var x = parseFloat(m[1]);
+ var y = parseFloat(m[2]);
+ var z = parseFloat(m[3]);
+ flatCoordinates.push(x, y, z, 0);
+ } else {
+ flatCoordinates.push(0, 0, 0, 0);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.MultiLineString|undefined} MultiLineString.
+ */
+ol.format.KML.readGxMultiTrack_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(ol.array.includes(
+ ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI),
+ 'namespaceURI of the node should be known to the KML parser');
+ goog.asserts.assert(node.localName == 'MultiTrack',
+ 'localName should be MultiTrack');
+ var lineStrings = ol.xml.pushParseAndPop([],
+ ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_, node, objectStack);
+ if (!lineStrings) {
+ return undefined;
+ }
+ var multiLineString = new ol.geom.MultiLineString(null);
+ multiLineString.setLineStrings(lineStrings);
+ return multiLineString;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.LineString|undefined} LineString.
+ */
+ol.format.KML.readGxTrack_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(ol.array.includes(
+ ol.format.KML.GX_NAMESPACE_URIS_, node.namespaceURI),
+ 'namespaceURI of the node should be known to the KML parser');
+ goog.asserts.assert(node.localName == 'Track', 'localName should be Track');
+ var gxTrackObject = ol.xml.pushParseAndPop(
+ /** @type {ol.KMLGxTrackObject_} */ ({
+ flatCoordinates: [],
+ whens: []
+ }), ol.format.KML.GX_TRACK_PARSERS_, node, objectStack);
+ if (!gxTrackObject) {
+ return undefined;
+ }
+ var flatCoordinates = gxTrackObject.flatCoordinates;
+ var whens = gxTrackObject.whens;
+ goog.asserts.assert(flatCoordinates.length / 4 == whens.length,
+ 'the length of the flatCoordinates array divided by 4 should be the ' +
+ 'length of the whens array');
+ var i, ii;
+ for (i = 0, ii = Math.min(flatCoordinates.length, whens.length); i < ii;
+ ++i) {
+ flatCoordinates[4 * i + 3] = whens[i];
+ }
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);
+ return lineString;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object} Icon object.
+ */
+ol.format.KML.readIcon_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Icon', 'localName should be Icon');
+ var iconObject = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.ICON_PARSERS_, node, objectStack);
+ if (iconObject) {
+ return iconObject;
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.format.KML.readFlatCoordinatesFromNode_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return ol.xml.pushParseAndPop(null,
+ ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.LineString|undefined} LineString.
+ */
+ol.format.KML.readLineString_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LineString',
+ 'localName should be LineString');
+ var properties = ol.xml.pushParseAndPop({},
+ ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
+ objectStack);
+ var flatCoordinates =
+ ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);
+ if (flatCoordinates) {
+ var lineString = new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
+ lineString.setProperties(properties);
+ return lineString;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.Polygon|undefined} Polygon.
+ */
+ol.format.KML.readLinearRing_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'LinearRing',
+ 'localName should be LinearRing');
+ var properties = ol.xml.pushParseAndPop({},
+ ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
+ objectStack);
+ var flatCoordinates =
+ ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);
+ if (flatCoordinates) {
+ var polygon = new ol.geom.Polygon(null);
+ polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates,
+ [flatCoordinates.length]);
+ polygon.setProperties(properties);
+ return polygon;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.KML.readMultiGeometry_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MultiGeometry',
+ 'localName should be MultiGeometry');
+ var geometries = ol.xml.pushParseAndPop([],
+ ol.format.KML.MULTI_GEOMETRY_PARSERS_, node, objectStack);
+ if (!geometries) {
+ return null;
+ }
+ if (geometries.length === 0) {
+ return new ol.geom.GeometryCollection(geometries);
+ }
+ var homogeneous = true;
+ var type = geometries[0].getType();
+ var geometry, i, ii;
+ for (i = 1, ii = geometries.length; i < ii; ++i) {
+ geometry = geometries[i];
+ if (geometry.getType() != type) {
+ homogeneous = false;
+ break;
+ }
+ }
+ if (homogeneous) {
+ var layout;
+ var flatCoordinates;
+ if (type == ol.geom.GeometryType.POINT) {
+ var point = geometries[0];
+ goog.asserts.assertInstanceof(point, ol.geom.Point,
+ 'point should be an ol.geom.Point');
+ layout = point.getLayout();
+ flatCoordinates = point.getFlatCoordinates();
+ for (i = 1, ii = geometries.length; i < ii; ++i) {
+ geometry = geometries[i];
+ goog.asserts.assertInstanceof(geometry, ol.geom.Point,
+ 'geometry should be an ol.geom.Point');
+ goog.asserts.assert(geometry.getLayout() == layout,
+ 'geometry layout should be consistent');
+ ol.array.extend(flatCoordinates, geometry.getFlatCoordinates());
+ }
+ var multiPoint = new ol.geom.MultiPoint(null);
+ multiPoint.setFlatCoordinates(layout, flatCoordinates);
+ ol.format.KML.setCommonGeometryProperties_(multiPoint, geometries);
+ return multiPoint;
+ } else if (type == ol.geom.GeometryType.LINE_STRING) {
+ var multiLineString = new ol.geom.MultiLineString(null);
+ multiLineString.setLineStrings(geometries);
+ ol.format.KML.setCommonGeometryProperties_(multiLineString, geometries);
+ return multiLineString;
+ } else if (type == ol.geom.GeometryType.POLYGON) {
+ var multiPolygon = new ol.geom.MultiPolygon(null);
+ multiPolygon.setPolygons(geometries);
+ ol.format.KML.setCommonGeometryProperties_(multiPolygon, geometries);
+ return multiPolygon;
+ } else if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
+ return new ol.geom.GeometryCollection(geometries);
+ } else {
+ goog.asserts.fail('Unexpected type: ' + type);
+ return null;
+ }
+ } else {
+ return new ol.geom.GeometryCollection(geometries);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.Point|undefined} Point.
+ */
+ol.format.KML.readPoint_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Point', 'localName should be Point');
+ var properties = ol.xml.pushParseAndPop({},
+ ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
+ objectStack);
+ var flatCoordinates =
+ ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);
+ if (flatCoordinates) {
+ var point = new ol.geom.Point(null);
+ goog.asserts.assert(flatCoordinates.length == 3,
+ 'flatCoordinates should have a length of 3');
+ point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
+ point.setProperties(properties);
+ return point;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.geom.Polygon|undefined} Polygon.
+ */
+ol.format.KML.readPolygon_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Polygon',
+ 'localName should be Polygon');
+ var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}),
+ ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
+ objectStack);
+ var flatLinearRings = ol.xml.pushParseAndPop([null],
+ ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack);
+ if (flatLinearRings && flatLinearRings[0]) {
+ var polygon = new ol.geom.Polygon(null);
+ var flatCoordinates = flatLinearRings[0];
+ var ends = [flatCoordinates.length];
+ var i, ii;
+ for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
+ ol.array.extend(flatCoordinates, flatLinearRings[i]);
+ ends.push(flatCoordinates.length);
+ }
+ polygon.setFlatCoordinates(
+ ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
+ polygon.setProperties(properties);
+ return polygon;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<ol.style.Style>} Style.
+ */
+ol.format.KML.readStyle_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Style', 'localName should be Style');
+ var styleObject = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.STYLE_PARSERS_, node, objectStack);
+ if (!styleObject) {
+ return null;
+ }
+ var fillStyle = /** @type {ol.style.Fill} */
+ ('fillStyle' in styleObject ?
+ styleObject['fillStyle'] : ol.format.KML.DEFAULT_FILL_STYLE_);
+ var fill = /** @type {boolean|undefined} */ (styleObject['fill']);
+ if (fill !== undefined && !fill) {
+ fillStyle = null;
+ }
+ var imageStyle = /** @type {ol.style.Image} */
+ ('imageStyle' in styleObject ?
+ styleObject['imageStyle'] : ol.format.KML.DEFAULT_IMAGE_STYLE_);
+ var textStyle = /** @type {ol.style.Text} */
+ ('textStyle' in styleObject ?
+ styleObject['textStyle'] : ol.format.KML.DEFAULT_TEXT_STYLE_);
+ var strokeStyle = /** @type {ol.style.Stroke} */
+ ('strokeStyle' in styleObject ?
+ styleObject['strokeStyle'] : ol.format.KML.DEFAULT_STROKE_STYLE_);
+ var outline = /** @type {boolean|undefined} */
+ (styleObject['outline']);
+ if (outline !== undefined && !outline) {
+ strokeStyle = null;
+ }
+ return [new ol.style.Style({
+ fill: fillStyle,
+ image: imageStyle,
+ stroke: strokeStyle,
+ text: textStyle,
+ zIndex: undefined // FIXME
+ })];
+};
+
+
+/**
+ * Reads an array of geometries and creates arrays for common geometry
+ * properties. Then sets them to the multi geometry.
+ * @param {ol.geom.MultiPoint|ol.geom.MultiLineString|ol.geom.MultiPolygon}
+ * multiGeometry A multi-geometry.
+ * @param {Array.<ol.geom.Geometry>} geometries List of geometries.
+ * @private
+ */
+ol.format.KML.setCommonGeometryProperties_ = function(multiGeometry,
+ geometries) {
+ var ii = geometries.length;
+ var extrudes = new Array(geometries.length);
+ var altitudeModes = new Array(geometries.length);
+ var geometry, i, hasExtrude, hasAltitudeMode;
+ hasExtrude = hasAltitudeMode = false;
+ for (i = 0; i < ii; ++i) {
+ geometry = geometries[i];
+ extrudes[i] = geometry.get('extrude');
+ altitudeModes[i] = geometry.get('altitudeMode');
+ hasExtrude = hasExtrude || extrudes[i] !== undefined;
+ hasAltitudeMode = hasAltitudeMode || altitudeModes[i];
+ }
+ if (hasExtrude) {
+ multiGeometry.set('extrude', extrudes);
+ }
+ if (hasAltitudeMode) {
+ multiGeometry.set('altitudeMode', altitudeModes);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.DataParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Data', 'localName should be Data');
+ var name = node.getAttribute('name');
+ if (name !== null) {
+ var data = ol.xml.pushParseAndPop(
+ undefined, ol.format.KML.DATA_PARSERS_, node, objectStack);
+ if (data) {
+ var featureObject =
+ /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(goog.isObject(featureObject),
+ 'featureObject should be an Object');
+ featureObject[name] = data;
+ }
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.ExtendedDataParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ExtendedData',
+ 'localName should be ExtendedData');
+ ol.xml.parseNode(ol.format.KML.EXTENDED_DATA_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.PairDataParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Pair', 'localName should be Pair');
+ var pairObject = ol.xml.pushParseAndPop(
+ {}, ol.format.KML.PAIR_PARSERS_, node, objectStack);
+ if (!pairObject) {
+ return;
+ }
+ var key = /** @type {string|undefined} */
+ (pairObject['key']);
+ if (key && key == 'normal') {
+ var styleUrl = /** @type {string|undefined} */
+ (pairObject['styleUrl']);
+ if (styleUrl) {
+ objectStack[objectStack.length - 1] = styleUrl;
+ }
+ var Style = /** @type {ol.style.Style} */
+ (pairObject['Style']);
+ if (Style) {
+ objectStack[objectStack.length - 1] = Style;
+ }
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.PlacemarkStyleMapParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'StyleMap',
+ 'localName should be StyleMap');
+ var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack);
+ if (!styleMapValue) {
+ return;
+ }
+ var placemarkObject = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(placemarkObject),
+ 'placemarkObject should be an Object');
+ if (Array.isArray(styleMapValue)) {
+ placemarkObject['Style'] = styleMapValue;
+ } else if (typeof styleMapValue === 'string') {
+ placemarkObject['styleUrl'] = styleMapValue;
+ } else {
+ goog.asserts.fail('styleMapValue has an unknown type');
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.SchemaDataParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'SchemaData',
+ 'localName should be SchemaData');
+ ol.xml.parseNode(ol.format.KML.SCHEMA_DATA_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.SimpleDataParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'SimpleData',
+ 'localName should be SimpleData');
+ var name = node.getAttribute('name');
+ if (name !== null) {
+ var data = ol.format.XSD.readString(node);
+ var featureObject =
+ /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ featureObject[name] = data;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.innerBoundaryIsParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'innerBoundaryIs',
+ 'localName should be innerBoundaryIs');
+ /** @type {Array.<number>|undefined} */
+ var flatLinearRing = ol.xml.pushParseAndPop(undefined,
+ ol.format.KML.INNER_BOUNDARY_IS_PARSERS_, node, objectStack);
+ if (flatLinearRing) {
+ var flatLinearRings = /** @type {Array.<Array.<number>>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(flatLinearRings),
+ 'flatLinearRings should be an array');
+ goog.asserts.assert(flatLinearRings.length > 0,
+ 'flatLinearRings array should not be empty');
+ flatLinearRings.push(flatLinearRing);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.outerBoundaryIsParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'outerBoundaryIs',
+ 'localName should be outerBoundaryIs');
+ /** @type {Array.<number>|undefined} */
+ var flatLinearRing = ol.xml.pushParseAndPop(undefined,
+ ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_, node, objectStack);
+ if (flatLinearRing) {
+ var flatLinearRings = /** @type {Array.<Array.<number>>} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(Array.isArray(flatLinearRings),
+ 'flatLinearRings should be an array');
+ goog.asserts.assert(flatLinearRings.length > 0,
+ 'flatLinearRings array should not be empty');
+ flatLinearRings[0] = flatLinearRing;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.LinkParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Link', 'localName should be Link');
+ ol.xml.parseNode(ol.format.KML.LINK_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.whenParser_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'when', 'localName should be when');
+ var gxTrackObject = /** @type {ol.KMLGxTrackObject_} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(goog.isObject(gxTrackObject),
+ 'gxTrackObject should be an Object');
+ var whens = gxTrackObject.whens;
+ var s = ol.xml.getAllTextContent(node, false);
+ var re =
+ /^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/;
+ var m = re.exec(s);
+ if (m) {
+ var year = parseInt(m[1], 10);
+ var month = m[3] ? parseInt(m[3], 10) - 1 : 0;
+ var day = m[5] ? parseInt(m[5], 10) : 1;
+ var hour = m[7] ? parseInt(m[7], 10) : 0;
+ var minute = m[8] ? parseInt(m[8], 10) : 0;
+ var second = m[9] ? parseInt(m[9], 10) : 0;
+ var when = Date.UTC(year, month, day, hour, minute, second);
+ if (m[10] && m[10] != 'Z') {
+ var sign = m[11] == '-' ? -1 : 1;
+ when += sign * 60 * parseInt(m[12], 10);
+ if (m[13]) {
+ when += sign * 60 * 60 * parseInt(m[13], 10);
+ }
+ }
+ whens.push(when);
+ } else {
+ whens.push(0);
+ }
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.DATA_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'value': ol.xml.makeReplacer(ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.EXTENDED_DATA_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Data': ol.format.KML.DataParser_,
+ 'SchemaData': ol.format.KML.SchemaDataParser_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'extrude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
+ 'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.FLAT_LINEAR_RING_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'innerBoundaryIs': ol.format.KML.innerBoundaryIsParser_,
+ 'outerBoundaryIs': ol.format.KML.outerBoundaryIsParser_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.GX_TRACK_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'when': ol.format.KML.whenParser_
+ }, ol.xml.makeStructureNS(
+ ol.format.KML.GX_NAMESPACE_URIS_, {
+ 'coord': ol.format.KML.gxCoordParser_
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.ICON_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)
+ }, ol.xml.makeStructureNS(
+ ol.format.KML.GX_NAMESPACE_URIS_, {
+ 'x': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'y': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'w': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'h': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.ICON_STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Icon': ol.xml.makeObjectPropertySetter(ol.format.KML.readIcon_),
+ 'heading': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
+ 'hotSpot': ol.xml.makeObjectPropertySetter(ol.format.KML.readVec2_),
+ 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.INNER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.LABEL_STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),
+ 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.LINE_STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),
+ 'width': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.MULTI_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'LineString': ol.xml.makeArrayPusher(ol.format.KML.readLineString_),
+ 'LinearRing': ol.xml.makeArrayPusher(ol.format.KML.readLinearRing_),
+ 'MultiGeometry': ol.xml.makeArrayPusher(ol.format.KML.readMultiGeometry_),
+ 'Point': ol.xml.makeArrayPusher(ol.format.KML.readPoint_),
+ 'Polygon': ol.xml.makeArrayPusher(ol.format.KML.readPolygon_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.GX_NAMESPACE_URIS_, {
+ 'Track': ol.xml.makeArrayPusher(ol.format.KML.readGxTrack_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.NETWORK_LINK_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'ExtendedData': ol.format.KML.ExtendedDataParser_,
+ 'Link': ol.format.KML.LinkParser_,
+ 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
+ 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.LINK_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.PAIR_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_),
+ 'key': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyleUrl_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.PLACEMARK_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'ExtendedData': ol.format.KML.ExtendedDataParser_,
+ 'MultiGeometry': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readMultiGeometry_, 'geometry'),
+ 'LineString': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readLineString_, 'geometry'),
+ 'LinearRing': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readLinearRing_, 'geometry'),
+ 'Point': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readPoint_, 'geometry'),
+ 'Polygon': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readPolygon_, 'geometry'),
+ 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_),
+ 'StyleMap': ol.format.KML.PlacemarkStyleMapParser_,
+ 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
+ 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_),
+ 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)
+ }, ol.xml.makeStructureNS(
+ ol.format.KML.GX_NAMESPACE_URIS_, {
+ 'MultiTrack': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readGxMultiTrack_, 'geometry'),
+ 'Track': ol.xml.makeObjectPropertySetter(
+ ol.format.KML.readGxTrack_, 'geometry')
+ }
+ ));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.POLY_STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),
+ 'fill': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
+ 'outline': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.SCHEMA_DATA_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'SimpleData': ol.format.KML.SimpleDataParser_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'IconStyle': ol.format.KML.IconStyleParser_,
+ 'LabelStyle': ol.format.KML.LabelStyleParser_,
+ 'LineStyle': ol.format.KML.LineStyleParser_,
+ 'PolyStyle': ol.format.KML.PolyStyleParser_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.KML.STYLE_MAP_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Pair': ol.format.KML.PairDataParser_
+ });
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.KML.prototype.getExtensions = function() {
+ return ol.format.KML.EXTENSIONS_;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<ol.Feature>|undefined} Features.
+ */
+ol.format.KML.prototype.readDocumentOrFolder_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ var localName = node.localName;
+ goog.asserts.assert(localName == 'Document' || localName == 'Folder',
+ 'localName should be Document or Folder');
+ // FIXME use scope somehow
+ var parsersNS = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Document': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this),
+ 'Folder': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this),
+ 'Placemark': ol.xml.makeArrayPusher(this.readPlacemark_, this),
+ 'Style': this.readSharedStyle_.bind(this),
+ 'StyleMap': this.readSharedStyleMap_.bind(this)
+ });
+ /** @type {Array.<ol.Feature>} */
+ var features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack, this);
+ if (features) {
+ return features;
+ } else {
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {ol.Feature|undefined} Feature.
+ */
+ol.format.KML.prototype.readPlacemark_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Placemark',
+ 'localName should be Placemark');
+ var object = ol.xml.pushParseAndPop({'geometry': null},
+ ol.format.KML.PLACEMARK_PARSERS_, node, objectStack);
+ if (!object) {
+ return undefined;
+ }
+ var feature = new ol.Feature();
+ var id = node.getAttribute('id');
+ if (id !== null) {
+ feature.setId(id);
+ }
+ var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
+
+ var geometry = object['geometry'];
+ if (geometry) {
+ ol.format.Feature.transformWithOptions(geometry, false, options);
+ }
+ feature.setGeometry(geometry);
+ delete object['geometry'];
+
+ if (this.extractStyles_) {
+ var style = object['Style'];
+ var styleUrl = object['styleUrl'];
+ var styleFunction = ol.format.KML.createFeatureStyleFunction_(
+ style, styleUrl, this.defaultStyle_, this.sharedStyles_,
+ this.showPointNames_);
+ feature.setStyle(styleFunction);
+ }
+ delete object['Style'];
+ // we do not remove the styleUrl property from the object, so it
+ // gets stored on feature when setProperties is called
+
+ feature.setProperties(object);
+
+ return feature;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Style', 'localName should be Style');
+ var id = node.getAttribute('id');
+ if (id !== null) {
+ var style = ol.format.KML.readStyle_(node, objectStack);
+ if (style) {
+ var styleUri;
+ if (node.baseURI) {
+ styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString();
+ } else {
+ styleUri = '#' + id;
+ }
+ this.sharedStyles_[styleUri] = style;
+ }
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'StyleMap',
+ 'localName should be StyleMap');
+ var id = node.getAttribute('id');
+ if (id === null) {
+ return;
+ }
+ var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack);
+ if (!styleMapValue) {
+ return;
+ }
+ var styleUri;
+ if (node.baseURI) {
+ styleUri = goog.Uri.resolve(node.baseURI, '#' + id).toString();
+ } else {
+ styleUri = '#' + id;
+ }
+ this.sharedStyles_[styleUri] = styleMapValue;
+};
+
+
+/**
+ * Read the first feature from a KML source. MultiGeometries are converted into
+ * GeometryCollections if they are a mix of geometry types, and into MultiPoint/
+ * MultiLineString/MultiPolygon if they are all of the same type.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api stable
+ */
+ol.format.KML.prototype.readFeature;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.KML.prototype.readFeatureFromNode = function(node, opt_options) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) {
+ return null;
+ }
+ goog.asserts.assert(node.localName == 'Placemark',
+ 'localName should be Placemark');
+ var feature = this.readPlacemark_(
+ node, [this.getReadOptions(node, opt_options)]);
+ if (feature) {
+ return feature;
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * Read all features from a KML source. MultiGeometries are converted into
+ * GeometryCollections if they are a mix of geometry types, and into MultiPoint/
+ * MultiLineString/MultiPolygon if they are all of the same type.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.KML.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) {
+ return [];
+ }
+ var features;
+ var localName = node.localName;
+ if (localName == 'Document' || localName == 'Folder') {
+ features = this.readDocumentOrFolder_(
+ node, [this.getReadOptions(node, opt_options)]);
+ if (features) {
+ return features;
+ } else {
+ return [];
+ }
+ } else if (localName == 'Placemark') {
+ var feature = this.readPlacemark_(
+ node, [this.getReadOptions(node, opt_options)]);
+ if (feature) {
+ return [feature];
+ } else {
+ return [];
+ }
+ } else if (localName == 'kml') {
+ features = [];
+ var n;
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ var fs = this.readFeaturesFromNode(n, opt_options);
+ if (fs) {
+ ol.array.extend(features, fs);
+ }
+ }
+ return features;
+ } else {
+ return [];
+ }
+};
+
+
+/**
+ * Read the name of the KML.
+ *
+ * @param {Document|Node|string} source Souce.
+ * @return {string|undefined} Name.
+ * @api stable
+ */
+ol.format.KML.prototype.readName = function(source) {
+ if (ol.xml.isDocument(source)) {
+ return this.readNameFromDocument(/** @type {Document} */ (source));
+ } else if (ol.xml.isNode(source)) {
+ return this.readNameFromNode(/** @type {Node} */ (source));
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readNameFromDocument(doc);
+ } else {
+ goog.asserts.fail('Unknown type for source');
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {string|undefined} Name.
+ */
+ol.format.KML.prototype.readNameFromDocument = function(doc) {
+ var n;
+ for (n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ var name = this.readNameFromNode(n);
+ if (name) {
+ return name;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {string|undefined} Name.
+ */
+ol.format.KML.prototype.readNameFromNode = function(node) {
+ var n;
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
+ n.localName == 'name') {
+ return ol.format.XSD.readString(n);
+ }
+ }
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ var localName = n.localName;
+ if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
+ (localName == 'Document' ||
+ localName == 'Folder' ||
+ localName == 'Placemark' ||
+ localName == 'kml')) {
+ var name = this.readNameFromNode(n);
+ if (name) {
+ return name;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * Read the network links of the KML.
+ *
+ * @param {Document|Node|string} source Source.
+ * @return {Array.<Object>} Network links.
+ * @api
+ */
+ol.format.KML.prototype.readNetworkLinks = function(source) {
+ var networkLinks = [];
+ if (ol.xml.isDocument(source)) {
+ ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(
+ /** @type {Document} */ (source)));
+ } else if (ol.xml.isNode(source)) {
+ ol.array.extend(networkLinks, this.readNetworkLinksFromNode(
+ /** @type {Node} */ (source)));
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc));
+ } else {
+ goog.asserts.fail('unknown type for source');
+ }
+ return networkLinks;
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {Array.<Object>} Network links.
+ */
+ol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) {
+ var n, networkLinks = [];
+ for (n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n));
+ }
+ }
+ return networkLinks;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {Array.<Object>} Network links.
+ */
+ol.format.KML.prototype.readNetworkLinksFromNode = function(node) {
+ var n, networkLinks = [];
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
+ n.localName == 'NetworkLink') {
+ var obj = ol.xml.pushParseAndPop({}, ol.format.KML.NETWORK_LINK_PARSERS_,
+ n, []);
+ networkLinks.push(obj);
+ }
+ }
+ for (n = node.firstElementChild; n; n = n.nextElementSibling) {
+ var localName = n.localName;
+ if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
+ (localName == 'Document' ||
+ localName == 'Folder' ||
+ localName == 'kml')) {
+ ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n));
+ }
+ }
+ return networkLinks;
+};
+
+
+/**
+ * Read the projection from a KML source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.KML.prototype.readProjection;
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the color to.
+ * @param {ol.Color|string} color Color.
+ * @private
+ */
+ol.format.KML.writeColorTextNode_ = function(node, color) {
+ var rgba = ol.color.asArray(color);
+ var opacity = (rgba.length == 4) ? rgba[3] : 1;
+ var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]];
+ var i;
+ for (i = 0; i < 4; ++i) {
+ var hex = parseInt(abgr[i], 10).toString(16);
+ abgr[i] = (hex.length == 1) ? '0' + hex : hex;
+ }
+ ol.format.XSD.writeStringTextNode(node, abgr.join(''));
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the coordinates to.
+ * @param {Array.<number>} coordinates Coordinates.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeCoordinatesTextNode_ = function(node, coordinates, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+
+ var layout = context['layout'];
+ var stride = context['stride'];
+
+ var dimension;
+ if (layout == ol.geom.GeometryLayout.XY ||
+ layout == ol.geom.GeometryLayout.XYM) {
+ dimension = 2;
+ } else if (layout == ol.geom.GeometryLayout.XYZ ||
+ layout == ol.geom.GeometryLayout.XYZM) {
+ dimension = 3;
+ } else {
+ goog.asserts.fail('Unknown geometry layout');
+ }
+
+ var d, i;
+ var ii = coordinates.length;
+ var text = '';
+ if (ii > 0) {
+ text += coordinates[0];
+ for (d = 1; d < dimension; ++d) {
+ text += ',' + coordinates[d];
+ }
+ for (i = stride; i < ii; i += stride) {
+ text += ' ' + coordinates[i];
+ for (d = 1; d < dimension; ++d) {
+ text += ',' + coordinates[i + d];
+ }
+ }
+ }
+ ol.format.XSD.writeStringTextNode(node, text);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {Array.<*>} objectStack Object stack.
+ * @this {ol.format.KML}
+ * @private
+ */
+ol.format.KML.writeDocument_ = function(node, features, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_,
+ ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack, undefined,
+ this);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Object} icon Icon object.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeIcon_ = function(node, icon, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(icon, orderedKeys);
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
+ values, objectStack, orderedKeys);
+ orderedKeys =
+ ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]];
+ values = ol.xml.makeSequence(icon, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_,
+ ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.style.Icon} style Icon style.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeIconStyle_ = function(node, style, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ var properties = {};
+ var src = style.getSrc();
+ var size = style.getSize();
+ var iconImageSize = style.getImageSize();
+ var iconProperties = {
+ 'href': src
+ };
+
+ if (size) {
+ iconProperties['w'] = size[0];
+ iconProperties['h'] = size[1];
+ var anchor = style.getAnchor(); // top-left
+ var origin = style.getOrigin(); // top-left
+
+ if (origin && iconImageSize && origin[0] !== 0 && origin[1] !== size[1]) {
+ iconProperties['x'] = origin[0];
+ iconProperties['y'] = iconImageSize[1] - (origin[1] + size[1]);
+ }
+
+ if (anchor && anchor[0] !== 0 && anchor[1] !== size[1]) {
+ var /** @type {ol.KMLVec2_} */ hotSpot = {
+ x: anchor[0],
+ xunits: ol.style.IconAnchorUnits.PIXELS,
+ y: size[1] - anchor[1],
+ yunits: ol.style.IconAnchorUnits.PIXELS
+ };
+ properties['hotSpot'] = hotSpot;
+ }
+ }
+
+ properties['Icon'] = iconProperties;
+
+ var scale = style.getScale();
+ if (scale !== 1) {
+ properties['scale'] = scale;
+ }
+
+ var rotation = style.getRotation();
+ if (rotation !== 0) {
+ properties['heading'] = rotation; // 0-360
+ }
+
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.style.Text} style style.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeLabelStyle_ = function(node, style, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ var properties = {};
+ var fill = style.getFill();
+ if (fill) {
+ properties['color'] = fill.getColor();
+ }
+ var scale = style.getScale();
+ if (scale && scale !== 1) {
+ properties['scale'] = scale;
+ }
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys =
+ ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.style.Stroke} style style.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeLineStyle_ = function(node, style, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ var properties = {
+ 'color': style.getColor(),
+ 'width': style.getWidth()
+ };
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeMultiGeometry_ = function(node, geometry, objectStack) {
+ goog.asserts.assert(
+ (geometry instanceof ol.geom.GeometryCollection) ||
+ (geometry instanceof ol.geom.MultiPoint) ||
+ (geometry instanceof ol.geom.MultiLineString) ||
+ (geometry instanceof ol.geom.MultiPolygon),
+ 'geometry should be one of: ol.geom.GeometryCollection, ' +
+ 'ol.geom.MultiPoint, ol.geom.MultiLineString or ol.geom.MultiPolygon');
+ /** @type {ol.XmlNodeStackItem} */
+ var context = {node: node};
+ var type = geometry.getType();
+ /** @type {Array.<ol.geom.Geometry>} */
+ var geometries;
+ /** @type {function(*, Array.<*>, string=): (Node|undefined)} */
+ var factory;
+ if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
+ geometries = geometry.getGeometries();
+ factory = ol.format.KML.GEOMETRY_NODE_FACTORY_;
+ } else if (type == ol.geom.GeometryType.MULTI_POINT) {
+ geometries =
+ (/** @type {ol.geom.MultiPoint} */ (geometry)).getPoints();
+ factory = ol.format.KML.POINT_NODE_FACTORY_;
+ } else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) {
+ geometries =
+ (/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings();
+ factory = ol.format.KML.LINE_STRING_NODE_FACTORY_;
+ } else if (type == ol.geom.GeometryType.MULTI_POLYGON) {
+ geometries =
+ (/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons();
+ factory = ol.format.KML.POLYGON_NODE_FACTORY_;
+ } else {
+ goog.asserts.fail('Unknown geometry type: ' + type);
+ }
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory,
+ geometries, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.LinearRing} linearRing Linear ring.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.KML.BOUNDARY_IS_SERIALIZERS_,
+ ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack);
+};
+
+
+/**
+ * FIXME currently we do serialize arbitrary/custom feature properties
+ * (ExtendedData).
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Object stack.
+ * @this {ol.format.KML}
+ * @private
+ */
+ol.format.KML.writePlacemark_ = function(node, feature, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+
+ // set id
+ if (feature.getId()) {
+ node.setAttribute('id', feature.getId());
+ }
+
+ // serialize properties (properties unknown to KML are not serialized)
+ var properties = feature.getProperties();
+
+ var styleFunction = feature.getStyleFunction();
+ if (styleFunction) {
+ // FIXME the styles returned by the style function are supposed to be
+ // resolution-independent here
+ var styles = styleFunction.call(feature, 0);
+ if (styles) {
+ var style = Array.isArray(styles) ? styles[0] : styles;
+ if (this.writeStyles_) {
+ properties['Style'] = style;
+ }
+ var textStyle = style.getText();
+ if (textStyle) {
+ properties['name'] = textStyle.getText();
+ }
+ }
+ }
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
+
+ // serialize geometry
+ var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ geometry =
+ ol.format.Feature.transformWithOptions(geometry, true, options);
+ }
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
+ ol.format.KML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.SimpleGeometry} geometry Geometry.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) {
+ goog.asserts.assert(
+ (geometry instanceof ol.geom.Point) ||
+ (geometry instanceof ol.geom.LineString) ||
+ (geometry instanceof ol.geom.LinearRing),
+ 'geometry should be one of ol.geom.Point, ol.geom.LineString ' +
+ 'or ol.geom.LinearRing');
+ var flatCoordinates = geometry.getFlatCoordinates();
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ context['layout'] = geometry.getLayout();
+ context['stride'] = geometry.getStride();
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_,
+ ol.format.KML.COORDINATES_NODE_FACTORY_,
+ [flatCoordinates], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.geom.Polygon} polygon Polygon.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writePolygon_ = function(node, polygon, objectStack) {
+ goog.asserts.assertInstanceof(polygon, ol.geom.Polygon,
+ 'polygon should be an ol.geom.Polygon');
+ var linearRings = polygon.getLinearRings();
+ goog.asserts.assert(linearRings.length > 0,
+ 'linearRings should not be empty');
+ var outerRing = linearRings.shift();
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ // inner rings
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.KML.POLYGON_SERIALIZERS_,
+ ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_,
+ linearRings, objectStack);
+ // outer ring
+ ol.xml.pushSerializeAndPop(context,
+ ol.format.KML.POLYGON_SERIALIZERS_,
+ ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_,
+ [outerRing], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.style.Fill} style Style.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writePolyStyle_ = function(node, style, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_,
+ ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the scale to.
+ * @param {number|undefined} scale Scale.
+ * @private
+ */
+ol.format.KML.writeScaleTextNode_ = function(node, scale) {
+ // the Math is to remove any excess decimals created by float arithmetic
+ ol.format.XSD.writeDecimalTextNode(node,
+ Math.round(scale * scale * 1e6) / 1e6);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.style.Style} style Style.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.KML.writeStyle_ = function(node, style, objectStack) {
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
+ var properties = {};
+ var fillStyle = style.getFill();
+ var strokeStyle = style.getStroke();
+ var imageStyle = style.getImage();
+ var textStyle = style.getText();
+ if (imageStyle instanceof ol.style.Icon) {
+ properties['IconStyle'] = imageStyle;
+ }
+ if (textStyle) {
+ properties['LabelStyle'] = textStyle;
+ }
+ if (strokeStyle) {
+ properties['LineStyle'] = strokeStyle;
+ }
+ if (fillStyle) {
+ properties['PolyStyle'] = fillStyle;
+ }
+ var parentNode = objectStack[objectStack.length - 1].node;
+ var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
+};
+
+
+/**
+ * @param {Node} node Node to append a TextNode with the Vec2 to.
+ * @param {ol.KMLVec2_} vec2 Vec2.
+ * @private
+ */
+ol.format.KML.writeVec2_ = function(node, vec2) {
+ node.setAttribute('x', vec2.x);
+ node.setAttribute('y', vec2.y);
+ node.setAttribute('xunits', vec2.xunits);
+ node.setAttribute('yunits', vec2.yunits);
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'Document', 'Placemark'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_),
+ 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, string>}
+ * @private
+ */
+ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = {
+ 'Point': 'Point',
+ 'LineString': 'LineString',
+ 'LinearRing': 'LinearRing',
+ 'Polygon': 'Polygon',
+ 'MultiPoint': 'MultiGeometry',
+ 'MultiLineString': 'MultiGeometry',
+ 'MultiPolygon': 'MultiGeometry',
+ 'GeometryCollection': 'MultiGeometry'
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'href'
+ ],
+ ol.xml.makeStructureNS(ol.format.KML.GX_NAMESPACE_URIS_, [
+ 'x', 'y', 'w', 'h'
+ ]));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
+ }, ol.xml.makeStructureNS(
+ ol.format.KML.GX_NAMESPACE_URIS_, {
+ 'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'scale', 'heading', 'Icon', 'hotSpot'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_),
+ 'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
+ 'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_),
+ 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'color', 'scale'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),
+ 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'color', 'width'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),
+ 'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'LinearRing': ol.xml.makeChildAppender(
+ ol.format.KML.writePrimitiveGeometry_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'LineString': ol.xml.makeChildAppender(
+ ol.format.KML.writePrimitiveGeometry_),
+ 'Point': ol.xml.makeChildAppender(
+ ol.format.KML.writePrimitiveGeometry_),
+ 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),
+ 'GeometryCollection': ol.xml.makeChildAppender(
+ ol.format.KML.writeMultiGeometry_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'name', 'open', 'visibility', 'address', 'phoneNumber', 'description',
+ 'styleUrl', 'Style'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'MultiGeometry': ol.xml.makeChildAppender(
+ ol.format.KML.writeMultiGeometry_),
+ 'LineString': ol.xml.makeChildAppender(
+ ol.format.KML.writePrimitiveGeometry_),
+ 'LinearRing': ol.xml.makeChildAppender(
+ ol.format.KML.writePrimitiveGeometry_),
+ 'Point': ol.xml.makeChildAppender(
+ ol.format.KML.writePrimitiveGeometry_),
+ 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),
+ 'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_),
+ 'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'description': ol.xml.makeChildAppender(
+ ol.format.XSD.writeStringTextNode),
+ 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'open': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode),
+ 'phoneNumber': ol.xml.makeChildAppender(
+ ol.format.XSD.writeStringTextNode),
+ 'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
+ 'visibility': ol.xml.makeChildAppender(
+ ol.format.XSD.writeBooleanTextNode)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'coordinates': ol.xml.makeChildAppender(
+ ol.format.KML.writeCoordinatesTextNode_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'outerBoundaryIs': ol.xml.makeChildAppender(
+ ol.format.KML.writeBoundaryIs_),
+ 'innerBoundaryIs': ol.xml.makeChildAppender(
+ ol.format.KML.writeBoundaryIs_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Array.<string>>}
+ * @private
+ */
+ol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, [
+ 'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle'
+ ]);
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
+ ol.format.KML.NAMESPACE_URIS_, {
+ 'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_),
+ 'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_),
+ 'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_),
+ 'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_)
+ });
+
+
+/**
+ * @const
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node|undefined} Node.
+ * @private
+ */
+ol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
+ return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0],
+ 'gx:' + opt_nodeName);
+};
+
+
+/**
+ * @const
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node|undefined} Node.
+ * @private
+ */
+ol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack,
+ opt_nodeName) {
+ goog.asserts.assertInstanceof(value, ol.Feature,
+ 'value should be an ol.Feature');
+ var parentNode = objectStack[objectStack.length - 1].node;
+ goog.asserts.assert(ol.xml.isNode(parentNode),
+ 'parentNode should be an XML node');
+ return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark');
+};
+
+
+/**
+ * @const
+ * @param {*} value Value.
+ * @param {Array.<*>} objectStack Object stack.
+ * @param {string=} opt_nodeName Node name.
+ * @return {Node|undefined} Node.
+ * @private
+ */
+ol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack,
+ opt_nodeName) {
+ if (value) {
+ goog.asserts.assertInstanceof(value, ol.geom.Geometry,
+ 'value should be an ol.geom.Geometry');
+ var parentNode = objectStack[objectStack.length - 1].node;
+ goog.asserts.assert(ol.xml.isNode(parentNode),
+ 'parentNode should be an XML node');
+ return ol.xml.createElementNS(parentNode.namespaceURI,
+ ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[value.getType()]);
+ }
+};
+
+
+/**
+ * A factory for creating coordinates nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color');
+
+
+/**
+ * A factory for creating coordinates nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.COORDINATES_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('coordinates');
+
+
+/**
+ * A factory for creating innerBoundaryIs nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('innerBoundaryIs');
+
+
+/**
+ * A factory for creating Point nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.POINT_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('Point');
+
+
+/**
+ * A factory for creating LineString nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.LINE_STRING_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('LineString');
+
+
+/**
+ * A factory for creating LinearRing nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.LINEAR_RING_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('LinearRing');
+
+
+/**
+ * A factory for creating Polygon nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.POLYGON_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('Polygon');
+
+
+/**
+ * A factory for creating outerBoundaryIs nodes.
+ * @const
+ * @type {function(*, Array.<*>, string=): (Node|undefined)}
+ * @private
+ */
+ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ =
+ ol.xml.makeSimpleNodeFactory('outerBoundaryIs');
+
+
+/**
+ * Encode an array of features in the KML format. GeometryCollections, MultiPoints,
+ * MultiLineStrings, and MultiPolygons are output as MultiGeometries.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {string} Result.
+ * @api stable
+ */
+ol.format.KML.prototype.writeFeatures;
+
+
+/**
+ * Encode an array of features in the KML format as an XML node. GeometryCollections,
+ * MultiPoints, MultiLineStrings, and MultiPolygons are output as MultiGeometries.
+ *
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Options.
+ * @return {Node} Node.
+ * @api
+ */
+ol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) {
+ opt_options = this.adaptOptions(opt_options);
+ var kml = ol.xml.createElementNS(ol.format.KML.NAMESPACE_URIS_[4], 'kml');
+ var xmlnsUri = 'http://www.w3.org/2000/xmlns/';
+ var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance';
+ ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:gx',
+ ol.format.KML.GX_NAMESPACE_URIS_[0]);
+ ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri);
+ ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation',
+ ol.format.KML.SCHEMA_LOCATION_);
+
+ var /** @type {ol.XmlNodeStackItem} */ context = {node: kml};
+ var properties = {};
+ if (features.length > 1) {
+ properties['Document'] = features;
+ } else if (features.length == 1) {
+ properties['Placemark'] = features[0];
+ }
+ var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI];
+ var values = ol.xml.makeSequence(properties, orderedKeys);
+ ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_,
+ ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [opt_options], orderedKeys,
+ this);
+ return kml;
+};
+
+goog.provide('ol.ext.pbf');
+/** @typedef {function(*)} */
+ol.ext.pbf;
+(function() {
+var exports = {};
+var module = {exports: exports};
+var define;
+/**
+ * @fileoverview
+ * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pbf = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+'use strict';
+
+// lightweight Buffer shim for pbf browser build
+// based on code from github.com/feross/buffer (MIT-licensed)
+
+module.exports = Buffer;
+
+var ieee754 = _dereq_('ieee754');
+
+var BufferMethods;
+
+function Buffer(length) {
+ var arr;
+ if (length && length.length) {
+ arr = length;
+ length = arr.length;
+ }
+ var buf = new Uint8Array(length || 0);
+ if (arr) buf.set(arr);
+
+ buf.readUInt32LE = BufferMethods.readUInt32LE;
+ buf.writeUInt32LE = BufferMethods.writeUInt32LE;
+ buf.readInt32LE = BufferMethods.readInt32LE;
+ buf.writeInt32LE = BufferMethods.writeInt32LE;
+ buf.readFloatLE = BufferMethods.readFloatLE;
+ buf.writeFloatLE = BufferMethods.writeFloatLE;
+ buf.readDoubleLE = BufferMethods.readDoubleLE;
+ buf.writeDoubleLE = BufferMethods.writeDoubleLE;
+ buf.toString = BufferMethods.toString;
+ buf.write = BufferMethods.write;
+ buf.slice = BufferMethods.slice;
+ buf.copy = BufferMethods.copy;
+
+ buf._isBuffer = true;
+ return buf;
+}
+
+var lastStr, lastStrEncoded;
+
+BufferMethods = {
+ readUInt32LE: function(pos) {
+ return ((this[pos]) |
+ (this[pos + 1] << 8) |
+ (this[pos + 2] << 16)) +
+ (this[pos + 3] * 0x1000000);
+ },
+
+ writeUInt32LE: function(val, pos) {
+ this[pos] = val;
+ this[pos + 1] = (val >>> 8);
+ this[pos + 2] = (val >>> 16);
+ this[pos + 3] = (val >>> 24);
+ },
+
+ readInt32LE: function(pos) {
+ return ((this[pos]) |
+ (this[pos + 1] << 8) |
+ (this[pos + 2] << 16)) +
+ (this[pos + 3] << 24);
+ },
+
+ readFloatLE: function(pos) { return ieee754.read(this, pos, true, 23, 4); },
+ readDoubleLE: function(pos) { return ieee754.read(this, pos, true, 52, 8); },
+
+ writeFloatLE: function(val, pos) { return ieee754.write(this, val, pos, true, 23, 4); },
+ writeDoubleLE: function(val, pos) { return ieee754.write(this, val, pos, true, 52, 8); },
+
+ toString: function(encoding, start, end) {
+ var str = '',
+ tmp = '';
+
+ start = start || 0;
+ end = Math.min(this.length, end || this.length);
+
+ for (var i = start; i < end; i++) {
+ var ch = this[i];
+ if (ch <= 0x7F) {
+ str += decodeURIComponent(tmp) + String.fromCharCode(ch);
+ tmp = '';
+ } else {
+ tmp += '%' + ch.toString(16);
+ }
+ }
+
+ str += decodeURIComponent(tmp);
+
+ return str;
+ },
+
+ write: function(str, pos) {
+ var bytes = str === lastStr ? lastStrEncoded : encodeString(str);
+ for (var i = 0; i < bytes.length; i++) {
+ this[pos + i] = bytes[i];
+ }
+ },
+
+ slice: function(start, end) {
+ return this.subarray(start, end);
+ },
+
+ copy: function(buf, pos) {
+ pos = pos || 0;
+ for (var i = 0; i < this.length; i++) {
+ buf[pos + i] = this[i];
+ }
+ }
+};
+
+BufferMethods.writeInt32LE = BufferMethods.writeUInt32LE;
+
+Buffer.byteLength = function(str) {
+ lastStr = str;
+ lastStrEncoded = encodeString(str);
+ return lastStrEncoded.length;
+};
+
+Buffer.isBuffer = function(buf) {
+ return !!(buf && buf._isBuffer);
+};
+
+function encodeString(str) {
+ var length = str.length,
+ bytes = [];
+
+ for (var i = 0, c, lead; i < length; i++) {
+ c = str.charCodeAt(i); // code point
+
+ if (c > 0xD7FF && c < 0xE000) {
+
+ if (lead) {
+ if (c < 0xDC00) {
+ bytes.push(0xEF, 0xBF, 0xBD);
+ lead = c;
+ continue;
+
+ } else {
+ c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
+ lead = null;
+ }
+
+ } else {
+ if (c > 0xDBFF || (i + 1 === length)) bytes.push(0xEF, 0xBF, 0xBD);
+ else lead = c;
+
+ continue;
+ }
+
+ } else if (lead) {
+ bytes.push(0xEF, 0xBF, 0xBD);
+ lead = null;
+ }
+
+ if (c < 0x80) bytes.push(c);
+ else if (c < 0x800) bytes.push(c >> 0x6 | 0xC0, c & 0x3F | 0x80);
+ else if (c < 0x10000) bytes.push(c >> 0xC | 0xE0, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80);
+ else bytes.push(c >> 0x12 | 0xF0, c >> 0xC & 0x3F | 0x80, c >> 0x6 & 0x3F | 0x80, c & 0x3F | 0x80);
+ }
+ return bytes;
+}
+
+},{"ieee754":3}],2:[function(_dereq_,module,exports){
+(function (global){
+'use strict';
+
+module.exports = Pbf;
+
+var Buffer = global.Buffer || _dereq_('./buffer');
+
+function Pbf(buf) {
+ this.buf = !Buffer.isBuffer(buf) ? new Buffer(buf || 0) : buf;
+ this.pos = 0;
+ this.length = this.buf.length;
+}
+
+Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
+Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
+Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
+Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
+
+var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
+ SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32,
+ POW_2_63 = Math.pow(2, 63);
+
+Pbf.prototype = {
+
+ destroy: function() {
+ this.buf = null;
+ },
+
+ // === READING =================================================================
+
+ readFields: function(readField, result, end) {
+ end = end || this.length;
+
+ while (this.pos < end) {
+ var val = this.readVarint(),
+ tag = val >> 3,
+ startPos = this.pos;
+
+ readField(tag, result, this);
+
+ if (this.pos === startPos) this.skip(val);
+ }
+ return result;
+ },
+
+ readMessage: function(readField, result) {
+ return this.readFields(readField, result, this.readVarint() + this.pos);
+ },
+
+ readFixed32: function() {
+ var val = this.buf.readUInt32LE(this.pos);
+ this.pos += 4;
+ return val;
+ },
+
+ readSFixed32: function() {
+ var val = this.buf.readInt32LE(this.pos);
+ this.pos += 4;
+ return val;
+ },
+
+ // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
+
+ readFixed64: function() {
+ var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32;
+ this.pos += 8;
+ return val;
+ },
+
+ readSFixed64: function() {
+ var val = this.buf.readUInt32LE(this.pos) + this.buf.readInt32LE(this.pos + 4) * SHIFT_LEFT_32;
+ this.pos += 8;
+ return val;
+ },
+
+ readFloat: function() {
+ var val = this.buf.readFloatLE(this.pos);
+ this.pos += 4;
+ return val;
+ },
+
+ readDouble: function() {
+ var val = this.buf.readDoubleLE(this.pos);
+ this.pos += 8;
+ return val;
+ },
+
+ readVarint: function() {
+ var buf = this.buf,
+ val, b;
+
+ b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val;
+ b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val;
+ b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val;
+ b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val;
+
+ return readVarintRemainder(val, this);
+ },
+
+ readVarint64: function() {
+ var startPos = this.pos,
+ val = this.readVarint();
+
+ if (val < POW_2_63) return val;
+
+ var pos = this.pos - 2;
+ while (this.buf[pos] === 0xff) pos--;
+ if (pos < startPos) pos = startPos;
+
+ val = 0;
+ for (var i = 0; i < pos - startPos + 1; i++) {
+ var b = ~this.buf[startPos + i] & 0x7f;
+ val += i < 4 ? b << i * 7 : b * Math.pow(2, i * 7);
+ }
+
+ return -val - 1;
+ },
+
+ readSVarint: function() {
+ var num = this.readVarint();
+ return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
+ },
+
+ readBoolean: function() {
+ return Boolean(this.readVarint());
+ },
+
+ readString: function() {
+ var end = this.readVarint() + this.pos,
+ str = this.buf.toString('utf8', this.pos, end);
+ this.pos = end;
+ return str;
+ },
+
+ readBytes: function() {
+ var end = this.readVarint() + this.pos,
+ buffer = this.buf.slice(this.pos, end);
+ this.pos = end;
+ return buffer;
+ },
+
+ // verbose for performance reasons; doesn't affect gzipped size
+
+ readPackedVarint: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readVarint());
+ return arr;
+ },
+ readPackedSVarint: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readSVarint());
+ return arr;
+ },
+ readPackedBoolean: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readBoolean());
+ return arr;
+ },
+ readPackedFloat: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readFloat());
+ return arr;
+ },
+ readPackedDouble: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readDouble());
+ return arr;
+ },
+ readPackedFixed32: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readFixed32());
+ return arr;
+ },
+ readPackedSFixed32: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readSFixed32());
+ return arr;
+ },
+ readPackedFixed64: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readFixed64());
+ return arr;
+ },
+ readPackedSFixed64: function() {
+ var end = this.readVarint() + this.pos, arr = [];
+ while (this.pos < end) arr.push(this.readSFixed64());
+ return arr;
+ },
+
+ skip: function(val) {
+ var type = val & 0x7;
+ if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {}
+ else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;
+ else if (type === Pbf.Fixed32) this.pos += 4;
+ else if (type === Pbf.Fixed64) this.pos += 8;
+ else throw new Error('Unimplemented type: ' + type);
+ },
+
+ // === WRITING =================================================================
+
+ writeTag: function(tag, type) {
+ this.writeVarint((tag << 3) | type);
+ },
+
+ realloc: function(min) {
+ var length = this.length || 16;
+
+ while (length < this.pos + min) length *= 2;
+
+ if (length !== this.length) {
+ var buf = new Buffer(length);
+ this.buf.copy(buf);
+ this.buf = buf;
+ this.length = length;
+ }
+ },
+
+ finish: function() {
+ this.length = this.pos;
+ this.pos = 0;
+ return this.buf.slice(0, this.length);
+ },
+
+ writeFixed32: function(val) {
+ this.realloc(4);
+ this.buf.writeUInt32LE(val, this.pos);
+ this.pos += 4;
+ },
+
+ writeSFixed32: function(val) {
+ this.realloc(4);
+ this.buf.writeInt32LE(val, this.pos);
+ this.pos += 4;
+ },
+
+ writeFixed64: function(val) {
+ this.realloc(8);
+ this.buf.writeInt32LE(val & -1, this.pos);
+ this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
+ this.pos += 8;
+ },
+
+ writeSFixed64: function(val) {
+ this.realloc(8);
+ this.buf.writeInt32LE(val & -1, this.pos);
+ this.buf.writeInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
+ this.pos += 8;
+ },
+
+ writeVarint: function(val) {
+ val = +val;
+
+ if (val > 0xfffffff) {
+ writeBigVarint(val, this);
+ return;
+ }
+
+ this.realloc(4);
+
+ this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
+ this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
+ this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
+ this.buf[this.pos++] = (val >>> 7) & 0x7f;
+ },
+
+ writeSVarint: function(val) {
+ this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
+ },
+
+ writeBoolean: function(val) {
+ this.writeVarint(Boolean(val));
+ },
+
+ writeString: function(str) {
+ str = String(str);
+ var bytes = Buffer.byteLength(str);
+ this.writeVarint(bytes);
+ this.realloc(bytes);
+ this.buf.write(str, this.pos);
+ this.pos += bytes;
+ },
+
+ writeFloat: function(val) {
+ this.realloc(4);
+ this.buf.writeFloatLE(val, this.pos);
+ this.pos += 4;
+ },
+
+ writeDouble: function(val) {
+ this.realloc(8);
+ this.buf.writeDoubleLE(val, this.pos);
+ this.pos += 8;
+ },
+
+ writeBytes: function(buffer) {
+ var len = buffer.length;
+ this.writeVarint(len);
+ this.realloc(len);
+ for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];
+ },
+
+ writeRawMessage: function(fn, obj) {
+ this.pos++; // reserve 1 byte for short message length
+
+ // write the message directly to the buffer and see how much was written
+ var startPos = this.pos;
+ fn(obj, this);
+ var len = this.pos - startPos;
+
+ if (len >= 0x80) reallocForRawMessage(startPos, len, this);
+
+ // finally, write the message length in the reserved place and restore the position
+ this.pos = startPos - 1;
+ this.writeVarint(len);
+ this.pos += len;
+ },
+
+ writeMessage: function(tag, fn, obj) {
+ this.writeTag(tag, Pbf.Bytes);
+ this.writeRawMessage(fn, obj);
+ },
+
+ writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); },
+ writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); },
+ writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); },
+ writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); },
+ writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); },
+ writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); },
+ writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); },
+ writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); },
+ writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); },
+
+ writeBytesField: function(tag, buffer) {
+ this.writeTag(tag, Pbf.Bytes);
+ this.writeBytes(buffer);
+ },
+ writeFixed32Field: function(tag, val) {
+ this.writeTag(tag, Pbf.Fixed32);
+ this.writeFixed32(val);
+ },
+ writeSFixed32Field: function(tag, val) {
+ this.writeTag(tag, Pbf.Fixed32);
+ this.writeSFixed32(val);
+ },
+ writeFixed64Field: function(tag, val) {
+ this.writeTag(tag, Pbf.Fixed64);
+ this.writeFixed64(val);
+ },
+ writeSFixed64Field: function(tag, val) {
+ this.writeTag(tag, Pbf.Fixed64);
+ this.writeSFixed64(val);
+ },
+ writeVarintField: function(tag, val) {
+ this.writeTag(tag, Pbf.Varint);
+ this.writeVarint(val);
+ },
+ writeSVarintField: function(tag, val) {
+ this.writeTag(tag, Pbf.Varint);
+ this.writeSVarint(val);
+ },
+ writeStringField: function(tag, str) {
+ this.writeTag(tag, Pbf.Bytes);
+ this.writeString(str);
+ },
+ writeFloatField: function(tag, val) {
+ this.writeTag(tag, Pbf.Fixed32);
+ this.writeFloat(val);
+ },
+ writeDoubleField: function(tag, val) {
+ this.writeTag(tag, Pbf.Fixed64);
+ this.writeDouble(val);
+ },
+ writeBooleanField: function(tag, val) {
+ this.writeVarintField(tag, Boolean(val));
+ }
+};
+
+function readVarintRemainder(val, pbf) {
+ var buf = pbf.buf, b;
+
+ b = buf[pbf.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val;
+ b = buf[pbf.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val;
+ b = buf[pbf.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val;
+ b = buf[pbf.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val;
+ b = buf[pbf.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val;
+ b = buf[pbf.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val;
+
+ throw new Error('Expected varint not more than 10 bytes');
+}
+
+function writeBigVarint(val, pbf) {
+ pbf.realloc(10);
+
+ var maxPos = pbf.pos + 10;
+
+ while (val >= 1) {
+ if (pbf.pos >= maxPos) throw new Error('Given varint doesn\'t fit into 10 bytes');
+ var b = val & 0xff;
+ pbf.buf[pbf.pos++] = b | (val >= 0x80 ? 0x80 : 0);
+ val /= 0x80;
+ }
+}
+
+function reallocForRawMessage(startPos, len, pbf) {
+ var extraLen =
+ len <= 0x3fff ? 1 :
+ len <= 0x1fffff ? 2 :
+ len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7));
+
+ // if 1 byte isn't enough for encoding message length, shift the data to the right
+ pbf.realloc(extraLen);
+ for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];
+}
+
+function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); }
+function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); }
+function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); }
+function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); }
+function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); }
+function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); }
+function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); }
+function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); }
+function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); }
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"./buffer":1}],3:[function(_dereq_,module,exports){
+exports.read = function (buffer, offset, isLE, mLen, nBytes) {
+ var e, m
+ var eLen = nBytes * 8 - mLen - 1
+ var eMax = (1 << eLen) - 1
+ var eBias = eMax >> 1
+ var nBits = -7
+ var i = isLE ? (nBytes - 1) : 0
+ var d = isLE ? -1 : 1
+ var s = buffer[offset + i]
+
+ i += d
+
+ e = s & ((1 << (-nBits)) - 1)
+ s >>= (-nBits)
+ nBits += eLen
+ for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
+
+ m = e & ((1 << (-nBits)) - 1)
+ e >>= (-nBits)
+ nBits += mLen
+ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
+
+ if (e === 0) {
+ e = 1 - eBias
+ } else if (e === eMax) {
+ return m ? NaN : ((s ? -1 : 1) * Infinity)
+ } else {
+ m = m + Math.pow(2, mLen)
+ e = e - eBias
+ }
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
+}
+
+exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
+ var e, m, c
+ var eLen = nBytes * 8 - mLen - 1
+ var eMax = (1 << eLen) - 1
+ var eBias = eMax >> 1
+ var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
+ var i = isLE ? 0 : (nBytes - 1)
+ var d = isLE ? 1 : -1
+ var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
+
+ value = Math.abs(value)
+
+ if (isNaN(value) || value === Infinity) {
+ m = isNaN(value) ? 1 : 0
+ e = eMax
+ } else {
+ e = Math.floor(Math.log(value) / Math.LN2)
+ if (value * (c = Math.pow(2, -e)) < 1) {
+ e--
+ c *= 2
+ }
+ if (e + eBias >= 1) {
+ value += rt / c
+ } else {
+ value += rt * Math.pow(2, 1 - eBias)
+ }
+ if (value * c >= 2) {
+ e++
+ c /= 2
+ }
+
+ if (e + eBias >= eMax) {
+ m = 0
+ e = eMax
+ } else if (e + eBias >= 1) {
+ m = (value * c - 1) * Math.pow(2, mLen)
+ e = e + eBias
+ } else {
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
+ e = 0
+ }
+ }
+
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
+
+ e = (e << mLen) | m
+ eLen += mLen
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
+
+ buffer[offset + i - d] |= s * 128
+}
+
+},{}]},{},[2])(2)
+});
+ol.ext.pbf = module.exports;
+})();
+
+goog.provide('ol.ext.vectortile');
+/** @typedef {function(*)} */
+ol.ext.vectortile;
+(function() {
+var exports = {};
+var module = {exports: exports};
+var define;
+/**
+ * @fileoverview
+ * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vectortile = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+module.exports.VectorTile = _dereq_('./lib/vectortile.js');
+module.exports.VectorTileFeature = _dereq_('./lib/vectortilefeature.js');
+module.exports.VectorTileLayer = _dereq_('./lib/vectortilelayer.js');
+
+},{"./lib/vectortile.js":2,"./lib/vectortilefeature.js":3,"./lib/vectortilelayer.js":4}],2:[function(_dereq_,module,exports){
+'use strict';
+
+var VectorTileLayer = _dereq_('./vectortilelayer');
+
+module.exports = VectorTile;
+
+function VectorTile(pbf, end) {
+ this.layers = pbf.readFields(readTile, {}, end);
+}
+
+function readTile(tag, layers, pbf) {
+ if (tag === 3) {
+ var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
+ if (layer.length) layers[layer.name] = layer;
+ }
+}
+
+
+},{"./vectortilelayer":4}],3:[function(_dereq_,module,exports){
+'use strict';
+
+var Point = _dereq_('point-geometry');
+
+module.exports = VectorTileFeature;
+
+function VectorTileFeature(pbf, end, extent, keys, values) {
+ // Public
+ this.properties = {};
+ this.extent = extent;
+ this.type = 0;
+
+ // Private
+ this._pbf = pbf;
+ this._geometry = -1;
+ this._keys = keys;
+ this._values = values;
+
+ pbf.readFields(readFeature, this, end);
+}
+
+function readFeature(tag, feature, pbf) {
+ if (tag == 1) feature._id = pbf.readVarint();
+ else if (tag == 2) readTag(pbf, feature);
+ else if (tag == 3) feature.type = pbf.readVarint();
+ else if (tag == 4) feature._geometry = pbf.pos;
+}
+
+function readTag(pbf, feature) {
+ var end = pbf.readVarint() + pbf.pos;
+
+ while (pbf.pos < end) {
+ var key = feature._keys[pbf.readVarint()],
+ value = feature._values[pbf.readVarint()];
+ feature.properties[key] = value;
+ }
+}
+
+VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
+
+VectorTileFeature.prototype.loadGeometry = function() {
+ var pbf = this._pbf;
+ pbf.pos = this._geometry;
+
+ var end = pbf.readVarint() + pbf.pos,
+ cmd = 1,
+ length = 0,
+ x = 0,
+ y = 0,
+ lines = [],
+ line;
+
+ while (pbf.pos < end) {
+ if (!length) {
+ var cmdLen = pbf.readVarint();
+ cmd = cmdLen & 0x7;
+ length = cmdLen >> 3;
+ }
+
+ length--;
+
+ if (cmd === 1 || cmd === 2) {
+ x += pbf.readSVarint();
+ y += pbf.readSVarint();
+
+ if (cmd === 1) { // moveTo
+ if (line) lines.push(line);
+ line = [];
+ }
+
+ line.push(new Point(x, y));
+
+ } else if (cmd === 7) {
+
+ // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
+ if (line) {
+ line.push(line[0].clone()); // closePolygon
+ }
+
+ } else {
+ throw new Error('unknown command ' + cmd);
+ }
+ }
+
+ if (line) lines.push(line);
+
+ return lines;
+};
+
+VectorTileFeature.prototype.bbox = function() {
+ var pbf = this._pbf;
+ pbf.pos = this._geometry;
+
+ var end = pbf.readVarint() + pbf.pos,
+ cmd = 1,
+ length = 0,
+ x = 0,
+ y = 0,
+ x1 = Infinity,
+ x2 = -Infinity,
+ y1 = Infinity,
+ y2 = -Infinity;
+
+ while (pbf.pos < end) {
+ if (!length) {
+ var cmdLen = pbf.readVarint();
+ cmd = cmdLen & 0x7;
+ length = cmdLen >> 3;
+ }
+
+ length--;
+
+ if (cmd === 1 || cmd === 2) {
+ x += pbf.readSVarint();
+ y += pbf.readSVarint();
+ if (x < x1) x1 = x;
+ if (x > x2) x2 = x;
+ if (y < y1) y1 = y;
+ if (y > y2) y2 = y;
+
+ } else if (cmd !== 7) {
+ throw new Error('unknown command ' + cmd);
+ }
+ }
+
+ return [x1, y1, x2, y2];
+};
+
+VectorTileFeature.prototype.toGeoJSON = function(x, y, z) {
+ var size = this.extent * Math.pow(2, z),
+ x0 = this.extent * x,
+ y0 = this.extent * y,
+ coords = this.loadGeometry(),
+ type = VectorTileFeature.types[this.type],
+ i, j;
+
+ function project(line) {
+ for (var j = 0; j < line.length; j++) {
+ var p = line[j], y2 = 180 - (p.y + y0) * 360 / size;
+ line[j] = [
+ (p.x + x0) * 360 / size - 180,
+ 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
+ ];
+ }
+ }
+
+ switch (this.type) {
+ case 1:
+ var points = [];
+ for (i = 0; i < coords.length; i++) {
+ points[i] = coords[i][0];
+ }
+ coords = points;
+ project(coords);
+ break;
+
+ case 2:
+ for (i = 0; i < coords.length; i++) {
+ project(coords[i]);
+ }
+ break;
+
+ case 3:
+ coords = classifyRings(coords);
+ for (i = 0; i < coords.length; i++) {
+ for (j = 0; j < coords[i].length; j++) {
+ project(coords[i][j]);
+ }
+ }
+ break;
+ }
+
+ if (coords.length === 1) {
+ coords = coords[0];
+ } else {
+ type = 'Multi' + type;
+ }
+
+ var result = {
+ type: "Feature",
+ geometry: {
+ type: type,
+ coordinates: coords
+ },
+ properties: this.properties
+ };
+
+ if ('_id' in this) {
+ result.id = this._id;
+ }
+
+ return result;
+};
+
+// classifies an array of rings into polygons with outer rings and holes
+
+function classifyRings(rings) {
+ var len = rings.length;
+
+ if (len <= 1) return [rings];
+
+ var polygons = [],
+ polygon,
+ ccw;
+
+ for (var i = 0; i < len; i++) {
+ var area = signedArea(rings[i]);
+ if (area === 0) continue;
+
+ if (ccw === undefined) ccw = area < 0;
+
+ if (ccw === area < 0) {
+ if (polygon) polygons.push(polygon);
+ polygon = [rings[i]];
+
+ } else {
+ polygon.push(rings[i]);
+ }
+ }
+ if (polygon) polygons.push(polygon);
+
+ return polygons;
+}
+
+function signedArea(ring) {
+ var sum = 0;
+ for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
+ p1 = ring[i];
+ p2 = ring[j];
+ sum += (p2.x - p1.x) * (p1.y + p2.y);
+ }
+ return sum;
+}
+
+},{"point-geometry":5}],4:[function(_dereq_,module,exports){
+'use strict';
+
+var VectorTileFeature = _dereq_('./vectortilefeature.js');
+
+module.exports = VectorTileLayer;
+
+function VectorTileLayer(pbf, end) {
+ // Public
+ this.version = 1;
+ this.name = null;
+ this.extent = 4096;
+ this.length = 0;
+
+ // Private
+ this._pbf = pbf;
+ this._keys = [];
+ this._values = [];
+ this._features = [];
+
+ pbf.readFields(readLayer, this, end);
+
+ this.length = this._features.length;
+}
+
+function readLayer(tag, layer, pbf) {
+ if (tag === 15) layer.version = pbf.readVarint();
+ else if (tag === 1) layer.name = pbf.readString();
+ else if (tag === 5) layer.extent = pbf.readVarint();
+ else if (tag === 2) layer._features.push(pbf.pos);
+ else if (tag === 3) layer._keys.push(pbf.readString());
+ else if (tag === 4) layer._values.push(readValueMessage(pbf));
+}
+
+function readValueMessage(pbf) {
+ var value = null,
+ end = pbf.readVarint() + pbf.pos;
+
+ while (pbf.pos < end) {
+ var tag = pbf.readVarint() >> 3;
+
+ value = tag === 1 ? pbf.readString() :
+ tag === 2 ? pbf.readFloat() :
+ tag === 3 ? pbf.readDouble() :
+ tag === 4 ? pbf.readVarint64() :
+ tag === 5 ? pbf.readVarint() :
+ tag === 6 ? pbf.readSVarint() :
+ tag === 7 ? pbf.readBoolean() : null;
+ }
+
+ return value;
+}
+
+// return feature `i` from this layer as a `VectorTileFeature`
+VectorTileLayer.prototype.feature = function(i) {
+ if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
+
+ this._pbf.pos = this._features[i];
+
+ var end = this._pbf.readVarint() + this._pbf.pos;
+ return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
+};
+
+},{"./vectortilefeature.js":3}],5:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = Point;
+
+function Point(x, y) {
+ this.x = x;
+ this.y = y;
+}
+
+Point.prototype = {
+ clone: function() { return new Point(this.x, this.y); },
+
+ add: function(p) { return this.clone()._add(p); },
+ sub: function(p) { return this.clone()._sub(p); },
+ mult: function(k) { return this.clone()._mult(k); },
+ div: function(k) { return this.clone()._div(k); },
+ rotate: function(a) { return this.clone()._rotate(a); },
+ matMult: function(m) { return this.clone()._matMult(m); },
+ unit: function() { return this.clone()._unit(); },
+ perp: function() { return this.clone()._perp(); },
+ round: function() { return this.clone()._round(); },
+
+ mag: function() {
+ return Math.sqrt(this.x * this.x + this.y * this.y);
+ },
+
+ equals: function(p) {
+ return this.x === p.x &&
+ this.y === p.y;
+ },
+
+ dist: function(p) {
+ return Math.sqrt(this.distSqr(p));
+ },
+
+ distSqr: function(p) {
+ var dx = p.x - this.x,
+ dy = p.y - this.y;
+ return dx * dx + dy * dy;
+ },
+
+ angle: function() {
+ return Math.atan2(this.y, this.x);
+ },
+
+ angleTo: function(b) {
+ return Math.atan2(this.y - b.y, this.x - b.x);
+ },
+
+ angleWith: function(b) {
+ return this.angleWithSep(b.x, b.y);
+ },
+
+ // Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ.
+ angleWithSep: function(x, y) {
+ return Math.atan2(
+ this.x * y - this.y * x,
+ this.x * x + this.y * y);
+ },
+
+ _matMult: function(m) {
+ var x = m[0] * this.x + m[1] * this.y,
+ y = m[2] * this.x + m[3] * this.y;
+ this.x = x;
+ this.y = y;
+ return this;
+ },
+
+ _add: function(p) {
+ this.x += p.x;
+ this.y += p.y;
+ return this;
+ },
+
+ _sub: function(p) {
+ this.x -= p.x;
+ this.y -= p.y;
+ return this;
+ },
+
+ _mult: function(k) {
+ this.x *= k;
+ this.y *= k;
+ return this;
+ },
+
+ _div: function(k) {
+ this.x /= k;
+ this.y /= k;
+ return this;
+ },
+
+ _unit: function() {
+ this._div(this.mag());
+ return this;
+ },
+
+ _perp: function() {
+ var y = this.y;
+ this.y = this.x;
+ this.x = -y;
+ return this;
+ },
+
+ _rotate: function(angle) {
+ var cos = Math.cos(angle),
+ sin = Math.sin(angle),
+ x = cos * this.x - sin * this.y,
+ y = sin * this.x + cos * this.y;
+ this.x = x;
+ this.y = y;
+ return this;
+ },
+
+ _round: function() {
+ this.x = Math.round(this.x);
+ this.y = Math.round(this.y);
+ return this;
+ }
+};
+
+// constructs Point from an array if necessary
+Point.convert = function (a) {
+ if (a instanceof Point) {
+ return a;
+ }
+ if (Array.isArray(a)) {
+ return new Point(a[0], a[1]);
+ }
+ return a;
+};
+
+},{}]},{},[1])(1)
+});
+ol.ext.vectortile = module.exports;
+})();
+
+//FIXME Implement projection handling
+
+goog.provide('ol.format.MVT');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.ext.pbf');
+goog.require('ol.ext.vectortile');
+goog.require('ol.format.Feature');
+goog.require('ol.format.FormatType');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.proj');
+goog.require('ol.proj.Projection');
+goog.require('ol.proj.Units');
+goog.require('ol.render.Feature');
+
+
+/**
+ * @classdesc
+ * Feature format for reading data in the Mapbox MVT format.
+ *
+ * @constructor
+ * @extends {ol.format.Feature}
+ * @param {olx.format.MVTOptions=} opt_options Options.
+ * @api
+ */
+ol.format.MVT = function(opt_options) {
+
+ ol.format.Feature.call(this);
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @type {ol.proj.Projection}
+ */
+ this.defaultDataProjection = new ol.proj.Projection({
+ code: '',
+ units: ol.proj.Units.TILE_PIXELS
+ });
+
+ /**
+ * @private
+ * @type {function((ol.geom.Geometry|Object.<string, *>)=)|
+ * function(ol.geom.GeometryType,Array.<number>,
+ * (Array.<number>|Array.<Array.<number>>),Object.<string, *>)}
+ */
+ this.featureClass_ = options.featureClass ?
+ options.featureClass : ol.render.Feature;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.geometryName_ = options.geometryName ?
+ options.geometryName : 'geometry';
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.layerName_ = options.layerName ? options.layerName : 'layer';
+
+ /**
+ * @private
+ * @type {Array.<string>}
+ */
+ this.layers_ = options.layers ? options.layers : null;
+
+};
+ol.inherits(ol.format.MVT, ol.format.Feature);
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.MVT.prototype.getType = function() {
+ return ol.format.FormatType.ARRAY_BUFFER;
+};
+
+
+/**
+ * @private
+ * @param {Object} rawFeature Raw Mapbox feature.
+ * @param {string} layer Layer.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ */
+ol.format.MVT.prototype.readFeature_ = function(
+ rawFeature, layer, opt_options) {
+ var feature = new this.featureClass_();
+ var values = rawFeature.properties;
+ values[this.layerName_] = layer;
+ var geometry = ol.format.Feature.transformWithOptions(
+ ol.format.MVT.readGeometry_(rawFeature), false,
+ this.adaptOptions(opt_options));
+ if (geometry) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.Geometry);
+ values[this.geometryName_] = geometry;
+ }
+ feature.setProperties(values);
+ feature.setGeometryName(this.geometryName_);
+ return feature;
+};
+
+
+/**
+ * @private
+ * @param {Object} rawFeature Raw Mapbox feature.
+ * @param {string} layer Layer.
+ * @return {ol.render.Feature} Feature.
+ */
+ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) {
+ var coords = rawFeature.loadGeometry();
+ var ends = [];
+ var flatCoordinates = [];
+ ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends);
+
+ var type = rawFeature.type;
+ /** @type {ol.geom.GeometryType} */
+ var geometryType;
+ if (type === 1) {
+ geometryType = coords.length === 1 ?
+ ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT;
+ } else if (type === 2) {
+ if (coords.length === 1) {
+ geometryType = ol.geom.GeometryType.LINE_STRING;
+ } else {
+ geometryType = ol.geom.GeometryType.MULTI_LINE_STRING;
+ }
+ } else if (type === 3) {
+ geometryType = ol.geom.GeometryType.POLYGON;
+ }
+
+ var values = rawFeature.properties;
+ values[this.layerName_] = layer;
+
+ return new this.featureClass_(geometryType, flatCoordinates, ends, values);
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.format.MVT.prototype.readFeatures = function(source, opt_options) {
+ goog.asserts.assertInstanceof(source, ArrayBuffer);
+
+ var layers = this.layers_;
+
+ var pbf = new ol.ext.pbf(source);
+ var tile = new ol.ext.vectortile.VectorTile(pbf);
+ var features = [];
+ var featureClass = this.featureClass_;
+ var layer, feature;
+ for (var name in tile.layers) {
+ if (layers && layers.indexOf(name) == -1) {
+ continue;
+ }
+ layer = tile.layers[name];
+
+ for (var i = 0, ii = layer.length; i < ii; ++i) {
+ if (featureClass === ol.render.Feature) {
+ feature = this.readRenderFeature_(layer.feature(i), name);
+ } else {
+ feature = this.readFeature_(layer.feature(i), name, opt_options);
+ }
+ features.push(feature);
+ }
+ }
+
+ return features;
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.format.MVT.prototype.readProjection = function(source) {
+ return this.defaultDataProjection;
+};
+
+
+/**
+ * Sets the layers that features will be read from.
+ * @param {Array.<string>} layers Layers.
+ * @api
+ */
+ol.format.MVT.prototype.setLayers = function(layers) {
+ this.layers_ = layers;
+};
+
+
+/**
+ * @private
+ * @param {Object} coords Raw feature coordinates.
+ * @param {Array.<number>} flatCoordinates Flat coordinates to be populated by
+ * this function.
+ * @param {Array.<number>} ends Ends to be populated by this function.
+ */
+ol.format.MVT.calculateFlatCoordinates_ = function(
+ coords, flatCoordinates, ends) {
+ var end = 0;
+ for (var i = 0, ii = coords.length; i < ii; ++i) {
+ var line = coords[i];
+ var j, jj;
+ for (j = 0, jj = line.length; j < jj; ++j) {
+ var coord = line[j];
+ // Non-tilespace coords can be calculated here when a TileGrid and
+ // TileCoord are known.
+ flatCoordinates.push(coord.x, coord.y);
+ }
+ end += 2 * j;
+ ends.push(end);
+ }
+};
+
+
+/**
+ * @private
+ * @param {Object} rawFeature Raw Mapbox feature.
+ * @return {ol.geom.Geometry} Geometry.
+ */
+ol.format.MVT.readGeometry_ = function(rawFeature) {
+ var type = rawFeature.type;
+ if (type === 0) {
+ return null;
+ }
+
+ var coords = rawFeature.loadGeometry();
+ var ends = [];
+ var flatCoordinates = [];
+ ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends);
+
+ var geom;
+ if (type === 1) {
+ geom = coords.length === 1 ?
+ new ol.geom.Point(null) : new ol.geom.MultiPoint(null);
+ } else if (type === 2) {
+ if (coords.length === 1) {
+ geom = new ol.geom.LineString(null);
+ } else {
+ geom = new ol.geom.MultiLineString(null);
+ }
+ } else if (type === 3) {
+ geom = new ol.geom.Polygon(null);
+ }
+
+ geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,
+ ends);
+
+ return geom;
+};
+
+goog.provide('ol.format.ogc.filter');
+goog.provide('ol.format.ogc.filter.Filter');
+goog.provide('ol.format.ogc.filter.Logical');
+goog.provide('ol.format.ogc.filter.LogicalBinary');
+goog.provide('ol.format.ogc.filter.And');
+goog.provide('ol.format.ogc.filter.Or');
+goog.provide('ol.format.ogc.filter.Not');
+goog.provide('ol.format.ogc.filter.Bbox');
+goog.provide('ol.format.ogc.filter.Comparison');
+goog.provide('ol.format.ogc.filter.ComparisonBinary');
+goog.provide('ol.format.ogc.filter.EqualTo');
+goog.provide('ol.format.ogc.filter.NotEqualTo');
+goog.provide('ol.format.ogc.filter.LessThan');
+goog.provide('ol.format.ogc.filter.LessThanOrEqualTo');
+goog.provide('ol.format.ogc.filter.GreaterThan');
+goog.provide('ol.format.ogc.filter.GreaterThanOrEqualTo');
+goog.provide('ol.format.ogc.filter.IsNull');
+goog.provide('ol.format.ogc.filter.IsBetween');
+goog.provide('ol.format.ogc.filter.IsLike');
+
+
+/**
+ * Create a logical `<And>` operator between two filter conditions.
+ *
+ * @param {!ol.format.ogc.filter.Filter} conditionA First filter condition.
+ * @param {!ol.format.ogc.filter.Filter} conditionB Second filter condition.
+ * @returns {!ol.format.ogc.filter.And} `<And>` operator.
+ * @api
+ */
+ol.format.ogc.filter.and = function(conditionA, conditionB) {
+ return new ol.format.ogc.filter.And(conditionA, conditionB);
+};
+
+
+/**
+ * Create a logical `<Or>` operator between two filter conditions.
+ *
+ * @param {!ol.format.ogc.filter.Filter} conditionA First filter condition.
+ * @param {!ol.format.ogc.filter.Filter} conditionB Second filter condition.
+ * @returns {!ol.format.ogc.filter.Or} `<Or>` operator.
+ * @api
+ */
+ol.format.ogc.filter.or = function(conditionA, conditionB) {
+ return new ol.format.ogc.filter.Or(conditionA, conditionB);
+};
+
+
+/**
+ * Represents a logical `<Not>` operator for a filter condition.
+ *
+ * @param {!ol.format.ogc.filter.Filter} condition Filter condition.
+ * @returns {!ol.format.ogc.filter.Not} `<Not>` operator.
+ * @api
+ */
+ol.format.ogc.filter.not = function(condition) {
+ return new ol.format.ogc.filter.Not(condition);
+};
+
+
+/**
+ * Create a `<BBOX>` operator to test whether a geometry-valued property
+ * intersects a fixed bounding box
+ *
+ * @param {!string} geometryName Geometry name to use.
+ * @param {!ol.Extent} extent Extent.
+ * @param {string=} opt_srsName SRS name. No srsName attribute will be
+ * set on geometries when this is not provided.
+ * @returns {!ol.format.ogc.filter.Bbox} `<BBOX>` operator.
+ * @api
+ */
+ol.format.ogc.filter.bbox = function(geometryName, extent, opt_srsName) {
+ return new ol.format.ogc.filter.Bbox(geometryName, extent, opt_srsName);
+};
+
+
+/**
+ * Creates a `<PropertyIsEqualTo>` comparison operator.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!(string|number)} expression The value to compare.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @returns {!ol.format.ogc.filter.EqualTo} `<PropertyIsEqualTo>` operator.
+ * @api
+ */
+ol.format.ogc.filter.equalTo = function(propertyName, expression, opt_matchCase) {
+ return new ol.format.ogc.filter.EqualTo(propertyName, expression, opt_matchCase);
+};
+
+
+/**
+ * Creates a `<PropertyIsNotEqualTo>` comparison operator.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!(string|number)} expression The value to compare.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @returns {!ol.format.ogc.filter.NotEqualTo} `<PropertyIsNotEqualTo>` operator.
+ * @api
+ */
+ol.format.ogc.filter.notEqualTo = function(propertyName, expression, opt_matchCase) {
+ return new ol.format.ogc.filter.NotEqualTo(propertyName, expression, opt_matchCase);
+};
+
+
+/**
+ * Creates a `<PropertyIsLessThan>` comparison operator.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @returns {!ol.format.ogc.filter.LessThan} `<PropertyIsLessThan>` operator.
+ * @api
+ */
+ol.format.ogc.filter.lessThan = function(propertyName, expression) {
+ return new ol.format.ogc.filter.LessThan(propertyName, expression);
+};
+
+
+/**
+ * Creates a `<PropertyIsLessThanOrEqualTo>` comparison operator.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @returns {!ol.format.ogc.filter.LessThanOrEqualTo} `<PropertyIsLessThanOrEqualTo>` operator.
+ * @api
+ */
+ol.format.ogc.filter.lessThanOrEqualTo = function(propertyName, expression) {
+ return new ol.format.ogc.filter.LessThanOrEqualTo(propertyName, expression);
+};
+
+
+/**
+ * Creates a `<PropertyIsGreaterThan>` comparison operator.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @returns {!ol.format.ogc.filter.GreaterThan} `<PropertyIsGreaterThan>` operator.
+ * @api
+ */
+ol.format.ogc.filter.greaterThan = function(propertyName, expression) {
+ return new ol.format.ogc.filter.GreaterThan(propertyName, expression);
+};
+
+
+/**
+ * Creates a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @returns {!ol.format.ogc.filter.GreaterThanOrEqualTo} `<PropertyIsGreaterThanOrEqualTo>` operator.
+ * @api
+ */
+ol.format.ogc.filter.greaterThanOrEqualTo = function(propertyName, expression) {
+ return new ol.format.ogc.filter.GreaterThanOrEqualTo(propertyName, expression);
+};
+
+
+/**
+ * Creates a `<PropertyIsNull>` comparison operator to test whether a property value
+ * is null.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @returns {!ol.format.ogc.filter.IsNull} `<PropertyIsNull>` operator.
+ * @api
+ */
+ol.format.ogc.filter.isNull = function(propertyName) {
+ return new ol.format.ogc.filter.IsNull(propertyName);
+};
+
+
+/**
+ * Creates a `<PropertyIsBetween>` comparison operator to test whether an expression
+ * value lies within a range given by a lower and upper bound (inclusive).
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} lowerBoundary The lower bound of the range.
+ * @param {!number} upperBoundary The upper bound of the range.
+ * @returns {!ol.format.ogc.filter.IsBetween} `<PropertyIsBetween>` operator.
+ * @api
+ */
+ol.format.ogc.filter.between = function(propertyName, lowerBoundary, upperBoundary) {
+ return new ol.format.ogc.filter.IsBetween(propertyName, lowerBoundary, upperBoundary);
+};
+
+
+/**
+ * Represents a `<PropertyIsLike>` comparison operator that matches a string property
+ * value against a text pattern.
+ *
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!string} pattern Text pattern.
+ * @param {string=} opt_wildCard Pattern character which matches any sequence of
+ * zero or more string characters. Default is '*'.
+ * @param {string=} opt_singleChar pattern character which matches any single
+ * string character. Default is '.'.
+ * @param {string=} opt_escapeChar Escape character which can be used to escape
+ * the pattern characters. Default is '!'.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @returns {!ol.format.ogc.filter.IsLike} `<PropertyIsLike>` operator.
+ * @api
+ */
+ol.format.ogc.filter.like = function(propertyName, pattern,
+ opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {
+ return new ol.format.ogc.filter.IsLike(propertyName, pattern,
+ opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase);
+};
+
+
+/**
+ * @classdesc
+ * Abstract class; normally only used for creating subclasses and not instantiated in apps.
+ * Base class for WFS GetFeature filters.
+ *
+ * @constructor
+ * @param {!string} tagName The XML tag name for this filter.
+ * @struct
+ * @api
+ */
+ol.format.ogc.filter.Filter = function(tagName) {
+
+ /**
+ * @private
+ * @type {!string}
+ */
+ this.tagName_ = tagName;
+};
+
+/**
+ * The XML tag name for a filter.
+ * @returns {!string} Name.
+ */
+ol.format.ogc.filter.Filter.prototype.getTagName = function() {
+ return this.tagName_;
+};
+
+
+// Logical filters
+
+
+/**
+ * @classdesc
+ * Abstract class; normally only used for creating subclasses and not instantiated in apps.
+ * Base class for WFS GetFeature logical filters.
+ *
+ * @constructor
+ * @param {!string} tagName The XML tag name for this filter.
+ * @extends {ol.format.ogc.filter.Filter}
+ */
+ol.format.ogc.filter.Logical = function(tagName) {
+ ol.format.ogc.filter.Filter.call(this, tagName);
+};
+ol.inherits(ol.format.ogc.filter.Logical, ol.format.ogc.filter.Filter);
+
+
+/**
+ * @classdesc
+ * Abstract class; normally only used for creating subclasses and not instantiated in apps.
+ * Base class for WFS GetFeature binary logical filters.
+ *
+ * @constructor
+ * @param {!string} tagName The XML tag name for this filter.
+ * @param {!ol.format.ogc.filter.Filter} conditionA First filter condition.
+ * @param {!ol.format.ogc.filter.Filter} conditionB Second filter condition.
+ * @extends {ol.format.ogc.filter.Logical}
+ */
+ol.format.ogc.filter.LogicalBinary = function(tagName, conditionA, conditionB) {
+
+ ol.format.ogc.filter.Logical.call(this, tagName);
+
+ /**
+ * @public
+ * @type {!ol.format.ogc.filter.Filter}
+ */
+ this.conditionA = conditionA;
+
+ /**
+ * @public
+ * @type {!ol.format.ogc.filter.Filter}
+ */
+ this.conditionB = conditionB;
+
+};
+ol.inherits(ol.format.ogc.filter.LogicalBinary, ol.format.ogc.filter.Logical);
+
+
+/**
+ * @classdesc
+ * Represents a logical `<And>` operator between two filter conditions.
+ *
+ * @constructor
+ * @param {!ol.format.ogc.filter.Filter} conditionA First filter condition.
+ * @param {!ol.format.ogc.filter.Filter} conditionB Second filter condition.
+ * @extends {ol.format.ogc.filter.LogicalBinary}
+ * @api
+ */
+ol.format.ogc.filter.And = function(conditionA, conditionB) {
+ ol.format.ogc.filter.LogicalBinary.call(this, 'And', conditionA, conditionB);
+};
+ol.inherits(ol.format.ogc.filter.And, ol.format.ogc.filter.LogicalBinary);
+
+
+/**
+ * @classdesc
+ * Represents a logical `<Or>` operator between two filter conditions.
+ *
+ * @constructor
+ * @param {!ol.format.ogc.filter.Filter} conditionA First filter condition.
+ * @param {!ol.format.ogc.filter.Filter} conditionB Second filter condition.
+ * @extends {ol.format.ogc.filter.LogicalBinary}
+ * @api
+ */
+ol.format.ogc.filter.Or = function(conditionA, conditionB) {
+ ol.format.ogc.filter.LogicalBinary.call(this, 'Or', conditionA, conditionB);
+};
+ol.inherits(ol.format.ogc.filter.Or, ol.format.ogc.filter.LogicalBinary);
+
+
+/**
+ * @classdesc
+ * Represents a logical `<Not>` operator for a filter condition.
+ *
+ * @constructor
+ * @param {!ol.format.ogc.filter.Filter} condition Filter condition.
+ * @extends {ol.format.ogc.filter.Logical}
+ * @api
+ */
+ol.format.ogc.filter.Not = function(condition) {
+
+ ol.format.ogc.filter.Logical.call(this, 'Not');
+
+ /**
+ * @public
+ * @type {!ol.format.ogc.filter.Filter}
+ */
+ this.condition = condition;
+};
+ol.inherits(ol.format.ogc.filter.Not, ol.format.ogc.filter.Logical);
+
+
+// Spatial filters
+
+
+/**
+ * @classdesc
+ * Represents a `<BBOX>` operator to test whether a geometry-valued property
+ * intersects a fixed bounding box
+ *
+ * @constructor
+ * @param {!string} geometryName Geometry name to use.
+ * @param {!ol.Extent} extent Extent.
+ * @param {string=} opt_srsName SRS name. No srsName attribute will be
+ * set on geometries when this is not provided.
+ * @extends {ol.format.ogc.filter.Filter}
+ * @api
+ */
+ol.format.ogc.filter.Bbox = function(geometryName, extent, opt_srsName) {
+
+ ol.format.ogc.filter.Filter.call(this, 'BBOX');
+
+ /**
+ * @public
+ * @type {!string}
+ */
+ this.geometryName = geometryName;
+
+ /**
+ * @public
+ * @type {ol.Extent}
+ */
+ this.extent = extent;
+
+ /**
+ * @public
+ * @type {string|undefined}
+ */
+ this.srsName = opt_srsName;
+};
+ol.inherits(ol.format.ogc.filter.Bbox, ol.format.ogc.filter.Filter);
+
+
+// Property comparison filters
+
+
+/**
+ * @classdesc
+ * Abstract class; normally only used for creating subclasses and not instantiated in apps.
+ * Base class for WFS GetFeature property comparison filters.
+ *
+ * @constructor
+ * @param {!string} tagName The XML tag name for this filter.
+ * @param {!string} propertyName Name of the context property to compare.
+ * @extends {ol.format.ogc.filter.Filter}
+ * @api
+ */
+ol.format.ogc.filter.Comparison = function(tagName, propertyName) {
+
+ ol.format.ogc.filter.Filter.call(this, tagName);
+
+ /**
+ * @public
+ * @type {!string}
+ */
+ this.propertyName = propertyName;
+};
+ol.inherits(ol.format.ogc.filter.Comparison, ol.format.ogc.filter.Filter);
+
+
+/**
+ * @classdesc
+ * Abstract class; normally only used for creating subclasses and not instantiated in apps.
+ * Base class for WFS GetFeature property binary comparison filters.
+ *
+ * @constructor
+ * @param {!string} tagName The XML tag name for this filter.
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!(string|number)} expression The value to compare.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @extends {ol.format.ogc.filter.Comparison}
+ * @api
+ */
+ol.format.ogc.filter.ComparisonBinary = function(
+ tagName, propertyName, expression, opt_matchCase) {
+
+ ol.format.ogc.filter.Comparison.call(this, tagName, propertyName);
+
+ /**
+ * @public
+ * @type {!(string|number)}
+ */
+ this.expression = expression;
+
+ /**
+ * @public
+ * @type {boolean|undefined}
+ */
+ this.matchCase = opt_matchCase;
+};
+ol.inherits(ol.format.ogc.filter.ComparisonBinary, ol.format.ogc.filter.Comparison);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsEqualTo>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!(string|number)} expression The value to compare.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @extends {ol.format.ogc.filter.ComparisonBinary}
+ * @api
+ */
+ol.format.ogc.filter.EqualTo = function(propertyName, expression, opt_matchCase) {
+ ol.format.ogc.filter.ComparisonBinary.call(this, 'PropertyIsEqualTo', propertyName, expression, opt_matchCase);
+};
+ol.inherits(ol.format.ogc.filter.EqualTo, ol.format.ogc.filter.ComparisonBinary);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsNotEqualTo>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!(string|number)} expression The value to compare.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @extends {ol.format.ogc.filter.ComparisonBinary}
+ * @api
+ */
+ol.format.ogc.filter.NotEqualTo = function(propertyName, expression, opt_matchCase) {
+ ol.format.ogc.filter.ComparisonBinary.call(this, 'PropertyIsNotEqualTo', propertyName, expression, opt_matchCase);
+};
+ol.inherits(ol.format.ogc.filter.NotEqualTo, ol.format.ogc.filter.ComparisonBinary);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsLessThan>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @extends {ol.format.ogc.filter.ComparisonBinary}
+ * @api
+ */
+ol.format.ogc.filter.LessThan = function(propertyName, expression) {
+ ol.format.ogc.filter.ComparisonBinary.call(this, 'PropertyIsLessThan', propertyName, expression);
+};
+ol.inherits(ol.format.ogc.filter.LessThan, ol.format.ogc.filter.ComparisonBinary);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsLessThanOrEqualTo>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @extends {ol.format.ogc.filter.ComparisonBinary}
+ * @api
+ */
+ol.format.ogc.filter.LessThanOrEqualTo = function(propertyName, expression) {
+ ol.format.ogc.filter.ComparisonBinary.call(this, 'PropertyIsLessThanOrEqualTo', propertyName, expression);
+};
+ol.inherits(ol.format.ogc.filter.LessThanOrEqualTo, ol.format.ogc.filter.ComparisonBinary);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsGreaterThan>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @extends {ol.format.ogc.filter.ComparisonBinary}
+ * @api
+ */
+ol.format.ogc.filter.GreaterThan = function(propertyName, expression) {
+ ol.format.ogc.filter.ComparisonBinary.call(this, 'PropertyIsGreaterThan', propertyName, expression);
+};
+ol.inherits(ol.format.ogc.filter.GreaterThan, ol.format.ogc.filter.ComparisonBinary);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} expression The value to compare.
+ * @extends {ol.format.ogc.filter.ComparisonBinary}
+ * @api
+ */
+ol.format.ogc.filter.GreaterThanOrEqualTo = function(propertyName, expression) {
+ ol.format.ogc.filter.ComparisonBinary.call(this, 'PropertyIsGreaterThanOrEqualTo', propertyName, expression);
+};
+ol.inherits(ol.format.ogc.filter.GreaterThanOrEqualTo, ol.format.ogc.filter.ComparisonBinary);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsNull>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @extends {ol.format.ogc.filter.Comparison}
+ * @api
+ */
+ol.format.ogc.filter.IsNull = function(propertyName) {
+ ol.format.ogc.filter.Comparison.call(this, 'PropertyIsNull', propertyName);
+};
+ol.inherits(ol.format.ogc.filter.IsNull, ol.format.ogc.filter.Comparison);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsBetween>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!number} lowerBoundary The lower bound of the range.
+ * @param {!number} upperBoundary The upper bound of the range.
+ * @extends {ol.format.ogc.filter.Comparison}
+ * @api
+ */
+ol.format.ogc.filter.IsBetween = function(propertyName, lowerBoundary, upperBoundary) {
+ ol.format.ogc.filter.Comparison.call(this, 'PropertyIsBetween', propertyName);
+
+ /**
+ * @public
+ * @type {!number}
+ */
+ this.lowerBoundary = lowerBoundary;
+
+ /**
+ * @public
+ * @type {!number}
+ */
+ this.upperBoundary = upperBoundary;
+};
+ol.inherits(ol.format.ogc.filter.IsBetween, ol.format.ogc.filter.Comparison);
+
+
+/**
+ * @classdesc
+ * Represents a `<PropertyIsLike>` comparison operator.
+ *
+ * @constructor
+ * @param {!string} propertyName Name of the context property to compare.
+ * @param {!string} pattern Text pattern.
+ * @param {string=} opt_wildCard Pattern character which matches any sequence of
+ * zero or more string characters. Default is '*'.
+ * @param {string=} opt_singleChar pattern character which matches any single
+ * string character. Default is '.'.
+ * @param {string=} opt_escapeChar Escape character which can be used to escape
+ * the pattern characters. Default is '!'.
+ * @param {boolean=} opt_matchCase Case-sensitive?
+ * @extends {ol.format.ogc.filter.Comparison}
+ * @api
+ */
+ol.format.ogc.filter.IsLike = function(propertyName, pattern,
+ opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {
+ ol.format.ogc.filter.Comparison.call(this, 'PropertyIsLike', propertyName);
+
+ /**
+ * @public
+ * @type {!string}
+ */
+ this.pattern = pattern;
+
+ /**
+ * @public
+ * @type {!string}
+ */
+ this.wildCard = (opt_wildCard !== undefined) ? opt_wildCard : '*';
+
+ /**
+ * @public
+ * @type {!string}
+ */
+ this.singleChar = (opt_singleChar !== undefined) ? opt_singleChar : '.';
+
+ /**
+ * @public
+ * @type {!string}
+ */
+ this.escapeChar = (opt_escapeChar !== undefined) ? opt_escapeChar : '!';
+
+ /**
+ * @public
+ * @type {boolean|undefined}
+ */
+ this.matchCase = opt_matchCase;
+};
+ol.inherits(ol.format.ogc.filter.IsLike, ol.format.ogc.filter.Comparison);
+
+// FIXME add typedef for stack state objects
+goog.provide('ol.format.OSMXML');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.XMLFeature');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Feature format for reading data in the
+ * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).
+ *
+ * @constructor
+ * @extends {ol.format.XMLFeature}
+ * @api stable
+ */
+ol.format.OSMXML = function() {
+ ol.format.XMLFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get('EPSG:4326');
+};
+ol.inherits(ol.format.OSMXML, ol.format.XMLFeature);
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.OSMXML.EXTENSIONS_ = ['.osm'];
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.OSMXML.prototype.getExtensions = function() {
+ return ol.format.OSMXML.EXTENSIONS_;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.OSMXML.readNode_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'node', 'localName should be node');
+ var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
+ var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ var id = node.getAttribute('id');
+ /** @type {ol.Coordinate} */
+ var coordinates = [
+ parseFloat(node.getAttribute('lon')),
+ parseFloat(node.getAttribute('lat'))
+ ];
+ state.nodes[id] = coordinates;
+
+ var values = ol.xml.pushParseAndPop({
+ tags: {}
+ }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack);
+ if (!ol.object.isEmpty(values.tags)) {
+ var geometry = new ol.geom.Point(coordinates);
+ ol.format.Feature.transformWithOptions(geometry, false, options);
+ var feature = new ol.Feature(geometry);
+ feature.setId(id);
+ feature.setProperties(values.tags);
+ state.features.push(feature);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.OSMXML.readWay_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'way', 'localName should be way');
+ var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
+ var id = node.getAttribute('id');
+ var values = ol.xml.pushParseAndPop({
+ ndrefs: [],
+ tags: {}
+ }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack);
+ var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ /** @type {Array.<number>} */
+ var flatCoordinates = [];
+ for (var i = 0, ii = values.ndrefs.length; i < ii; i++) {
+ var point = state.nodes[values.ndrefs[i]];
+ ol.array.extend(flatCoordinates, point);
+ }
+ var geometry;
+ if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {
+ // closed way
+ geometry = new ol.geom.Polygon(null);
+ geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,
+ [flatCoordinates.length]);
+ } else {
+ geometry = new ol.geom.LineString(null);
+ geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
+ }
+ ol.format.Feature.transformWithOptions(geometry, false, options);
+ var feature = new ol.Feature(geometry);
+ feature.setId(id);
+ feature.setProperties(values.tags);
+ state.features.push(feature);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.OSMXML.readNd_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'nd', 'localName should be nd');
+ var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ values.ndrefs.push(node.getAttribute('ref'));
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.OSMXML.readTag_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'tag', 'localName should be tag');
+ var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
+ values.tags[node.getAttribute('k')] = node.getAttribute('v');
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<string>}
+ */
+ol.format.OSMXML.NAMESPACE_URIS_ = [
+ null
+];
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OSMXML.NAMESPACE_URIS_, {
+ 'nd': ol.format.OSMXML.readNd_,
+ 'tag': ol.format.OSMXML.readTag_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OSMXML.PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OSMXML.NAMESPACE_URIS_, {
+ 'node': ol.format.OSMXML.readNode_,
+ 'way': ol.format.OSMXML.readWay_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OSMXML.NAMESPACE_URIS_, {
+ 'tag': ol.format.OSMXML.readTag_
+ });
+
+
+/**
+ * Read all features from an OSM source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.OSMXML.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ var options = this.getReadOptions(node, opt_options);
+ if (node.localName == 'osm') {
+ var state = ol.xml.pushParseAndPop({
+ nodes: {},
+ features: []
+ }, ol.format.OSMXML.PARSERS_, node, [options]);
+ if (state.features) {
+ return state.features;
+ }
+ }
+ return [];
+};
+
+
+/**
+ * Read the projection from an OSM source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.OSMXML.prototype.readProjection;
+
+goog.provide('ol.format.XLink');
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink';
+
+
+/**
+ * @param {Node} node Node.
+ * @return {boolean|undefined} Boolean.
+ */
+ol.format.XLink.readHref = function(node) {
+ return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href');
+};
+
+goog.provide('ol.format.XML');
+
+goog.require('goog.asserts');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Generic format for reading non-feature XML data
+ *
+ * @constructor
+ * @struct
+ */
+ol.format.XML = function() {
+};
+
+
+/**
+ * @param {Document|Node|string} source Source.
+ * @return {Object} The parsed result.
+ */
+ol.format.XML.prototype.read = function(source) {
+ if (ol.xml.isDocument(source)) {
+ return this.readFromDocument(/** @type {Document} */ (source));
+ } else if (ol.xml.isNode(source)) {
+ return this.readFromNode(/** @type {Node} */ (source));
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readFromDocument(doc);
+ } else {
+ goog.asserts.fail();
+ return null;
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {Object}
+ */
+ol.format.XML.prototype.readFromDocument = goog.abstractMethod;
+
+
+/**
+ * @param {Node} node Node.
+ * @return {Object}
+ */
+ol.format.XML.prototype.readFromNode = goog.abstractMethod;
+
+goog.provide('ol.format.OWS');
+
+goog.require('goog.asserts');
+goog.require('ol.format.XLink');
+goog.require('ol.format.XML');
+goog.require('ol.format.XSD');
+goog.require('ol.xml');
+
+
+/**
+ * @constructor
+ * @extends {ol.format.XML}
+ */
+ol.format.OWS = function() {
+ ol.format.XML.call(this);
+};
+ol.inherits(ol.format.OWS, ol.format.XML);
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {Object} OWS object.
+ */
+ol.format.OWS.prototype.readFromDocument = function(doc) {
+ goog.asserts.assert(doc.nodeType == Node.DOCUMENT_NODE,
+ 'doc.nodeType should be DOCUMENT');
+ for (var n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ return this.readFromNode(n);
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {Object} OWS object.
+ */
+ol.format.OWS.prototype.readFromNode = function(node) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ var owsObject = ol.xml.pushParseAndPop({},
+ ol.format.OWS.PARSERS_, node, []);
+ return owsObject ? owsObject : null;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The address.
+ */
+ol.format.OWS.readAddress_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Address',
+ 'localName should be Address');
+ return ol.xml.pushParseAndPop({},
+ ol.format.OWS.ADDRESS_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The values.
+ */
+ol.format.OWS.readAllowedValues_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'AllowedValues',
+ 'localName should be AllowedValues');
+ return ol.xml.pushParseAndPop({},
+ ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The constraint.
+ */
+ol.format.OWS.readConstraint_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Constraint',
+ 'localName should be Constraint');
+ var name = node.getAttribute('name');
+ if (!name) {
+ return undefined;
+ }
+ return ol.xml.pushParseAndPop({'name': name},
+ ol.format.OWS.CONSTRAINT_PARSERS_, node,
+ objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The contact info.
+ */
+ol.format.OWS.readContactInfo_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ContactInfo',
+ 'localName should be ContactInfo');
+ return ol.xml.pushParseAndPop({},
+ ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The DCP.
+ */
+ol.format.OWS.readDcp_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'DCP', 'localName should be DCP');
+ return ol.xml.pushParseAndPop({},
+ ol.format.OWS.DCP_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The GET object.
+ */
+ol.format.OWS.readGet_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Get', 'localName should be Get');
+ var href = ol.format.XLink.readHref(node);
+ if (!href) {
+ return undefined;
+ }
+ return ol.xml.pushParseAndPop({'href': href},
+ ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The HTTP object.
+ */
+ol.format.OWS.readHttp_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP');
+ return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_,
+ node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The operation.
+ */
+ol.format.OWS.readOperation_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Operation',
+ 'localName should be Operation');
+ var name = node.getAttribute('name');
+ var value = ol.xml.pushParseAndPop({},
+ ol.format.OWS.OPERATION_PARSERS_, node, objectStack);
+ if (!value) {
+ return undefined;
+ }
+ var object = /** @type {Object} */
+ (objectStack[objectStack.length - 1]);
+ goog.asserts.assert(goog.isObject(object), 'object should be an Object');
+ object[name] = value;
+
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The operations metadata.
+ */
+ol.format.OWS.readOperationsMetadata_ = function(node,
+ objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'OperationsMetadata',
+ 'localName should be OperationsMetadata');
+ return ol.xml.pushParseAndPop({},
+ ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node,
+ objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The phone.
+ */
+ol.format.OWS.readPhone_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Phone', 'localName should be Phone');
+ return ol.xml.pushParseAndPop({},
+ ol.format.OWS.PHONE_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The service identification.
+ */
+ol.format.OWS.readServiceIdentification_ = function(node,
+ objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ServiceIdentification',
+ 'localName should be ServiceIdentification');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node,
+ objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The service contact.
+ */
+ol.format.OWS.readServiceContact_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ServiceContact',
+ 'localName should be ServiceContact');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node,
+ objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} The service provider.
+ */
+ol.format.OWS.readServiceProvider_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ServiceProvider',
+ 'localName should be ServiceProvider');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node,
+ objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {string|undefined} The value.
+ */
+ol.format.OWS.readValue_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Value', 'localName should be Value');
+ return ol.format.XSD.readString(node);
+};
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ * @private
+ */
+ol.format.OWS.NAMESPACE_URIS_ = [
+ null,
+ 'http://www.opengis.net/ows/1.1'
+];
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'ServiceIdentification': ol.xml.makeObjectPropertySetter(
+ ol.format.OWS.readServiceIdentification_),
+ 'ServiceProvider': ol.xml.makeObjectPropertySetter(
+ ol.format.OWS.readServiceProvider_),
+ 'OperationsMetadata': ol.xml.makeObjectPropertySetter(
+ ol.format.OWS.readOperationsMetadata_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'DeliveryPoint': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'AdministrativeArea': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'ElectronicMailAddress': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'AllowedValues': ol.xml.makeObjectPropertySetter(
+ ol.format.OWS.readAllowedValues_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_),
+ 'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.DCP_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.HTTP_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_),
+ 'Post': undefined // TODO
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Operation': ol.format.OWS.readOperation_
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.PHONE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Constraint': ol.xml.makeObjectPropertyPusher(
+ ol.format.OWS.readConstraint_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.SERVICE_CONTACT_PARSERS_ =
+ ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'IndividualName': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'ContactInfo': ol.xml.makeObjectPropertySetter(
+ ol.format.OWS.readContactInfo_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ =
+ ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'ServiceTypeVersion': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.OWS.SERVICE_PROVIDER_PARSERS_ =
+ ol.xml.makeStructureNS(
+ ol.format.OWS.NAMESPACE_URIS_, {
+ 'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref),
+ 'ServiceContact': ol.xml.makeObjectPropertySetter(
+ ol.format.OWS.readServiceContact_)
+ });
+
+goog.provide('ol.geom.flat.flip');
+
+goog.require('goog.asserts');
+
+
+/**
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ * @param {number} offset Offset.
+ * @param {number} end End.
+ * @param {number} stride Stride.
+ * @param {Array.<number>=} opt_dest Destination.
+ * @param {number=} opt_destOffset Destination offset.
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.geom.flat.flip.flipXY = function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) {
+ var dest, destOffset;
+ if (opt_dest !== undefined) {
+ dest = opt_dest;
+ destOffset = opt_destOffset !== undefined ? opt_destOffset : 0;
+ } else {
+ goog.asserts.assert(opt_destOffset === undefined,
+ 'opt_destOffSet should be defined');
+ dest = [];
+ destOffset = 0;
+ }
+ var j = offset;
+ while (j < end) {
+ var x = flatCoordinates[j++];
+ dest[destOffset++] = flatCoordinates[j++];
+ dest[destOffset++] = x;
+ for (var k = 2; k < stride; ++k) {
+ dest[destOffset++] = flatCoordinates[j++];
+ }
+ }
+ dest.length = destOffset;
+ return dest;
+};
+
+goog.provide('ol.format.Polyline');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.TextFeature');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.flip');
+goog.require('ol.geom.flat.inflate');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the Encoded
+ * Polyline Algorithm Format.
+ *
+ * @constructor
+ * @extends {ol.format.TextFeature}
+ * @param {olx.format.PolylineOptions=} opt_options
+ * Optional configuration object.
+ * @api stable
+ */
+ol.format.Polyline = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.TextFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get('EPSG:4326');
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.factor_ = options.factor ? options.factor : 1e5;
+
+ /**
+ * @private
+ * @type {ol.geom.GeometryLayout}
+ */
+ this.geometryLayout_ = options.geometryLayout ?
+ options.geometryLayout : ol.geom.GeometryLayout.XY;
+};
+ol.inherits(ol.format.Polyline, ol.format.TextFeature);
+
+
+/**
+ * Encode a list of n-dimensional points and return an encoded string
+ *
+ * Attention: This function will modify the passed array!
+ *
+ * @param {Array.<number>} numbers A list of n-dimensional points.
+ * @param {number} stride The number of dimension of the points in the list.
+ * @param {number=} opt_factor The factor by which the numbers will be
+ * multiplied. The remaining decimal places will get rounded away.
+ * Default is `1e5`.
+ * @return {string} The encoded string.
+ * @api
+ */
+ol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) {
+ var factor = opt_factor ? opt_factor : 1e5;
+ var d;
+
+ var lastNumbers = new Array(stride);
+ for (d = 0; d < stride; ++d) {
+ lastNumbers[d] = 0;
+ }
+
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii;) {
+ for (d = 0; d < stride; ++d, ++i) {
+ var num = numbers[i];
+ var delta = num - lastNumbers[d];
+ lastNumbers[d] = num;
+
+ numbers[i] = delta;
+ }
+ }
+
+ return ol.format.Polyline.encodeFloats(numbers, factor);
+};
+
+
+/**
+ * Decode a list of n-dimensional points from an encoded string
+ *
+ * @param {string} encoded An encoded string.
+ * @param {number} stride The number of dimension of the points in the
+ * encoded string.
+ * @param {number=} opt_factor The factor by which the resulting numbers will
+ * be divided. Default is `1e5`.
+ * @return {Array.<number>} A list of n-dimensional points.
+ * @api
+ */
+ol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) {
+ var factor = opt_factor ? opt_factor : 1e5;
+ var d;
+
+ /** @type {Array.<number>} */
+ var lastNumbers = new Array(stride);
+ for (d = 0; d < stride; ++d) {
+ lastNumbers[d] = 0;
+ }
+
+ var numbers = ol.format.Polyline.decodeFloats(encoded, factor);
+
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii;) {
+ for (d = 0; d < stride; ++d, ++i) {
+ lastNumbers[d] += numbers[i];
+
+ numbers[i] = lastNumbers[d];
+ }
+ }
+
+ return numbers;
+};
+
+
+/**
+ * Encode a list of floating point numbers and return an encoded string
+ *
+ * Attention: This function will modify the passed array!
+ *
+ * @param {Array.<number>} numbers A list of floating point numbers.
+ * @param {number=} opt_factor The factor by which the numbers will be
+ * multiplied. The remaining decimal places will get rounded away.
+ * Default is `1e5`.
+ * @return {string} The encoded string.
+ * @api
+ */
+ol.format.Polyline.encodeFloats = function(numbers, opt_factor) {
+ var factor = opt_factor ? opt_factor : 1e5;
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii; ++i) {
+ numbers[i] = Math.round(numbers[i] * factor);
+ }
+
+ return ol.format.Polyline.encodeSignedIntegers(numbers);
+};
+
+
+/**
+ * Decode a list of floating point numbers from an encoded string
+ *
+ * @param {string} encoded An encoded string.
+ * @param {number=} opt_factor The factor by which the result will be divided.
+ * Default is `1e5`.
+ * @return {Array.<number>} A list of floating point numbers.
+ * @api
+ */
+ol.format.Polyline.decodeFloats = function(encoded, opt_factor) {
+ var factor = opt_factor ? opt_factor : 1e5;
+ var numbers = ol.format.Polyline.decodeSignedIntegers(encoded);
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii; ++i) {
+ numbers[i] /= factor;
+ }
+ return numbers;
+};
+
+
+/**
+ * Encode a list of signed integers and return an encoded string
+ *
+ * Attention: This function will modify the passed array!
+ *
+ * @param {Array.<number>} numbers A list of signed integers.
+ * @return {string} The encoded string.
+ */
+ol.format.Polyline.encodeSignedIntegers = function(numbers) {
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii; ++i) {
+ var num = numbers[i];
+ numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);
+ }
+ return ol.format.Polyline.encodeUnsignedIntegers(numbers);
+};
+
+
+/**
+ * Decode a list of signed integers from an encoded string
+ *
+ * @param {string} encoded An encoded string.
+ * @return {Array.<number>} A list of signed integers.
+ */
+ol.format.Polyline.decodeSignedIntegers = function(encoded) {
+ var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded);
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii; ++i) {
+ var num = numbers[i];
+ numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
+ }
+ return numbers;
+};
+
+
+/**
+ * Encode a list of unsigned integers and return an encoded string
+ *
+ * @param {Array.<number>} numbers A list of unsigned integers.
+ * @return {string} The encoded string.
+ */
+ol.format.Polyline.encodeUnsignedIntegers = function(numbers) {
+ var encoded = '';
+ var i, ii;
+ for (i = 0, ii = numbers.length; i < ii; ++i) {
+ encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]);
+ }
+ return encoded;
+};
+
+
+/**
+ * Decode a list of unsigned integers from an encoded string
+ *
+ * @param {string} encoded An encoded string.
+ * @return {Array.<number>} A list of unsigned integers.
+ */
+ol.format.Polyline.decodeUnsignedIntegers = function(encoded) {
+ var numbers = [];
+ var current = 0;
+ var shift = 0;
+ var i, ii;
+ for (i = 0, ii = encoded.length; i < ii; ++i) {
+ var b = encoded.charCodeAt(i) - 63;
+ current |= (b & 0x1f) << shift;
+ if (b < 0x20) {
+ numbers.push(current);
+ current = 0;
+ shift = 0;
+ } else {
+ shift += 5;
+ }
+ }
+ return numbers;
+};
+
+
+/**
+ * Encode one single unsigned integer and return an encoded string
+ *
+ * @param {number} num Unsigned integer that should be encoded.
+ * @return {string} The encoded string.
+ */
+ol.format.Polyline.encodeUnsignedInteger = function(num) {
+ var value, encoded = '';
+ while (num >= 0x20) {
+ value = (0x20 | (num & 0x1f)) + 63;
+ encoded += String.fromCharCode(value);
+ num >>= 5;
+ }
+ value = num + 63;
+ encoded += String.fromCharCode(value);
+ return encoded;
+};
+
+
+/**
+ * Read the feature from the Polyline source. The coordinates are assumed to be
+ * in two dimensions and in latitude, longitude order.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api stable
+ */
+ol.format.Polyline.prototype.readFeature;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) {
+ var geometry = this.readGeometryFromText(text, opt_options);
+ return new ol.Feature(geometry);
+};
+
+
+/**
+ * Read the feature from the source. As Polyline sources contain a single
+ * feature, this will return the feature in an array.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.Polyline.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.Polyline.prototype.readFeaturesFromText = function(text, opt_options) {
+ var feature = this.readFeatureFromText(text, opt_options);
+ return [feature];
+};
+
+
+/**
+ * Read the geometry from the source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.geom.Geometry} Geometry.
+ * @api stable
+ */
+ol.format.Polyline.prototype.readGeometry;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.Polyline.prototype.readGeometryFromText = function(text, opt_options) {
+ var stride = ol.geom.SimpleGeometry.getStrideForLayout(this.geometryLayout_);
+ var flatCoordinates = ol.format.Polyline.decodeDeltas(
+ text, stride, this.factor_);
+ ol.geom.flat.flip.flipXY(
+ flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
+ var coordinates = ol.geom.flat.inflate.coordinates(
+ flatCoordinates, 0, flatCoordinates.length, stride);
+
+ return /** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(
+ new ol.geom.LineString(coordinates, this.geometryLayout_), false,
+ this.adaptOptions(opt_options)));
+};
+
+
+/**
+ * Read the projection from a Polyline source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.Polyline.prototype.readProjection;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) {
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ return this.writeGeometryText(geometry, opt_options);
+ } else {
+ goog.asserts.fail('geometry needs to be defined');
+ return '';
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.Polyline.prototype.writeFeaturesText = function(features, opt_options) {
+ goog.asserts.assert(features.length == 1,
+ 'features array should have 1 item');
+ return this.writeFeatureText(features[0], opt_options);
+};
+
+
+/**
+ * Write a single geometry in Polyline format.
+ *
+ * @function
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} Geometry.
+ * @api stable
+ */
+ol.format.Polyline.prototype.writeGeometry;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.Polyline.prototype.writeGeometryText = function(geometry, opt_options) {
+ goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
+ 'geometry should be an ol.geom.LineString');
+ geometry = /** @type {ol.geom.LineString} */
+ (ol.format.Feature.transformWithOptions(
+ geometry, true, this.adaptOptions(opt_options)));
+ var flatCoordinates = geometry.getFlatCoordinates();
+ var stride = geometry.getStride();
+ ol.geom.flat.flip.flipXY(
+ flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
+ return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_);
+};
+
+goog.provide('ol.format.TopoJSON');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.JSONFeature');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.object');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Feature format for reading data in the TopoJSON format.
+ *
+ * @constructor
+ * @extends {ol.format.JSONFeature}
+ * @param {olx.format.TopoJSONOptions=} opt_options Options.
+ * @api stable
+ */
+ol.format.TopoJSON = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.JSONFeature.call(this);
+
+ /**
+ * @inheritDoc
+ */
+ this.defaultDataProjection = ol.proj.get(
+ options.defaultDataProjection ?
+ options.defaultDataProjection : 'EPSG:4326');
+
+};
+ol.inherits(ol.format.TopoJSON, ol.format.JSONFeature);
+
+
+/**
+ * @const {Array.<string>}
+ * @private
+ */
+ol.format.TopoJSON.EXTENSIONS_ = ['.topojson'];
+
+
+/**
+ * Concatenate arcs into a coordinate array.
+ * @param {Array.<number>} indices Indices of arcs to concatenate. Negative
+ * values indicate arcs need to be reversed.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already
+ * transformed).
+ * @return {Array.<ol.Coordinate>} Coordinates array.
+ * @private
+ */
+ol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) {
+ /** @type {Array.<ol.Coordinate>} */
+ var coordinates = [];
+ var index, arc;
+ var i, ii;
+ var j, jj;
+ for (i = 0, ii = indices.length; i < ii; ++i) {
+ index = indices[i];
+ if (i > 0) {
+ // splicing together arcs, discard last point
+ coordinates.pop();
+ }
+ if (index >= 0) {
+ // forward arc
+ arc = arcs[index];
+ } else {
+ // reverse arc
+ arc = arcs[~index].slice().reverse();
+ }
+ coordinates.push.apply(coordinates, arc);
+ }
+ // provide fresh copies of coordinate arrays
+ for (j = 0, jj = coordinates.length; j < jj; ++j) {
+ coordinates[j] = coordinates[j].slice();
+ }
+ return coordinates;
+};
+
+
+/**
+ * Create a point from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON object.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @return {ol.geom.Point} Geometry.
+ * @private
+ */
+ol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) {
+ var coordinates = object.coordinates;
+ if (scale && translate) {
+ ol.format.TopoJSON.transformVertex_(coordinates, scale, translate);
+ }
+ return new ol.geom.Point(coordinates);
+};
+
+
+/**
+ * Create a multi-point from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON object.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @return {ol.geom.MultiPoint} Geometry.
+ * @private
+ */
+ol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale,
+ translate) {
+ var coordinates = object.coordinates;
+ var i, ii;
+ if (scale && translate) {
+ for (i = 0, ii = coordinates.length; i < ii; ++i) {
+ ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate);
+ }
+ }
+ return new ol.geom.MultiPoint(coordinates);
+};
+
+
+/**
+ * Create a linestring from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON object.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @return {ol.geom.LineString} Geometry.
+ * @private
+ */
+ol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) {
+ var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs);
+ return new ol.geom.LineString(coordinates);
+};
+
+
+/**
+ * Create a multi-linestring from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON object.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @return {ol.geom.MultiLineString} Geometry.
+ * @private
+ */
+ol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) {
+ var coordinates = [];
+ var i, ii;
+ for (i = 0, ii = object.arcs.length; i < ii; ++i) {
+ coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);
+ }
+ return new ol.geom.MultiLineString(coordinates);
+};
+
+
+/**
+ * Create a polygon from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON object.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @return {ol.geom.Polygon} Geometry.
+ * @private
+ */
+ol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) {
+ var coordinates = [];
+ var i, ii;
+ for (i = 0, ii = object.arcs.length; i < ii; ++i) {
+ coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);
+ }
+ return new ol.geom.Polygon(coordinates);
+};
+
+
+/**
+ * Create a multi-polygon from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON object.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @return {ol.geom.MultiPolygon} Geometry.
+ * @private
+ */
+ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) {
+ var coordinates = [];
+ var polyArray, ringCoords, j, jj;
+ var i, ii;
+ for (i = 0, ii = object.arcs.length; i < ii; ++i) {
+ // for each polygon
+ polyArray = object.arcs[i];
+ ringCoords = [];
+ for (j = 0, jj = polyArray.length; j < jj; ++j) {
+ // for each ring
+ ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs);
+ }
+ coordinates[i] = ringCoords;
+ }
+ return new ol.geom.MultiPolygon(coordinates);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TopoJSON.prototype.getExtensions = function() {
+ return ol.format.TopoJSON.EXTENSIONS_;
+};
+
+
+/**
+ * Create features from a TopoJSON GeometryCollection object.
+ *
+ * @param {TopoJSONGeometryCollection} collection TopoJSON Geometry
+ * object.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Array of features.
+ * @private
+ */
+ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function(
+ collection, arcs, scale, translate, opt_options) {
+ var geometries = collection.geometries;
+ var features = [];
+ var i, ii;
+ for (i = 0, ii = geometries.length; i < ii; ++i) {
+ features[i] = ol.format.TopoJSON.readFeatureFromGeometry_(
+ geometries[i], arcs, scale, translate, opt_options);
+ }
+ return features;
+};
+
+
+/**
+ * Create a feature from a TopoJSON geometry object.
+ *
+ * @param {TopoJSONGeometry} object TopoJSON geometry object.
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @private
+ */
+ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs,
+ scale, translate, opt_options) {
+ var geometry;
+ var type = object.type;
+ var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type];
+ goog.asserts.assert(geometryReader, 'geometryReader should be defined');
+ if ((type === 'Point') || (type === 'MultiPoint')) {
+ geometry = geometryReader(object, scale, translate);
+ } else {
+ geometry = geometryReader(object, arcs);
+ }
+ var feature = new ol.Feature();
+ feature.setGeometry(/** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(geometry, false, opt_options)));
+ if (object.id !== undefined) {
+ feature.setId(object.id);
+ }
+ if (object.properties) {
+ feature.setProperties(object.properties);
+ }
+ return feature;
+};
+
+
+/**
+ * Read all features from a TopoJSON source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.TopoJSON.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.TopoJSON.prototype.readFeaturesFromObject = function(
+ object, opt_options) {
+ if (object.type == 'Topology') {
+ var topoJSONTopology = /** @type {TopoJSONTopology} */ (object);
+ var transform, scale = null, translate = null;
+ if (topoJSONTopology.transform) {
+ transform = topoJSONTopology.transform;
+ scale = transform.scale;
+ translate = transform.translate;
+ }
+ var arcs = topoJSONTopology.arcs;
+ if (transform) {
+ ol.format.TopoJSON.transformArcs_(arcs, scale, translate);
+ }
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ var topoJSONFeatures = ol.object.getValues(topoJSONTopology.objects);
+ var i, ii;
+ var feature;
+ for (i = 0, ii = topoJSONFeatures.length; i < ii; ++i) {
+ if (topoJSONFeatures[i].type === 'GeometryCollection') {
+ feature = /** @type {TopoJSONGeometryCollection} */
+ (topoJSONFeatures[i]);
+ features.push.apply(features,
+ ol.format.TopoJSON.readFeaturesFromGeometryCollection_(
+ feature, arcs, scale, translate, opt_options));
+ } else {
+ feature = /** @type {TopoJSONGeometry} */
+ (topoJSONFeatures[i]);
+ features.push(ol.format.TopoJSON.readFeatureFromGeometry_(
+ feature, arcs, scale, translate, opt_options));
+ }
+ }
+ return features;
+ } else {
+ return [];
+ }
+};
+
+
+/**
+ * Apply a linear transform to array of arcs. The provided array of arcs is
+ * modified in place.
+ *
+ * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @private
+ */
+ol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) {
+ var i, ii;
+ for (i = 0, ii = arcs.length; i < ii; ++i) {
+ ol.format.TopoJSON.transformArc_(arcs[i], scale, translate);
+ }
+};
+
+
+/**
+ * Apply a linear transform to an arc. The provided arc is modified in place.
+ *
+ * @param {Array.<ol.Coordinate>} arc Arc.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @private
+ */
+ol.format.TopoJSON.transformArc_ = function(arc, scale, translate) {
+ var x = 0;
+ var y = 0;
+ var vertex;
+ var i, ii;
+ for (i = 0, ii = arc.length; i < ii; ++i) {
+ vertex = arc[i];
+ x += vertex[0];
+ y += vertex[1];
+ vertex[0] = x;
+ vertex[1] = y;
+ ol.format.TopoJSON.transformVertex_(vertex, scale, translate);
+ }
+};
+
+
+/**
+ * Apply a linear transform to a vertex. The provided vertex is modified in
+ * place.
+ *
+ * @param {ol.Coordinate} vertex Vertex.
+ * @param {Array.<number>} scale Scale for each dimension.
+ * @param {Array.<number>} translate Translation for each dimension.
+ * @private
+ */
+ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) {
+ vertex[0] = vertex[0] * scale[0] + translate[0];
+ vertex[1] = vertex[1] * scale[1] + translate[1];
+};
+
+
+/**
+ * Read the projection from a TopoJSON source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} object Source.
+ * @return {ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.TopoJSON.prototype.readProjection = function(object) {
+ return this.defaultDataProjection;
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>}
+ */
+ol.format.TopoJSON.GEOMETRY_READERS_ = {
+ 'Point': ol.format.TopoJSON.readPointGeometry_,
+ 'LineString': ol.format.TopoJSON.readLineStringGeometry_,
+ 'Polygon': ol.format.TopoJSON.readPolygonGeometry_,
+ 'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_,
+ 'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_,
+ 'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_
+};
+
+goog.provide('ol.format.WFS');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.format.GML3');
+goog.require('ol.format.GMLBase');
+goog.require('ol.format.ogc.filter');
+goog.require('ol.format.ogc.filter.Bbox');
+goog.require('ol.format.ogc.filter.ComparisonBinary');
+goog.require('ol.format.ogc.filter.LogicalBinary');
+goog.require('ol.format.ogc.filter.Not');
+goog.require('ol.format.ogc.filter.IsBetween');
+goog.require('ol.format.ogc.filter.IsNull');
+goog.require('ol.format.ogc.filter.IsLike');
+goog.require('ol.format.XMLFeature');
+goog.require('ol.format.XSD');
+goog.require('ol.geom.Geometry');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Feature format for reading and writing data in the WFS format.
+ * By default, supports WFS version 1.1.0. You can pass a GML format
+ * as option if you want to read a WFS that contains GML2 (WFS 1.0.0).
+ * Also see {@link ol.format.GMLBase} which is used by this format.
+ *
+ * @constructor
+ * @param {olx.format.WFSOptions=} opt_options
+ * Optional configuration object.
+ * @extends {ol.format.XMLFeature}
+ * @api stable
+ */
+ol.format.WFS = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {Array.<string>|string|undefined}
+ */
+ this.featureType_ = options.featureType;
+
+ /**
+ * @private
+ * @type {Object.<string, string>|string|undefined}
+ */
+ this.featureNS_ = options.featureNS;
+
+ /**
+ * @private
+ * @type {ol.format.GMLBase}
+ */
+ this.gmlFormat_ = options.gmlFormat ?
+ options.gmlFormat : new ol.format.GML3();
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.schemaLocation_ = options.schemaLocation ?
+ options.schemaLocation : ol.format.WFS.SCHEMA_LOCATION;
+
+ ol.format.XMLFeature.call(this);
+};
+ol.inherits(ol.format.WFS, ol.format.XMLFeature);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.WFS.FEATURE_PREFIX = 'feature';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/';
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.WFS.SCHEMA_LOCATION = 'http://www.opengis.net/wfs ' +
+ 'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd';
+
+
+/**
+ * Read all features from a WFS FeatureCollection.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.WFS.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) {
+ var context = /** @type {ol.XmlNodeStackItem} */ ({
+ 'featureType': this.featureType_,
+ 'featureNS': this.featureNS_
+ });
+ ol.object.assign(context, this.getReadOptions(node,
+ opt_options ? opt_options : {}));
+ var objectStack = [context];
+ this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][
+ 'featureMember'] =
+ ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);
+ var features = ol.xml.pushParseAndPop([],
+ this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
+ objectStack, this.gmlFormat_);
+ if (!features) {
+ features = [];
+ }
+ return features;
+};
+
+
+/**
+ * Read transaction response of the source.
+ *
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.WFSTransactionResponse|undefined} Transaction response.
+ * @api stable
+ */
+ol.format.WFS.prototype.readTransactionResponse = function(source) {
+ if (ol.xml.isDocument(source)) {
+ return this.readTransactionResponseFromDocument(
+ /** @type {Document} */ (source));
+ } else if (ol.xml.isNode(source)) {
+ return this.readTransactionResponseFromNode(/** @type {Node} */ (source));
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readTransactionResponseFromDocument(doc);
+ } else {
+ goog.asserts.fail('Unknown source type');
+ return undefined;
+ }
+};
+
+
+/**
+ * Read feature collection metadata of the source.
+ *
+ * @param {Document|Node|Object|string} source Source.
+ * @return {ol.WFSFeatureCollectionMetadata|undefined}
+ * FeatureCollection metadata.
+ * @api stable
+ */
+ol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) {
+ if (ol.xml.isDocument(source)) {
+ return this.readFeatureCollectionMetadataFromDocument(
+ /** @type {Document} */ (source));
+ } else if (ol.xml.isNode(source)) {
+ return this.readFeatureCollectionMetadataFromNode(
+ /** @type {Node} */ (source));
+ } else if (typeof source === 'string') {
+ var doc = ol.xml.parse(source);
+ return this.readFeatureCollectionMetadataFromDocument(doc);
+ } else {
+ goog.asserts.fail('Unknown source type');
+ return undefined;
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {ol.WFSFeatureCollectionMetadata|undefined}
+ * FeatureCollection metadata.
+ */
+ol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument = function(doc) {
+ goog.asserts.assert(doc.nodeType == Node.DOCUMENT_NODE,
+ 'doc.nodeType should be DOCUMENT');
+ for (var n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ return this.readFeatureCollectionMetadataFromNode(n);
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WFS.FEATURE_COLLECTION_PARSERS_ = {
+ 'http://www.opengis.net/gml': {
+ 'boundedBy': ol.xml.makeObjectPropertySetter(
+ ol.format.GMLBase.prototype.readGeometryElement, 'bounds')
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {ol.WFSFeatureCollectionMetadata|undefined}
+ * FeatureCollection metadata.
+ */
+ol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'FeatureCollection',
+ 'localName should be FeatureCollection');
+ var result = {};
+ var value = ol.format.XSD.readNonNegativeIntegerString(
+ node.getAttribute('numberOfFeatures'));
+ result['numberOfFeatures'] = value;
+ return ol.xml.pushParseAndPop(
+ /** @type {ol.WFSFeatureCollectionMetadata} */ (result),
+ ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_);
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = {
+ 'http://www.opengis.net/wfs': {
+ 'totalInserted': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'totalUpdated': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'totalDeleted': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger)
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Transaction Summary.
+ * @private
+ */
+ol.format.WFS.readTransactionSummary_ = function(node, objectStack) {
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WFS.OGC_FID_PARSERS_ = {
+ 'http://www.opengis.net/ogc': {
+ 'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) {
+ return node.getAttribute('fid');
+ })
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ */
+ol.format.WFS.fidParser_ = function(node, objectStack) {
+ ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WFS.INSERT_RESULTS_PARSERS_ = {
+ 'http://www.opengis.net/wfs': {
+ 'Feature': ol.format.WFS.fidParser_
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Array.<string>|undefined} Insert results.
+ * @private
+ */
+ol.format.WFS.readInsertResults_ = function(node, objectStack) {
+ return ol.xml.pushParseAndPop(
+ [], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = {
+ 'http://www.opengis.net/wfs': {
+ 'TransactionSummary': ol.xml.makeObjectPropertySetter(
+ ol.format.WFS.readTransactionSummary_, 'transactionSummary'),
+ 'InsertResults': ol.xml.makeObjectPropertySetter(
+ ol.format.WFS.readInsertResults_, 'insertIds')
+ }
+};
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {ol.WFSTransactionResponse|undefined} Transaction response.
+ */
+ol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) {
+ goog.asserts.assert(doc.nodeType == Node.DOCUMENT_NODE,
+ 'doc.nodeType should be DOCUMENT');
+ for (var n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ return this.readTransactionResponseFromNode(n);
+ }
+ }
+ return undefined;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {ol.WFSTransactionResponse|undefined} Transaction response.
+ */
+ol.format.WFS.prototype.readTransactionResponseFromNode = function(node) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'TransactionResponse',
+ 'localName should be TransactionResponse');
+ return ol.xml.pushParseAndPop(
+ /** @type {ol.WFSTransactionResponse} */({}),
+ ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []);
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.WFS.QUERY_SERIALIZERS_ = {
+ 'http://www.opengis.net/wfs': {
+ 'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeFeature_ = function(node, feature, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var featureType = context['featureType'];
+ var featureNS = context['featureNS'];
+ var child = ol.xml.createElementNS(featureNS, featureType);
+ node.appendChild(child);
+ ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {number|string} fid Feature identifier.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) {
+ var filter = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter');
+ var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'FeatureId');
+ filter.appendChild(child);
+ child.setAttribute('fid', fid);
+ node.appendChild(filter);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ goog.asserts.assert(feature.getId() !== undefined, 'feature should have an id');
+ var featureType = context['featureType'];
+ var featurePrefix = context['featurePrefix'];
+ featurePrefix = featurePrefix ? featurePrefix :
+ ol.format.WFS.FEATURE_PREFIX;
+ var featureNS = context['featureNS'];
+ node.setAttribute('typeName', featurePrefix + ':' + featureType);
+ ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
+ featureNS);
+ var fid = feature.getId();
+ if (fid !== undefined) {
+ ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.Feature} feature Feature.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ goog.asserts.assert(feature.getId() !== undefined, 'feature should have an id');
+ var featureType = context['featureType'];
+ var featurePrefix = context['featurePrefix'];
+ featurePrefix = featurePrefix ? featurePrefix :
+ ol.format.WFS.FEATURE_PREFIX;
+ var featureNS = context['featureNS'];
+ node.setAttribute('typeName', featurePrefix + ':' + featureType);
+ ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
+ featureNS);
+ var fid = feature.getId();
+ if (fid !== undefined) {
+ var keys = feature.getKeys();
+ var values = [];
+ for (var i = 0, ii = keys.length; i < ii; i++) {
+ var value = feature.get(keys[i]);
+ if (value !== undefined) {
+ values.push({name: keys[i], value: value});
+ }
+ }
+ ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */ (
+ {node: node, 'srsName': context['srsName']}),
+ ol.format.WFS.TRANSACTION_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('Property'), values,
+ objectStack);
+ ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Object} pair Property name and value.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeProperty_ = function(node, pair, objectStack) {
+ var name = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Name');
+ node.appendChild(name);
+ ol.format.XSD.writeStringTextNode(name, pair.name);
+ if (pair.value !== undefined && pair.value !== null) {
+ var value = ol.xml.createElementNS('http://www.opengis.net/wfs', 'Value');
+ node.appendChild(value);
+ if (pair.value instanceof ol.geom.Geometry) {
+ ol.format.GML3.prototype.writeGeometryElement(value,
+ pair.value, objectStack);
+ } else {
+ ol.format.XSD.writeStringTextNode(value, pair.value);
+ }
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {{vendorId: string, safeToIgnore: boolean, value: string}}
+ * nativeElement The native element.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) {
+ if (nativeElement.vendorId) {
+ node.setAttribute('vendorId', nativeElement.vendorId);
+ }
+ if (nativeElement.safeToIgnore !== undefined) {
+ node.setAttribute('safeToIgnore', nativeElement.safeToIgnore);
+ }
+ if (nativeElement.value !== undefined) {
+ ol.format.XSD.writeStringTextNode(node, nativeElement.value);
+ }
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.WFS.TRANSACTION_SERIALIZERS_ = {
+ 'http://www.opengis.net/wfs': {
+ 'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_),
+ 'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_),
+ 'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_),
+ 'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_),
+ 'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_)
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {string} featureType Feature type.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeQuery_ = function(node, featureType, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var featurePrefix = context['featurePrefix'];
+ var featureNS = context['featureNS'];
+ var propertyNames = context['propertyNames'];
+ var srsName = context['srsName'];
+ var prefix = featurePrefix ? featurePrefix + ':' : '';
+ node.setAttribute('typeName', prefix + featureType);
+ if (srsName) {
+ node.setAttribute('srsName', srsName);
+ }
+ if (featureNS) {
+ ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
+ featureNS);
+ }
+ var item = /** @type {ol.XmlNodeStackItem} */ (ol.object.assign({}, context));
+ item.node = node;
+ ol.xml.pushSerializeAndPop(item,
+ ol.format.WFS.QUERY_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames,
+ objectStack);
+ var filter = context['filter'];
+ if (filter) {
+ var child = ol.xml.createElementNS('http://www.opengis.net/ogc', 'Filter');
+ node.appendChild(child);
+ ol.format.WFS.writeFilterCondition_(child, filter, objectStack);
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeFilterCondition_ = function(node, filter, objectStack) {
+ /** @type {ol.XmlNodeStackItem} */
+ var item = {node: node};
+ ol.xml.pushSerializeAndPop(item,
+ ol.format.WFS.GETFEATURE_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory(filter.getTagName()),
+ [filter], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeBboxFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.Bbox,
+ 'must be bbox filter');
+
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ context['srsName'] = filter.srsName;
+
+ ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);
+ ol.format.GML3.prototype.writeGeometryElement(node, filter.extent, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeLogicalFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.LogicalBinary,
+ 'must be logical filter');
+ /** @type {ol.XmlNodeStackItem} */
+ var item = {node: node};
+ var conditionA = filter.conditionA;
+ ol.xml.pushSerializeAndPop(item,
+ ol.format.WFS.GETFEATURE_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory(conditionA.getTagName()),
+ [conditionA], objectStack);
+ var conditionB = filter.conditionB;
+ ol.xml.pushSerializeAndPop(item,
+ ol.format.WFS.GETFEATURE_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory(conditionB.getTagName()),
+ [conditionB], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeNotFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.Not,
+ 'must be Not filter');
+ /** @type {ol.XmlNodeStackItem} */
+ var item = {node: node};
+ var condition = filter.condition;
+ ol.xml.pushSerializeAndPop(item,
+ ol.format.WFS.GETFEATURE_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory(condition.getTagName()),
+ [condition], objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeComparisonFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.ComparisonBinary,
+ 'must be binary comparison filter');
+ if (filter.matchCase !== undefined) {
+ node.setAttribute('matchCase', filter.matchCase.toString());
+ }
+ ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
+ ol.format.WFS.writeOgcLiteral_(node, '' + filter.expression);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeIsNullFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.IsNull,
+ 'must be IsNull comparison filter');
+ ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeIsBetweenFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.IsBetween,
+ 'must be IsBetween comparison filter');
+ ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
+ ol.format.WFS.writeOgcExpression_('LowerBoundary', node, '' + filter.lowerBoundary);
+ ol.format.WFS.writeOgcExpression_('UpperBoundary', node, '' + filter.upperBoundary);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {ol.format.ogc.filter.Filter} filter Filter.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeIsLikeFilter_ = function(node, filter, objectStack) {
+ goog.asserts.assertInstanceof(filter, ol.format.ogc.filter.IsLike,
+ 'must be IsLike comparison filter');
+ node.setAttribute('wildCard', filter.wildCard);
+ node.setAttribute('singleChar', filter.singleChar);
+ node.setAttribute('escapeChar', filter.escapeChar);
+ if (filter.matchCase !== undefined) {
+ node.setAttribute('matchCase', filter.matchCase.toString());
+ }
+ ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
+ ol.format.WFS.writeOgcLiteral_(node, '' + filter.pattern);
+};
+
+
+/**
+ * @param {string} tagName Tag name.
+ * @param {Node} node Node.
+ * @param {string} value Value.
+ * @private
+ */
+ol.format.WFS.writeOgcExpression_ = function(tagName, node, value) {
+ var property = ol.xml.createElementNS('http://www.opengis.net/ogc', tagName);
+ ol.format.XSD.writeStringTextNode(property, value);
+ node.appendChild(property);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {string} value PropertyName value.
+ * @private
+ */
+ol.format.WFS.writeOgcPropertyName_ = function(node, value) {
+ ol.format.WFS.writeOgcExpression_('PropertyName', node, value);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {string} value PropertyName value.
+ * @private
+ */
+ol.format.WFS.writeOgcLiteral_ = function(node, value) {
+ ol.format.WFS.writeOgcExpression_('Literal', node, value);
+};
+
+
+/**
+ * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
+ * @private
+ */
+ol.format.WFS.GETFEATURE_SERIALIZERS_ = {
+ 'http://www.opengis.net/wfs': {
+ 'Query': ol.xml.makeChildAppender(ol.format.WFS.writeQuery_)
+ },
+ 'http://www.opengis.net/ogc': {
+ 'And': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
+ 'Or': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
+ 'Not': ol.xml.makeChildAppender(ol.format.WFS.writeNotFilter_),
+ 'BBOX': ol.xml.makeChildAppender(ol.format.WFS.writeBboxFilter_),
+ 'PropertyIsEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
+ 'PropertyIsNotEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
+ 'PropertyIsLessThan': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
+ 'PropertyIsLessThanOrEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
+ 'PropertyIsGreaterThan': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
+ 'PropertyIsGreaterThanOrEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
+ 'PropertyIsNull': ol.xml.makeChildAppender(ol.format.WFS.writeIsNullFilter_),
+ 'PropertyIsBetween': ol.xml.makeChildAppender(ol.format.WFS.writeIsBetweenFilter_),
+ 'PropertyIsLike': ol.xml.makeChildAppender(ol.format.WFS.writeIsLikeFilter_)
+ }
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<{string}>} featureTypes Feature types.
+ * @param {Array.<*>} objectStack Node stack.
+ * @private
+ */
+ol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) {
+ var context = objectStack[objectStack.length - 1];
+ goog.asserts.assert(goog.isObject(context), 'context should be an Object');
+ var item = /** @type {ol.XmlNodeStackItem} */ (ol.object.assign({}, context));
+ item.node = node;
+ ol.xml.pushSerializeAndPop(item,
+ ol.format.WFS.GETFEATURE_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('Query'), featureTypes,
+ objectStack);
+};
+
+
+/**
+ * Encode format as WFS `GetFeature` and return the Node.
+ *
+ * @param {olx.format.WFSWriteGetFeatureOptions} options Options.
+ * @return {Node} Result.
+ * @api stable
+ */
+ol.format.WFS.prototype.writeGetFeature = function(options) {
+ var node = ol.xml.createElementNS('http://www.opengis.net/wfs',
+ 'GetFeature');
+ node.setAttribute('service', 'WFS');
+ node.setAttribute('version', '1.1.0');
+ var filter;
+ if (options) {
+ if (options.handle) {
+ node.setAttribute('handle', options.handle);
+ }
+ if (options.outputFormat) {
+ node.setAttribute('outputFormat', options.outputFormat);
+ }
+ if (options.maxFeatures !== undefined) {
+ node.setAttribute('maxFeatures', options.maxFeatures);
+ }
+ if (options.resultType) {
+ node.setAttribute('resultType', options.resultType);
+ }
+ if (options.startIndex !== undefined) {
+ node.setAttribute('startIndex', options.startIndex);
+ }
+ if (options.count !== undefined) {
+ node.setAttribute('count', options.count);
+ }
+ filter = options.filter;
+ if (options.bbox) {
+ goog.asserts.assert(options.geometryName,
+ 'geometryName must be set when using bbox filter');
+ var bbox = ol.format.ogc.filter.bbox(
+ options.geometryName, options.bbox, options.srsName);
+ if (filter) {
+ // if bbox and filter are both set, combine the two into a single filter
+ filter = ol.format.ogc.filter.and(filter, bbox);
+ } else {
+ filter = bbox;
+ }
+ }
+ }
+ ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation', this.schemaLocation_);
+ /** @type {ol.XmlNodeStackItem} */
+ var context = {
+ node: node,
+ 'srsName': options.srsName,
+ 'featureNS': options.featureNS ? options.featureNS : this.featureNS_,
+ 'featurePrefix': options.featurePrefix,
+ 'geometryName': options.geometryName,
+ 'filter': filter,
+ 'propertyNames': options.propertyNames ? options.propertyNames : []
+ };
+ goog.asserts.assert(Array.isArray(options.featureTypes),
+ 'options.featureTypes should be an array');
+ ol.format.WFS.writeGetFeature_(node, options.featureTypes, [context]);
+ return node;
+};
+
+
+/**
+ * Encode format as WFS `Transaction` and return the Node.
+ *
+ * @param {Array.<ol.Feature>} inserts The features to insert.
+ * @param {Array.<ol.Feature>} updates The features to update.
+ * @param {Array.<ol.Feature>} deletes The features to delete.
+ * @param {olx.format.WFSWriteTransactionOptions} options Write options.
+ * @return {Node} Result.
+ * @api stable
+ */
+ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes,
+ options) {
+ var objectStack = [];
+ var node = ol.xml.createElementNS('http://www.opengis.net/wfs',
+ 'Transaction');
+ node.setAttribute('service', 'WFS');
+ node.setAttribute('version', '1.1.0');
+ var baseObj;
+ /** @type {ol.XmlNodeStackItem} */
+ var obj;
+ if (options) {
+ baseObj = options.gmlOptions ? options.gmlOptions : {};
+ if (options.handle) {
+ node.setAttribute('handle', options.handle);
+ }
+ }
+ ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation', this.schemaLocation_);
+ if (inserts) {
+ obj = {node: node, 'featureNS': options.featureNS,
+ 'featureType': options.featureType, 'featurePrefix': options.featurePrefix,
+ 'srsName': options.srsName};
+ ol.object.assign(obj, baseObj);
+ ol.xml.pushSerializeAndPop(obj,
+ ol.format.WFS.TRANSACTION_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('Insert'), inserts,
+ objectStack);
+ }
+ if (updates) {
+ obj = {node: node, 'featureNS': options.featureNS,
+ 'featureType': options.featureType, 'featurePrefix': options.featurePrefix,
+ 'srsName': options.srsName};
+ ol.object.assign(obj, baseObj);
+ ol.xml.pushSerializeAndPop(obj,
+ ol.format.WFS.TRANSACTION_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('Update'), updates,
+ objectStack);
+ }
+ if (deletes) {
+ ol.xml.pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
+ 'featureType': options.featureType, 'featurePrefix': options.featurePrefix,
+ 'srsName': options.srsName},
+ ol.format.WFS.TRANSACTION_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('Delete'), deletes,
+ objectStack);
+ }
+ if (options.nativeElements) {
+ ol.xml.pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
+ 'featureType': options.featureType, 'featurePrefix': options.featurePrefix,
+ 'srsName': options.srsName},
+ ol.format.WFS.TRANSACTION_SERIALIZERS_,
+ ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements,
+ objectStack);
+ }
+ return node;
+};
+
+
+/**
+ * Read the projection from a WFS source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @return {?ol.proj.Projection} Projection.
+ * @api stable
+ */
+ol.format.WFS.prototype.readProjection;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WFS.prototype.readProjectionFromDocument = function(doc) {
+ goog.asserts.assert(doc.nodeType == Node.DOCUMENT_NODE,
+ 'doc.nodeType should be a DOCUMENT');
+ for (var n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ return this.readProjectionFromNode(n);
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WFS.prototype.readProjectionFromNode = function(node) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'FeatureCollection',
+ 'localName should be FeatureCollection');
+
+ if (node.firstElementChild &&
+ node.firstElementChild.firstElementChild) {
+ node = node.firstElementChild.firstElementChild;
+ for (var n = node.firstElementChild; n; n = n.nextElementSibling) {
+ if (!(n.childNodes.length === 0 ||
+ (n.childNodes.length === 1 &&
+ n.firstChild.nodeType === 3))) {
+ var objectStack = [{}];
+ this.gmlFormat_.readGeometryElement(n, objectStack);
+ return ol.proj.get(objectStack.pop().srsName);
+ }
+ }
+ }
+
+ return null;
+};
+
+goog.provide('ol.format.WKT');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.Feature');
+goog.require('ol.format.Feature');
+goog.require('ol.format.TextFeature');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryCollection');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+
+
+/**
+ * @classdesc
+ * Geometry format for reading and writing data in the `WellKnownText` (WKT)
+ * format.
+ *
+ * @constructor
+ * @extends {ol.format.TextFeature}
+ * @param {olx.format.WKTOptions=} opt_options Options.
+ * @api stable
+ */
+ol.format.WKT = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.format.TextFeature.call(this);
+
+ /**
+ * Split GeometryCollection into multiple features.
+ * @type {boolean}
+ * @private
+ */
+ this.splitCollection_ = options.splitCollection !== undefined ?
+ options.splitCollection : false;
+
+};
+ol.inherits(ol.format.WKT, ol.format.TextFeature);
+
+
+/**
+ * @const
+ * @type {string}
+ */
+ol.format.WKT.EMPTY = 'EMPTY';
+
+
+/**
+ * @param {ol.geom.Point} geom Point geometry.
+ * @return {string} Coordinates part of Point as WKT.
+ * @private
+ */
+ol.format.WKT.encodePointGeometry_ = function(geom) {
+ var coordinates = geom.getCoordinates();
+ if (coordinates.length === 0) {
+ return '';
+ }
+ return coordinates[0] + ' ' + coordinates[1];
+};
+
+
+/**
+ * @param {ol.geom.MultiPoint} geom MultiPoint geometry.
+ * @return {string} Coordinates part of MultiPoint as WKT.
+ * @private
+ */
+ol.format.WKT.encodeMultiPointGeometry_ = function(geom) {
+ var array = [];
+ var components = geom.getPoints();
+ for (var i = 0, ii = components.length; i < ii; ++i) {
+ array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')');
+ }
+ return array.join(',');
+};
+
+
+/**
+ * @param {ol.geom.GeometryCollection} geom GeometryCollection geometry.
+ * @return {string} Coordinates part of GeometryCollection as WKT.
+ * @private
+ */
+ol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) {
+ var array = [];
+ var geoms = geom.getGeometries();
+ for (var i = 0, ii = geoms.length; i < ii; ++i) {
+ array.push(ol.format.WKT.encode_(geoms[i]));
+ }
+ return array.join(',');
+};
+
+
+/**
+ * @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry.
+ * @return {string} Coordinates part of LineString as WKT.
+ * @private
+ */
+ol.format.WKT.encodeLineStringGeometry_ = function(geom) {
+ var coordinates = geom.getCoordinates();
+ var array = [];
+ for (var i = 0, ii = coordinates.length; i < ii; ++i) {
+ array.push(coordinates[i][0] + ' ' + coordinates[i][1]);
+ }
+ return array.join(',');
+};
+
+
+/**
+ * @param {ol.geom.MultiLineString} geom MultiLineString geometry.
+ * @return {string} Coordinates part of MultiLineString as WKT.
+ * @private
+ */
+ol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) {
+ var array = [];
+ var components = geom.getLineStrings();
+ for (var i = 0, ii = components.length; i < ii; ++i) {
+ array.push('(' + ol.format.WKT.encodeLineStringGeometry_(
+ components[i]) + ')');
+ }
+ return array.join(',');
+};
+
+
+/**
+ * @param {ol.geom.Polygon} geom Polygon geometry.
+ * @return {string} Coordinates part of Polygon as WKT.
+ * @private
+ */
+ol.format.WKT.encodePolygonGeometry_ = function(geom) {
+ var array = [];
+ var rings = geom.getLinearRings();
+ for (var i = 0, ii = rings.length; i < ii; ++i) {
+ array.push('(' + ol.format.WKT.encodeLineStringGeometry_(
+ rings[i]) + ')');
+ }
+ return array.join(',');
+};
+
+
+/**
+ * @param {ol.geom.MultiPolygon} geom MultiPolygon geometry.
+ * @return {string} Coordinates part of MultiPolygon as WKT.
+ * @private
+ */
+ol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) {
+ var array = [];
+ var components = geom.getPolygons();
+ for (var i = 0, ii = components.length; i < ii; ++i) {
+ array.push('(' + ol.format.WKT.encodePolygonGeometry_(
+ components[i]) + ')');
+ }
+ return array.join(',');
+};
+
+
+/**
+ * Encode a geometry as WKT.
+ * @param {ol.geom.Geometry} geom The geometry to encode.
+ * @return {string} WKT string for the geometry.
+ * @private
+ */
+ol.format.WKT.encode_ = function(geom) {
+ var type = geom.getType();
+ var geometryEncoder = ol.format.WKT.GeometryEncoder_[type];
+ goog.asserts.assert(geometryEncoder, 'geometryEncoder should be defined');
+ var enc = geometryEncoder(geom);
+ type = type.toUpperCase();
+ if (enc.length === 0) {
+ return type + ' ' + ol.format.WKT.EMPTY;
+ }
+ return type + '(' + enc + ')';
+};
+
+
+/**
+ * @const
+ * @type {Object.<string, function(ol.geom.Geometry): string>}
+ * @private
+ */
+ol.format.WKT.GeometryEncoder_ = {
+ 'Point': ol.format.WKT.encodePointGeometry_,
+ 'LineString': ol.format.WKT.encodeLineStringGeometry_,
+ 'Polygon': ol.format.WKT.encodePolygonGeometry_,
+ 'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_,
+ 'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_,
+ 'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_,
+ 'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_
+};
+
+
+/**
+ * Parse a WKT string.
+ * @param {string} wkt WKT string.
+ * @return {ol.geom.Geometry|ol.geom.GeometryCollection|undefined}
+ * The geometry created.
+ * @private
+ */
+ol.format.WKT.prototype.parse_ = function(wkt) {
+ var lexer = new ol.format.WKT.Lexer(wkt);
+ var parser = new ol.format.WKT.Parser(lexer);
+ return parser.parse();
+};
+
+
+/**
+ * Read a feature from a WKT source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.Feature} Feature.
+ * @api stable
+ */
+ol.format.WKT.prototype.readFeature;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) {
+ var geom = this.readGeometryFromText(text, opt_options);
+ if (geom) {
+ var feature = new ol.Feature();
+ feature.setGeometry(geom);
+ return feature;
+ }
+ return null;
+};
+
+
+/**
+ * Read all features from a WKT source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.WKT.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) {
+ var geometries = [];
+ var geometry = this.readGeometryFromText(text, opt_options);
+ if (this.splitCollection_ &&
+ geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
+ geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry))
+ .getGeometriesArray();
+ } else {
+ geometries = [geometry];
+ }
+ var feature, features = [];
+ for (var i = 0, ii = geometries.length; i < ii; ++i) {
+ feature = new ol.Feature();
+ feature.setGeometry(geometries[i]);
+ features.push(feature);
+ }
+ return features;
+};
+
+
+/**
+ * Read a single geometry from a WKT source.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Read options.
+ * @return {ol.geom.Geometry} Geometry.
+ * @api stable
+ */
+ol.format.WKT.prototype.readGeometry;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) {
+ var geometry = this.parse_(text);
+ if (geometry) {
+ return /** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(geometry, false, opt_options));
+ } else {
+ return null;
+ }
+};
+
+
+/**
+ * Encode a feature as a WKT string.
+ *
+ * @function
+ * @param {ol.Feature} feature Feature.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} WKT string.
+ * @api stable
+ */
+ol.format.WKT.prototype.writeFeature;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) {
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ return this.writeGeometryText(geometry, opt_options);
+ }
+ return '';
+};
+
+
+/**
+ * Encode an array of features as a WKT string.
+ *
+ * @function
+ * @param {Array.<ol.Feature>} features Features.
+ * @param {olx.format.WriteOptions=} opt_options Write options.
+ * @return {string} WKT string.
+ * @api stable
+ */
+ol.format.WKT.prototype.writeFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) {
+ if (features.length == 1) {
+ return this.writeFeatureText(features[0], opt_options);
+ }
+ var geometries = [];
+ for (var i = 0, ii = features.length; i < ii; ++i) {
+ geometries.push(features[i].getGeometry());
+ }
+ var collection = new ol.geom.GeometryCollection(geometries);
+ return this.writeGeometryText(collection, opt_options);
+};
+
+
+/**
+ * Write a single geometry as a WKT string.
+ *
+ * @function
+ * @param {ol.geom.Geometry} geometry Geometry.
+ * @return {string} WKT string.
+ * @api stable
+ */
+ol.format.WKT.prototype.writeGeometry;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) {
+ return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ (
+ ol.format.Feature.transformWithOptions(geometry, true, opt_options)));
+};
+
+
+/**
+ * @const
+ * @enum {number}
+ */
+ol.format.WKT.TokenType = {
+ TEXT: 1,
+ LEFT_PAREN: 2,
+ RIGHT_PAREN: 3,
+ NUMBER: 4,
+ COMMA: 5,
+ EOF: 6
+};
+
+
+/**
+ * Class to tokenize a WKT string.
+ * @param {string} wkt WKT string.
+ * @constructor
+ * @protected
+ */
+ol.format.WKT.Lexer = function(wkt) {
+
+ /**
+ * @type {string}
+ */
+ this.wkt = wkt;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.index_ = -1;
+};
+
+
+/**
+ * @param {string} c Character.
+ * @return {boolean} Whether the character is alphabetic.
+ * @private
+ */
+ol.format.WKT.Lexer.prototype.isAlpha_ = function(c) {
+ return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
+};
+
+
+/**
+ * @param {string} c Character.
+ * @param {boolean=} opt_decimal Whether the string number
+ * contains a dot, i.e. is a decimal number.
+ * @return {boolean} Whether the character is numeric.
+ * @private
+ */
+ol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) {
+ var decimal = opt_decimal !== undefined ? opt_decimal : false;
+ return c >= '0' && c <= '9' || c == '.' && !decimal;
+};
+
+
+/**
+ * @param {string} c Character.
+ * @return {boolean} Whether the character is whitespace.
+ * @private
+ */
+ol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) {
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+};
+
+
+/**
+ * @return {string} Next string character.
+ * @private
+ */
+ol.format.WKT.Lexer.prototype.nextChar_ = function() {
+ return this.wkt.charAt(++this.index_);
+};
+
+
+/**
+ * Fetch and return the next token.
+ * @return {!ol.WKTToken} Next string token.
+ */
+ol.format.WKT.Lexer.prototype.nextToken = function() {
+ var c = this.nextChar_();
+ var token = {position: this.index_, value: c};
+
+ if (c == '(') {
+ token.type = ol.format.WKT.TokenType.LEFT_PAREN;
+ } else if (c == ',') {
+ token.type = ol.format.WKT.TokenType.COMMA;
+ } else if (c == ')') {
+ token.type = ol.format.WKT.TokenType.RIGHT_PAREN;
+ } else if (this.isNumeric_(c) || c == '-') {
+ token.type = ol.format.WKT.TokenType.NUMBER;
+ token.value = this.readNumber_();
+ } else if (this.isAlpha_(c)) {
+ token.type = ol.format.WKT.TokenType.TEXT;
+ token.value = this.readText_();
+ } else if (this.isWhiteSpace_(c)) {
+ return this.nextToken();
+ } else if (c === '') {
+ token.type = ol.format.WKT.TokenType.EOF;
+ } else {
+ throw new Error('Unexpected character: ' + c);
+ }
+
+ return token;
+};
+
+
+/**
+ * @return {number} Numeric token value.
+ * @private
+ */
+ol.format.WKT.Lexer.prototype.readNumber_ = function() {
+ var c, index = this.index_;
+ var decimal = false;
+ var scientificNotation = false;
+ do {
+ if (c == '.') {
+ decimal = true;
+ } else if (c == 'e' || c == 'E') {
+ scientificNotation = true;
+ }
+ c = this.nextChar_();
+ } while (
+ this.isNumeric_(c, decimal) ||
+ // if we haven't detected a scientific number before, 'e' or 'E'
+ // hint that we should continue to read
+ !scientificNotation && (c == 'e' || c == 'E') ||
+ // once we know that we have a scientific number, both '-' and '+'
+ // are allowed
+ scientificNotation && (c == '-' || c == '+')
+ );
+ return parseFloat(this.wkt.substring(index, this.index_--));
+};
+
+
+/**
+ * @return {string} String token value.
+ * @private
+ */
+ol.format.WKT.Lexer.prototype.readText_ = function() {
+ var c, index = this.index_;
+ do {
+ c = this.nextChar_();
+ } while (this.isAlpha_(c));
+ return this.wkt.substring(index, this.index_--).toUpperCase();
+};
+
+
+/**
+ * Class to parse the tokens from the WKT string.
+ * @param {ol.format.WKT.Lexer} lexer The lexer.
+ * @constructor
+ * @protected
+ */
+ol.format.WKT.Parser = function(lexer) {
+
+ /**
+ * @type {ol.format.WKT.Lexer}
+ * @private
+ */
+ this.lexer_ = lexer;
+
+ /**
+ * @type {ol.WKTToken}
+ * @private
+ */
+ this.token_;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.dimension_ = 2;
+};
+
+
+/**
+ * Fetch the next token form the lexer and replace the active token.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.consume_ = function() {
+ this.token_ = this.lexer_.nextToken();
+};
+
+
+/**
+ * If the given type matches the current token, consume it.
+ * @param {ol.format.WKT.TokenType} type Token type.
+ * @return {boolean} Whether the token matches the given type.
+ */
+ol.format.WKT.Parser.prototype.match = function(type) {
+ var isMatch = this.token_.type == type;
+ if (isMatch) {
+ this.consume_();
+ }
+ return isMatch;
+};
+
+
+/**
+ * Try to parse the tokens provided by the lexer.
+ * @return {ol.geom.Geometry|ol.geom.GeometryCollection} The geometry.
+ */
+ol.format.WKT.Parser.prototype.parse = function() {
+ this.consume_();
+ var geometry = this.parseGeometry_();
+ goog.asserts.assert(this.token_.type == ol.format.WKT.TokenType.EOF,
+ 'token type should be end of file');
+ return geometry;
+};
+
+
+/**
+ * @return {!(ol.geom.Geometry|ol.geom.GeometryCollection)} The geometry.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseGeometry_ = function() {
+ var token = this.token_;
+ if (this.match(ol.format.WKT.TokenType.TEXT)) {
+ var geomType = token.value;
+ if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) {
+ var geometries = this.parseGeometryCollectionText_();
+ return new ol.geom.GeometryCollection(geometries);
+ } else {
+ var parser = ol.format.WKT.Parser.GeometryParser_[geomType];
+ var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType];
+ if (!parser || !ctor) {
+ throw new Error('Invalid geometry type: ' + geomType);
+ }
+ var coordinates = parser.call(this);
+ return new ctor(coordinates);
+ }
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<ol.geom.Geometry>} A collection of geometries.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var geometries = [];
+ do {
+ geometries.push(this.parseGeometry_());
+ } while (this.match(ol.format.WKT.TokenType.COMMA));
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return geometries;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return [];
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {Array.<number>} All values in a point.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parsePointText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var coordinates = this.parsePoint_();
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return coordinates;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return null;
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} All points in a linestring.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseLineStringText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var coordinates = this.parsePointList_();
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return coordinates;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return [];
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} All points in a polygon.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parsePolygonText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var coordinates = this.parseLineStringTextList_();
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return coordinates;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return [];
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} All points in a multipoint.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseMultiPointText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var coordinates;
+ if (this.token_.type == ol.format.WKT.TokenType.LEFT_PAREN) {
+ coordinates = this.parsePointTextList_();
+ } else {
+ coordinates = this.parsePointList_();
+ }
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return coordinates;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return [];
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} All linestring points
+ * in a multilinestring.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var coordinates = this.parseLineStringTextList_();
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return coordinates;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return [];
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} All polygon points in a multipolygon.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() {
+ if (this.match(ol.format.WKT.TokenType.LEFT_PAREN)) {
+ var coordinates = this.parsePolygonTextList_();
+ if (this.match(ol.format.WKT.TokenType.RIGHT_PAREN)) {
+ return coordinates;
+ }
+ } else if (this.isEmptyGeometry_()) {
+ return [];
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<number>} A point.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parsePoint_ = function() {
+ var coordinates = [];
+ for (var i = 0; i < this.dimension_; ++i) {
+ var token = this.token_;
+ if (this.match(ol.format.WKT.TokenType.NUMBER)) {
+ coordinates.push(token.value);
+ } else {
+ break;
+ }
+ }
+ if (coordinates.length == this.dimension_) {
+ return coordinates;
+ }
+ throw new Error(this.formatErrorMessage_());
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} An array of points.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parsePointList_ = function() {
+ var coordinates = [this.parsePoint_()];
+ while (this.match(ol.format.WKT.TokenType.COMMA)) {
+ coordinates.push(this.parsePoint_());
+ }
+ return coordinates;
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} An array of points.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parsePointTextList_ = function() {
+ var coordinates = [this.parsePointText_()];
+ while (this.match(ol.format.WKT.TokenType.COMMA)) {
+ coordinates.push(this.parsePointText_());
+ }
+ return coordinates;
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} An array of points.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() {
+ var coordinates = [this.parseLineStringText_()];
+ while (this.match(ol.format.WKT.TokenType.COMMA)) {
+ coordinates.push(this.parseLineStringText_());
+ }
+ return coordinates;
+};
+
+
+/**
+ * @return {!Array.<!Array.<number>>} An array of points.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() {
+ var coordinates = [this.parsePolygonText_()];
+ while (this.match(ol.format.WKT.TokenType.COMMA)) {
+ coordinates.push(this.parsePolygonText_());
+ }
+ return coordinates;
+};
+
+
+/**
+ * @return {boolean} Whether the token implies an empty geometry.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() {
+ var isEmpty = this.token_.type == ol.format.WKT.TokenType.TEXT &&
+ this.token_.value == ol.format.WKT.EMPTY;
+ if (isEmpty) {
+ this.consume_();
+ }
+ return isEmpty;
+};
+
+
+/**
+ * Create an error message for an unexpected token error.
+ * @return {string} Error message.
+ * @private
+ */
+ol.format.WKT.Parser.prototype.formatErrorMessage_ = function() {
+ return 'Unexpected `' + this.token_.value + '` at position ' +
+ this.token_.position + ' in `' + this.lexer_.wkt + '`';
+};
+
+
+/**
+ * @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout)}
+ * @private
+ */
+ol.format.WKT.Parser.GeometryConstructor_ = {
+ 'POINT': ol.geom.Point,
+ 'LINESTRING': ol.geom.LineString,
+ 'POLYGON': ol.geom.Polygon,
+ 'MULTIPOINT': ol.geom.MultiPoint,
+ 'MULTILINESTRING': ol.geom.MultiLineString,
+ 'MULTIPOLYGON': ol.geom.MultiPolygon
+};
+
+
+/**
+ * @enum {(function(): Array)}
+ * @private
+ */
+ol.format.WKT.Parser.GeometryParser_ = {
+ 'POINT': ol.format.WKT.Parser.prototype.parsePointText_,
+ 'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_,
+ 'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_,
+ 'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_,
+ 'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_,
+ 'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_
+};
+
+goog.provide('ol.format.WMSCapabilities');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.format.XLink');
+goog.require('ol.format.XML');
+goog.require('ol.format.XSD');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Format for reading WMS capabilities data
+ *
+ * @constructor
+ * @extends {ol.format.XML}
+ * @api
+ */
+ol.format.WMSCapabilities = function() {
+
+ ol.format.XML.call(this);
+
+ /**
+ * @type {string|undefined}
+ */
+ this.version = undefined;
+};
+ol.inherits(ol.format.WMSCapabilities, ol.format.XML);
+
+
+/**
+ * Read a WMS capabilities document.
+ *
+ * @function
+ * @param {Document|Node|string} source The XML source.
+ * @return {Object} An object representing the WMS capabilities.
+ * @api
+ */
+ol.format.WMSCapabilities.prototype.read;
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {Object} WMS Capability object.
+ */
+ol.format.WMSCapabilities.prototype.readFromDocument = function(doc) {
+ goog.asserts.assert(doc.nodeType == Node.DOCUMENT_NODE,
+ 'doc.nodeType should be DOCUMENT');
+ for (var n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ return this.readFromNode(n);
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {Object} WMS Capability object.
+ */
+ol.format.WMSCapabilities.prototype.readFromNode = function(node) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'WMS_Capabilities' ||
+ node.localName == 'WMT_MS_Capabilities',
+ 'localName should be WMS_Capabilities or WMT_MS_Capabilities');
+ this.version = node.getAttribute('version').trim();
+ goog.asserts.assertString(this.version, 'this.version should be a string');
+ var wmsCapabilityObject = ol.xml.pushParseAndPop({
+ 'version': this.version
+ }, ol.format.WMSCapabilities.PARSERS_, node, []);
+ return wmsCapabilityObject ? wmsCapabilityObject : null;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Attribution object.
+ */
+ol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Attribution',
+ 'localName should be Attribution');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object} Bounding box object.
+ */
+ol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'BoundingBox',
+ 'localName should be BoundingBox');
+
+ var extent = [
+ ol.format.XSD.readDecimalString(node.getAttribute('minx')),
+ ol.format.XSD.readDecimalString(node.getAttribute('miny')),
+ ol.format.XSD.readDecimalString(node.getAttribute('maxx')),
+ ol.format.XSD.readDecimalString(node.getAttribute('maxy'))
+ ];
+
+ var resolutions = [
+ ol.format.XSD.readDecimalString(node.getAttribute('resx')),
+ ol.format.XSD.readDecimalString(node.getAttribute('resy'))
+ ];
+
+ return {
+ 'crs': node.getAttribute('CRS'),
+ 'extent': extent,
+ 'res': resolutions
+ };
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {ol.Extent|undefined} Bounding box object.
+ */
+ol.format.WMSCapabilities.readEXGeographicBoundingBox_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'EX_GeographicBoundingBox',
+ 'localName should be EX_GeographicBoundingBox');
+ var geographicBoundingBox = ol.xml.pushParseAndPop(
+ {},
+ ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_,
+ node, objectStack);
+ if (!geographicBoundingBox) {
+ return undefined;
+ }
+ var westBoundLongitude = /** @type {number|undefined} */
+ (geographicBoundingBox['westBoundLongitude']);
+ var southBoundLatitude = /** @type {number|undefined} */
+ (geographicBoundingBox['southBoundLatitude']);
+ var eastBoundLongitude = /** @type {number|undefined} */
+ (geographicBoundingBox['eastBoundLongitude']);
+ var northBoundLatitude = /** @type {number|undefined} */
+ (geographicBoundingBox['northBoundLatitude']);
+ if (westBoundLongitude === undefined || southBoundLatitude === undefined ||
+ eastBoundLongitude === undefined || northBoundLatitude === undefined) {
+ return undefined;
+ }
+ return [
+ westBoundLongitude, southBoundLatitude,
+ eastBoundLongitude, northBoundLatitude
+ ];
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} Capability object.
+ */
+ol.format.WMSCapabilities.readCapability_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Capability',
+ 'localName should be Capability');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} Service object.
+ */
+ol.format.WMSCapabilities.readService_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Service',
+ 'localName should be Service');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} Contact information object.
+ */
+ol.format.WMSCapabilities.readContactInformation_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType shpuld be ELEMENT');
+ goog.asserts.assert(node.localName == 'ContactInformation',
+ 'localName should be ContactInformation');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_,
+ node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} Contact person object.
+ */
+ol.format.WMSCapabilities.readContactPersonPrimary_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ContactPersonPrimary',
+ 'localName should be ContactPersonPrimary');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_,
+ node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} Contact address object.
+ */
+ol.format.WMSCapabilities.readContactAddress_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'ContactAddress',
+ 'localName should be ContactAddress');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_,
+ node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Array.<string>|undefined} Format array.
+ */
+ol.format.WMSCapabilities.readException_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Exception',
+ 'localName should be Exception');
+ return ol.xml.pushParseAndPop(
+ [], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @private
+ * @return {Object|undefined} Layer object.
+ */
+ol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Layer object.
+ */
+ol.format.WMSCapabilities.readLayer_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer');
+ var parentLayerObject = /** @type {Object.<string,*>} */
+ (objectStack[objectStack.length - 1]);
+
+ var layerObject = ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);
+
+ if (!layerObject) {
+ return undefined;
+ }
+ var queryable =
+ ol.format.XSD.readBooleanString(node.getAttribute('queryable'));
+ if (queryable === undefined) {
+ queryable = parentLayerObject['queryable'];
+ }
+ layerObject['queryable'] = queryable !== undefined ? queryable : false;
+
+ var cascaded = ol.format.XSD.readNonNegativeIntegerString(
+ node.getAttribute('cascaded'));
+ if (cascaded === undefined) {
+ cascaded = parentLayerObject['cascaded'];
+ }
+ layerObject['cascaded'] = cascaded;
+
+ var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque'));
+ if (opaque === undefined) {
+ opaque = parentLayerObject['opaque'];
+ }
+ layerObject['opaque'] = opaque !== undefined ? opaque : false;
+
+ var noSubsets =
+ ol.format.XSD.readBooleanString(node.getAttribute('noSubsets'));
+ if (noSubsets === undefined) {
+ noSubsets = parentLayerObject['noSubsets'];
+ }
+ layerObject['noSubsets'] = noSubsets !== undefined ? noSubsets : false;
+
+ var fixedWidth =
+ ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth'));
+ if (!fixedWidth) {
+ fixedWidth = parentLayerObject['fixedWidth'];
+ }
+ layerObject['fixedWidth'] = fixedWidth;
+
+ var fixedHeight =
+ ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight'));
+ if (!fixedHeight) {
+ fixedHeight = parentLayerObject['fixedHeight'];
+ }
+ layerObject['fixedHeight'] = fixedHeight;
+
+ // See 7.2.4.8
+ var addKeys = ['Style', 'CRS', 'AuthorityURL'];
+ addKeys.forEach(function(key) {
+ if (key in parentLayerObject) {
+ var childValue = layerObject[key] || [];
+ layerObject[key] = childValue.concat(parentLayerObject[key]);
+ }
+ });
+
+ var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension',
+ 'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator'];
+ replaceKeys.forEach(function(key) {
+ if (!(key in layerObject)) {
+ var parentValue = parentLayerObject[key];
+ layerObject[key] = parentValue;
+ }
+ });
+
+ return layerObject;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object} Dimension object.
+ */
+ol.format.WMSCapabilities.readDimension_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Dimension',
+ 'localName should be Dimension');
+ var dimensionObject = {
+ 'name': node.getAttribute('name'),
+ 'units': node.getAttribute('units'),
+ 'unitSymbol': node.getAttribute('unitSymbol'),
+ 'default': node.getAttribute('default'),
+ 'multipleValues': ol.format.XSD.readBooleanString(
+ node.getAttribute('multipleValues')),
+ 'nearestValue': ol.format.XSD.readBooleanString(
+ node.getAttribute('nearestValue')),
+ 'current': ol.format.XSD.readBooleanString(node.getAttribute('current')),
+ 'values': ol.format.XSD.readString(node)
+ };
+ return dimensionObject;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Online resource object.
+ */
+ol.format.WMSCapabilities.readFormatOnlineresource_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_,
+ node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Request object.
+ */
+ol.format.WMSCapabilities.readRequest_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Request',
+ 'localName should be Request');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} DCP type object.
+ */
+ol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'DCPType',
+ 'localName should be DCPType');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} HTTP object.
+ */
+ol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'HTTP', 'localName should be HTTP');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Operation type object.
+ */
+ol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Online resource object.
+ */
+ol.format.WMSCapabilities.readSizedFormatOnlineresource_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ var formatOnlineresource =
+ ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
+ if (formatOnlineresource) {
+ var size = [
+ ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')),
+ ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height'))
+ ];
+ formatOnlineresource['size'] = size;
+ return formatOnlineresource;
+ }
+ return undefined;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Authority URL object.
+ */
+ol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'AuthorityURL',
+ 'localName should be AuthorityURL');
+ var authorityObject =
+ ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
+ if (authorityObject) {
+ authorityObject['name'] = node.getAttribute('name');
+ return authorityObject;
+ }
+ return undefined;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Metadata URL object.
+ */
+ol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'MetadataURL',
+ 'localName should be MetadataURL');
+ var metadataObject =
+ ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
+ if (metadataObject) {
+ metadataObject['type'] = node.getAttribute('type');
+ return metadataObject;
+ }
+ return undefined;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Style object.
+ */
+ol.format.WMSCapabilities.readStyle_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Style', 'localName should be Style');
+ return ol.xml.pushParseAndPop(
+ {}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Array.<string>|undefined} Keyword list.
+ */
+ol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'KeywordList',
+ 'localName should be KeywordList');
+ return ol.xml.pushParseAndPop(
+ [], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<string>}
+ */
+ol.format.WMSCapabilities.NAMESPACE_URIS_ = [
+ null,
+ 'http://www.opengis.net/wms'
+];
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Service': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readService_),
+ 'Capability': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readCapability_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Request': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readRequest_),
+ 'Exception': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readException_),
+ 'Layer': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readCapabilityLayer_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'KeywordList': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readKeywordList_),
+ 'OnlineResource': ol.xml.makeObjectPropertySetter(
+ ol.format.XLink.readHref),
+ 'ContactInformation': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readContactInformation_),
+ 'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'AccessConstraints': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'LayerLimit': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'MaxWidth': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'MaxHeight': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'ContactPersonPrimary': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readContactPersonPrimary_),
+ 'ContactPosition': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'ContactAddress': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readContactAddress_),
+ 'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'ContactPerson': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'ContactOrganization': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'StateOrProvince': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'KeywordList': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readKeywordList_),
+ 'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
+ 'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readEXGeographicBoundingBox_),
+ 'BoundingBox': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readBoundingBox_),
+ 'Dimension': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readDimension_),
+ 'Attribution': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readAttribution_),
+ 'AuthorityURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readAuthorityURL_),
+ 'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
+ 'MetadataURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readMetadataURL_),
+ 'DataURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readFormatOnlineresource_),
+ 'FeatureListURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readFormatOnlineresource_),
+ 'Style': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readStyle_),
+ 'MinScaleDenominator': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal),
+ 'MaxScaleDenominator': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal),
+ 'Layer': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readLayer_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'OnlineResource': ol.xml.makeObjectPropertySetter(
+ ol.format.XLink.readHref),
+ 'LogoURL': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readSizedFormatOnlineresource_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ =
+ ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'westBoundLongitude': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal),
+ 'eastBoundLongitude': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal),
+ 'southBoundLatitude': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal),
+ 'northBoundLatitude': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'GetCapabilities': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readOperationType_),
+ 'GetMap': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readOperationType_),
+ 'GetFeatureInfo': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readOperationType_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
+ 'DCPType': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readDCPType_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'HTTP': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readHTTP_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Get': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readFormatOnlineresource_),
+ 'Post': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readFormatOnlineresource_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'LegendURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMSCapabilities.readSizedFormatOnlineresource_),
+ 'StyleSheetURL': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readFormatOnlineresource_),
+ 'StyleURL': ol.xml.makeObjectPropertySetter(
+ ol.format.WMSCapabilities.readFormatOnlineresource_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ =
+ ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
+ 'OnlineResource': ol.xml.makeObjectPropertySetter(
+ ol.format.XLink.readHref)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMSCapabilities.NAMESPACE_URIS_, {
+ 'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString)
+ });
+
+goog.provide('ol.format.WMSGetFeatureInfo');
+
+goog.require('goog.asserts');
+goog.require('ol.array');
+goog.require('ol.format.GML2');
+goog.require('ol.format.XMLFeature');
+goog.require('ol.object');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Format for reading WMSGetFeatureInfo format. It uses
+ * {@link ol.format.GML2} to read features.
+ *
+ * @constructor
+ * @extends {ol.format.XMLFeature}
+ * @param {olx.format.WMSGetFeatureInfoOptions=} opt_options Options.
+ * @api
+ */
+ol.format.WMSGetFeatureInfo = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver';
+
+
+ /**
+ * @private
+ * @type {ol.format.GML2}
+ */
+ this.gmlFormat_ = new ol.format.GML2();
+
+
+ /**
+ * @private
+ * @type {Array.<string>}
+ */
+ this.layers_ = options.layers ? options.layers : null;
+
+ ol.format.XMLFeature.call(this);
+};
+ol.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature);
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature';
+
+
+/**
+ * @const
+ * @type {string}
+ * @private
+ */
+ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer';
+
+
+/**
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Array.<ol.Feature>} Features.
+ * @private
+ */
+ol.format.WMSGetFeatureInfo.prototype.readFeatures_ = function(node, objectStack) {
+
+ node.setAttribute('namespaceURI', this.featureNS_);
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ var localName = node.localName;
+ /** @type {Array.<ol.Feature>} */
+ var features = [];
+ if (node.childNodes.length === 0) {
+ return features;
+ }
+ if (localName == 'msGMLOutput') {
+ for (var i = 0, ii = node.childNodes.length; i < ii; i++) {
+ var layer = node.childNodes[i];
+ if (layer.nodeType !== Node.ELEMENT_NODE) {
+ continue;
+ }
+ var context = objectStack[0];
+ goog.asserts.assert(goog.isObject(context),
+ 'context should be an Object');
+
+ goog.asserts.assert(layer.localName.indexOf(
+ ol.format.WMSGetFeatureInfo.layerIdentifier_) >= 0,
+ 'localName of layer node should match layerIdentifier');
+
+ var toRemove = ol.format.WMSGetFeatureInfo.layerIdentifier_;
+ var layerName = layer.localName.replace(toRemove, '');
+
+ if (this.layers_ && !ol.array.includes(this.layers_, layerName)) {
+ continue;
+ }
+
+ var featureType = layerName +
+ ol.format.WMSGetFeatureInfo.featureIdentifier_;
+
+ context['featureType'] = featureType;
+ context['featureNS'] = this.featureNS_;
+
+ var parsers = {};
+ parsers[featureType] = ol.xml.makeArrayPusher(
+ this.gmlFormat_.readFeatureElement, this.gmlFormat_);
+ var parsersNS = ol.xml.makeStructureNS(
+ [context['featureNS'], null], parsers);
+ layer.setAttribute('namespaceURI', this.featureNS_);
+ var layerFeatures = ol.xml.pushParseAndPop(
+ [], parsersNS, layer, objectStack, this.gmlFormat_);
+ if (layerFeatures) {
+ ol.array.extend(features, layerFeatures);
+ }
+ }
+ }
+ if (localName == 'FeatureCollection') {
+ var gmlFeatures = ol.xml.pushParseAndPop([],
+ this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
+ [{}], this.gmlFormat_);
+ if (gmlFeatures) {
+ features = gmlFeatures;
+ }
+ }
+ return features;
+};
+
+
+/**
+ * Read all features from a WMSGetFeatureInfo response.
+ *
+ * @function
+ * @param {Document|Node|Object|string} source Source.
+ * @param {olx.format.ReadOptions=} opt_options Options.
+ * @return {Array.<ol.Feature>} Features.
+ * @api stable
+ */
+ol.format.WMSGetFeatureInfo.prototype.readFeatures;
+
+
+/**
+ * @inheritDoc
+ */
+ol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode = function(node, opt_options) {
+ var options = {};
+ if (opt_options) {
+ ol.object.assign(options, this.getReadOptions(node, opt_options));
+ }
+ return this.readFeatures_(node, [options]);
+};
+
+goog.provide('ol.format.WMTSCapabilities');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.format.OWS');
+goog.require('ol.format.XLink');
+goog.require('ol.format.XML');
+goog.require('ol.format.XSD');
+goog.require('ol.xml');
+
+
+/**
+ * @classdesc
+ * Format for reading WMTS capabilities data.
+ *
+ * @constructor
+ * @extends {ol.format.XML}
+ * @api
+ */
+ol.format.WMTSCapabilities = function() {
+ ol.format.XML.call(this);
+
+ /**
+ * @type {ol.format.OWS}
+ * @private
+ */
+ this.owsParser_ = new ol.format.OWS();
+};
+ol.inherits(ol.format.WMTSCapabilities, ol.format.XML);
+
+
+/**
+ * Read a WMTS capabilities document.
+ *
+ * @function
+ * @param {Document|Node|string} source The XML source.
+ * @return {Object} An object representing the WMTS capabilities.
+ * @api
+ */
+ol.format.WMTSCapabilities.prototype.read;
+
+
+/**
+ * @param {Document} doc Document.
+ * @return {Object} WMTS Capability object.
+ */
+ol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) {
+ goog.asserts.assert(doc.nodeType == Node.DOCUMENT_NODE,
+ 'doc.nodeType should be DOCUMENT');
+ for (var n = doc.firstChild; n; n = n.nextSibling) {
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ return this.readFromNode(n);
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @param {Node} node Node.
+ * @return {Object} WMTS Capability object.
+ */
+ol.format.WMTSCapabilities.prototype.readFromNode = function(node) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Capabilities',
+ 'localName should be Capabilities');
+ var version = node.getAttribute('version').trim();
+ goog.asserts.assertString(version, 'version should be a string');
+ var WMTSCapabilityObject = this.owsParser_.readFromNode(node);
+ if (!WMTSCapabilityObject) {
+ return null;
+ }
+ WMTSCapabilityObject['version'] = version;
+ WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject,
+ ol.format.WMTSCapabilities.PARSERS_, node, []);
+ return WMTSCapabilityObject ? WMTSCapabilityObject : null;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Attribution object.
+ */
+ol.format.WMTSCapabilities.readContents_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Contents',
+ 'localName should be Contents');
+
+ return ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Layers object.
+ */
+ol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) {
+ goog.asserts.assert(node.nodeType == Node.ELEMENT_NODE,
+ 'node.nodeType should be ELEMENT');
+ goog.asserts.assert(node.localName == 'Layer', 'localName should be Layer');
+ return ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Tile Matrix Set object.
+ */
+ol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) {
+ return ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Style object.
+ */
+ol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) {
+ var style = ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack);
+ if (!style) {
+ return undefined;
+ }
+ var isDefault = node.getAttribute('isDefault') === 'true';
+ style['isDefault'] = isDefault;
+ return style;
+
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Tile Matrix Set Link object.
+ */
+ol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node,
+ objectStack) {
+ return ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Dimension object.
+ */
+ol.format.WMTSCapabilities.readDimensions_ = function(node, objectStack) {
+ return ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.DIMENSION_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Resource URL object.
+ */
+ol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) {
+ var format = node.getAttribute('format');
+ var template = node.getAttribute('template');
+ var resourceType = node.getAttribute('resourceType');
+ var resource = {};
+ if (format) {
+ resource['format'] = format;
+ }
+ if (template) {
+ resource['template'] = template;
+ }
+ if (resourceType) {
+ resource['resourceType'] = resourceType;
+ }
+ return resource;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} WGS84 BBox object.
+ */
+ol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) {
+ var coordinates = ol.xml.pushParseAndPop([],
+ ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack);
+ if (coordinates.length != 2) {
+ return undefined;
+ }
+ return ol.extent.boundingExtent(coordinates);
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Legend object.
+ */
+ol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) {
+ var legend = {};
+ legend['format'] = node.getAttribute('format');
+ legend['href'] = ol.format.XLink.readHref(node);
+ return legend;
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} Coordinates object.
+ */
+ol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) {
+ var coordinates = ol.format.XSD.readString(node).split(' ');
+ if (!coordinates || coordinates.length != 2) {
+ return undefined;
+ }
+ var x = +coordinates[0];
+ var y = +coordinates[1];
+ if (isNaN(x) || isNaN(y)) {
+ return undefined;
+ }
+ return [x, y];
+};
+
+
+/**
+ * @private
+ * @param {Node} node Node.
+ * @param {Array.<*>} objectStack Object stack.
+ * @return {Object|undefined} TileMatrix object.
+ */
+ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) {
+ return ol.xml.pushParseAndPop({},
+ ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack);
+};
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<string>}
+ */
+ol.format.WMTSCapabilities.NAMESPACE_URIS_ = [
+ null,
+ 'http://www.opengis.net/wmts/1.0'
+];
+
+
+/**
+ * @const
+ * @private
+ * @type {Array.<string>}
+ */
+ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [
+ null,
+ 'http://www.opengis.net/ows/1.1'
+];
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'Contents': ol.xml.makeObjectPropertySetter(
+ ol.format.WMTSCapabilities.readContents_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'Layer': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readLayer_),
+ 'TileMatrixSet': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readTileMatrixSet_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'Style': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readStyle_),
+ 'Format': ol.xml.makeObjectPropertyPusher(
+ ol.format.XSD.readString),
+ 'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readTileMatrixSetLink_),
+ 'Dimension': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readDimensions_),
+ 'ResourceURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readResourceUrl_)
+ }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
+ 'Title': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'Abstract': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'WGS84BoundingBox': ol.xml.makeObjectPropertySetter(
+ ol.format.WMTSCapabilities.readWgs84BoundingBox_),
+ 'Identifier': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'LegendURL': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readLegendUrl_)
+ }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
+ 'Title': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'Identifier': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'TileMatrixSet': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.DIMENSION_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'Default': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'Value': ol.xml.makeObjectPropertyPusher(
+ ol.format.XSD.readString)
+ }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
+ 'Identifier': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
+ 'LowerCorner': ol.xml.makeArrayPusher(
+ ol.format.WMTSCapabilities.readCoordinates_),
+ 'UpperCorner': ol.xml.makeArrayPusher(
+ ol.format.WMTSCapabilities.readCoordinates_)
+ });
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'WellKnownScaleSet': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'TileMatrix': ol.xml.makeObjectPropertyPusher(
+ ol.format.WMTSCapabilities.readTileMatrix_)
+ }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
+ 'SupportedCRS': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString),
+ 'Identifier': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ }));
+
+
+/**
+ * @const
+ * @type {Object.<string, Object.<string, ol.XmlParser>>}
+ * @private
+ */
+ol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeStructureNS(
+ ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
+ 'TopLeftCorner': ol.xml.makeObjectPropertySetter(
+ ol.format.WMTSCapabilities.readCoordinates_),
+ 'ScaleDenominator': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readDecimal),
+ 'TileWidth': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'TileHeight': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'MatrixWidth': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger),
+ 'MatrixHeight': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readNonNegativeInteger)
+ }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
+ 'Identifier': ol.xml.makeObjectPropertySetter(
+ ol.format.XSD.readString)
+ }));
+
+// FIXME handle geolocation not supported
+
+goog.provide('ol.Geolocation');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.Object');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.Polygon');
+goog.require('ol.has');
+goog.require('ol.math');
+goog.require('ol.proj');
+goog.require('ol.sphere.WGS84');
+
+
+/**
+ * @enum {string}
+ */
+ol.GeolocationProperty = {
+ ACCURACY: 'accuracy',
+ ACCURACY_GEOMETRY: 'accuracyGeometry',
+ ALTITUDE: 'altitude',
+ ALTITUDE_ACCURACY: 'altitudeAccuracy',
+ HEADING: 'heading',
+ POSITION: 'position',
+ PROJECTION: 'projection',
+ SPEED: 'speed',
+ TRACKING: 'tracking',
+ TRACKING_OPTIONS: 'trackingOptions'
+};
+
+
+/**
+ * @classdesc
+ * Helper class for providing HTML5 Geolocation capabilities.
+ * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
+ * is used to locate a user's position.
+ *
+ * To get notified of position changes, register a listener for the generic
+ * `change` event on your instance of `ol.Geolocation`.
+ *
+ * Example:
+ *
+ * var geolocation = new ol.Geolocation({
+ * // take the projection to use from the map's view
+ * projection: view.getProjection()
+ * });
+ * // listen to changes in position
+ * geolocation.on('change', function(evt) {
+ * window.console.log(geolocation.getPosition());
+ * });
+ *
+ * @fires error
+ * @constructor
+ * @extends {ol.Object}
+ * @param {olx.GeolocationOptions=} opt_options Options.
+ * @api stable
+ */
+ol.Geolocation = function(opt_options) {
+
+ ol.Object.call(this);
+
+ var options = opt_options || {};
+
+ /**
+ * The unprojected (EPSG:4326) device position.
+ * @private
+ * @type {ol.Coordinate}
+ */
+ this.position_ = null;
+
+ /**
+ * @private
+ * @type {ol.TransformFunction}
+ */
+ this.transform_ = ol.proj.identityTransform;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.watchId_ = undefined;
+
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION),
+ this.handleProjectionChanged_, this);
+ ol.events.listen(
+ this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING),
+ this.handleTrackingChanged_, this);
+
+ if (options.projection !== undefined) {
+ this.setProjection(ol.proj.get(options.projection));
+ }
+ if (options.trackingOptions !== undefined) {
+ this.setTrackingOptions(options.trackingOptions);
+ }
+
+ this.setTracking(options.tracking !== undefined ? options.tracking : false);
+
+};
+ol.inherits(ol.Geolocation, ol.Object);
+
+
+/**
+ * @inheritDoc
+ */
+ol.Geolocation.prototype.disposeInternal = function() {
+ this.setTracking(false);
+ ol.Object.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @private
+ */
+ol.Geolocation.prototype.handleProjectionChanged_ = function() {
+ var projection = this.getProjection();
+ if (projection) {
+ this.transform_ = ol.proj.getTransformFromProjections(
+ ol.proj.get('EPSG:4326'), projection);
+ if (this.position_) {
+ this.set(
+ ol.GeolocationProperty.POSITION, this.transform_(this.position_));
+ }
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.Geolocation.prototype.handleTrackingChanged_ = function() {
+ if (ol.has.GEOLOCATION) {
+ var tracking = this.getTracking();
+ if (tracking && this.watchId_ === undefined) {
+ this.watchId_ = ol.global.navigator.geolocation.watchPosition(
+ this.positionChange_.bind(this),
+ this.positionError_.bind(this),
+ this.getTrackingOptions());
+ } else if (!tracking && this.watchId_ !== undefined) {
+ ol.global.navigator.geolocation.clearWatch(this.watchId_);
+ this.watchId_ = undefined;
+ }
+ }
+};
+
+
+/**
+ * @private
+ * @param {GeolocationPosition} position position event.
+ */
+ol.Geolocation.prototype.positionChange_ = function(position) {
+ var coords = position.coords;
+ this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy);
+ this.set(ol.GeolocationProperty.ALTITUDE,
+ coords.altitude === null ? undefined : coords.altitude);
+ this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY,
+ coords.altitudeAccuracy === null ?
+ undefined : coords.altitudeAccuracy);
+ this.set(ol.GeolocationProperty.HEADING, coords.heading === null ?
+ undefined : ol.math.toRadians(coords.heading));
+ if (!this.position_) {
+ this.position_ = [coords.longitude, coords.latitude];
+ } else {
+ this.position_[0] = coords.longitude;
+ this.position_[1] = coords.latitude;
+ }
+ var projectedPosition = this.transform_(this.position_);
+ this.set(ol.GeolocationProperty.POSITION, projectedPosition);
+ this.set(ol.GeolocationProperty.SPEED,
+ coords.speed === null ? undefined : coords.speed);
+ var geometry = ol.geom.Polygon.circular(
+ ol.sphere.WGS84, this.position_, coords.accuracy);
+ geometry.applyTransform(this.transform_);
+ this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry);
+ this.changed();
+};
+
+/**
+ * Triggered when the Geolocation returns an error.
+ * @event error
+ * @api
+ */
+
+/**
+ * @private
+ * @param {GeolocationPositionError} error error object.
+ */
+ol.Geolocation.prototype.positionError_ = function(error) {
+ error.type = ol.events.EventType.ERROR;
+ this.setTracking(false);
+ this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
+};
+
+
+/**
+ * Get the accuracy of the position in meters.
+ * @return {number|undefined} The accuracy of the position measurement in
+ * meters.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getAccuracy = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.GeolocationProperty.ACCURACY));
+};
+
+
+/**
+ * Get a geometry of the position accuracy.
+ * @return {?ol.geom.Geometry} A geometry of the position accuracy.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getAccuracyGeometry = function() {
+ return /** @type {?ol.geom.Geometry} */ (
+ this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null);
+};
+
+
+/**
+ * Get the altitude associated with the position.
+ * @return {number|undefined} The altitude of the position in meters above mean
+ * sea level.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getAltitude = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.GeolocationProperty.ALTITUDE));
+};
+
+
+/**
+ * Get the altitude accuracy of the position.
+ * @return {number|undefined} The accuracy of the altitude measurement in
+ * meters.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getAltitudeAccuracy = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY));
+};
+
+
+/**
+ * Get the heading as radians clockwise from North.
+ * @return {number|undefined} The heading of the device in radians from north.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getHeading = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.GeolocationProperty.HEADING));
+};
+
+
+/**
+ * Get the position of the device.
+ * @return {ol.Coordinate|undefined} The current position of the device reported
+ * in the current projection.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getPosition = function() {
+ return /** @type {ol.Coordinate|undefined} */ (
+ this.get(ol.GeolocationProperty.POSITION));
+};
+
+
+/**
+ * Get the projection associated with the position.
+ * @return {ol.proj.Projection|undefined} The projection the position is
+ * reported in.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getProjection = function() {
+ return /** @type {ol.proj.Projection|undefined} */ (
+ this.get(ol.GeolocationProperty.PROJECTION));
+};
+
+
+/**
+ * Get the speed in meters per second.
+ * @return {number|undefined} The instantaneous speed of the device in meters
+ * per second.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getSpeed = function() {
+ return /** @type {number|undefined} */ (
+ this.get(ol.GeolocationProperty.SPEED));
+};
+
+
+/**
+ * Determine if the device location is being tracked.
+ * @return {boolean} The device location is being tracked.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getTracking = function() {
+ return /** @type {boolean} */ (
+ this.get(ol.GeolocationProperty.TRACKING));
+};
+
+
+/**
+ * Get the tracking options.
+ * @see http://www.w3.org/TR/geolocation-API/#position-options
+ * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
+ * the [HTML5 Geolocation spec
+ * ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.getTrackingOptions = function() {
+ return /** @type {GeolocationPositionOptions|undefined} */ (
+ this.get(ol.GeolocationProperty.TRACKING_OPTIONS));
+};
+
+
+/**
+ * Set the projection to use for transforming the coordinates.
+ * @param {ol.proj.Projection} projection The projection the position is
+ * reported in.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.setProjection = function(projection) {
+ this.set(ol.GeolocationProperty.PROJECTION, projection);
+};
+
+
+/**
+ * Enable or disable tracking.
+ * @param {boolean} tracking Enable tracking.
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.setTracking = function(tracking) {
+ this.set(ol.GeolocationProperty.TRACKING, tracking);
+};
+
+
+/**
+ * Set the tracking options.
+ * @see http://www.w3.org/TR/geolocation-API/#position-options
+ * @param {GeolocationPositionOptions} options PositionOptions as defined by the
+ * [HTML5 Geolocation spec
+ * ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
+ * @observable
+ * @api stable
+ */
+ol.Geolocation.prototype.setTrackingOptions = function(options) {
+ this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options);
+};
+
+goog.provide('ol.geom.Circle');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.geom.flat.deflate');
+
+
+/**
+ * @classdesc
+ * Circle geometry.
+ *
+ * @constructor
+ * @extends {ol.geom.SimpleGeometry}
+ * @param {ol.Coordinate} center Center.
+ * @param {number=} opt_radius Radius.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api
+ */
+ol.geom.Circle = function(center, opt_radius, opt_layout) {
+ ol.geom.SimpleGeometry.call(this);
+ var radius = opt_radius ? opt_radius : 0;
+ this.setCenterAndRadius(center, radius, opt_layout);
+};
+ol.inherits(ol.geom.Circle, ol.geom.SimpleGeometry);
+
+
+/**
+ * Make a complete copy of the geometry.
+ * @return {!ol.geom.Circle} Clone.
+ * @api
+ */
+ol.geom.Circle.prototype.clone = function() {
+ var circle = new ol.geom.Circle(null);
+ circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
+ return circle;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Circle.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
+ var flatCoordinates = this.flatCoordinates;
+ var dx = x - flatCoordinates[0];
+ var dy = y - flatCoordinates[1];
+ var squaredDistance = dx * dx + dy * dy;
+ if (squaredDistance < minSquaredDistance) {
+ var i;
+ if (squaredDistance === 0) {
+ for (i = 0; i < this.stride; ++i) {
+ closestPoint[i] = flatCoordinates[i];
+ }
+ } else {
+ var delta = this.getRadius() / Math.sqrt(squaredDistance);
+ closestPoint[0] = flatCoordinates[0] + delta * dx;
+ closestPoint[1] = flatCoordinates[1] + delta * dy;
+ for (i = 2; i < this.stride; ++i) {
+ closestPoint[i] = flatCoordinates[i];
+ }
+ }
+ closestPoint.length = this.stride;
+ return squaredDistance;
+ } else {
+ return minSquaredDistance;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Circle.prototype.containsXY = function(x, y) {
+ var flatCoordinates = this.flatCoordinates;
+ var dx = x - flatCoordinates[0];
+ var dy = y - flatCoordinates[1];
+ return dx * dx + dy * dy <= this.getRadiusSquared_();
+};
+
+
+/**
+ * Return the center of the circle as {@link ol.Coordinate coordinate}.
+ * @return {ol.Coordinate} Center.
+ * @api
+ */
+ol.geom.Circle.prototype.getCenter = function() {
+ return this.flatCoordinates.slice(0, this.stride);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.geom.Circle.prototype.computeExtent = function(extent) {
+ var flatCoordinates = this.flatCoordinates;
+ var radius = flatCoordinates[this.stride] - flatCoordinates[0];
+ return ol.extent.createOrUpdate(
+ flatCoordinates[0] - radius, flatCoordinates[1] - radius,
+ flatCoordinates[0] + radius, flatCoordinates[1] + radius,
+ extent);
+};
+
+
+/**
+ * Return the radius of the circle.
+ * @return {number} Radius.
+ * @api
+ */
+ol.geom.Circle.prototype.getRadius = function() {
+ return Math.sqrt(this.getRadiusSquared_());
+};
+
+
+/**
+ * @private
+ * @return {number} Radius squared.
+ */
+ol.geom.Circle.prototype.getRadiusSquared_ = function() {
+ var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
+ var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
+ return dx * dx + dy * dy;
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.geom.Circle.prototype.getType = function() {
+ return ol.geom.GeometryType.CIRCLE;
+};
+
+
+/**
+ * @inheritDoc
+ * @api stable
+ */
+ol.geom.Circle.prototype.intersectsExtent = function(extent) {
+ var circleExtent = this.getExtent();
+ if (ol.extent.intersects(extent, circleExtent)) {
+ var center = this.getCenter();
+
+ if (extent[0] <= center[0] && extent[2] >= center[0]) {
+ return true;
+ }
+ if (extent[1] <= center[1] && extent[3] >= center[1]) {
+ return true;
+ }
+
+ return ol.extent.forEachCorner(extent, this.containsCoordinate, this);
+ }
+ return false;
+
+};
+
+
+/**
+ * Set the center of the circle as {@link ol.Coordinate coordinate}.
+ * @param {ol.Coordinate} center Center.
+ * @api
+ */
+ol.geom.Circle.prototype.setCenter = function(center) {
+ var stride = this.stride;
+ goog.asserts.assert(center.length == stride,
+ 'center array length should match stride');
+ var radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
+ var flatCoordinates = center.slice();
+ flatCoordinates[stride] = flatCoordinates[0] + radius;
+ var i;
+ for (i = 1; i < stride; ++i) {
+ flatCoordinates[stride + i] = center[i];
+ }
+ this.setFlatCoordinates(this.layout, flatCoordinates);
+};
+
+
+/**
+ * Set the center (as {@link ol.Coordinate coordinate}) and the radius (as
+ * number) of the circle.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} radius Radius.
+ * @param {ol.geom.GeometryLayout=} opt_layout Layout.
+ * @api
+ */
+ol.geom.Circle.prototype.setCenterAndRadius = function(center, radius, opt_layout) {
+ if (!center) {
+ this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
+ } else {
+ this.setLayout(opt_layout, center, 0);
+ if (!this.flatCoordinates) {
+ this.flatCoordinates = [];
+ }
+ /** @type {Array.<number>} */
+ var flatCoordinates = this.flatCoordinates;
+ var offset = ol.geom.flat.deflate.coordinate(
+ flatCoordinates, 0, center, this.stride);
+ flatCoordinates[offset++] = flatCoordinates[0] + radius;
+ var i, ii;
+ for (i = 1, ii = this.stride; i < ii; ++i) {
+ flatCoordinates[offset++] = flatCoordinates[i];
+ }
+ flatCoordinates.length = offset;
+ this.changed();
+ }
+};
+
+
+/**
+ * @param {ol.geom.GeometryLayout} layout Layout.
+ * @param {Array.<number>} flatCoordinates Flat coordinates.
+ */
+ol.geom.Circle.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
+ this.setFlatCoordinatesInternal(layout, flatCoordinates);
+ this.changed();
+};
+
+
+/**
+ * Set the radius of the circle. The radius is in the units of the projection.
+ * @param {number} radius Radius.
+ * @api
+ */
+ol.geom.Circle.prototype.setRadius = function(radius) {
+ goog.asserts.assert(this.flatCoordinates,
+ 'truthy this.flatCoordinates expected');
+ this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
+ this.changed();
+};
+
+
+/**
+ * Transform each coordinate of the circle from one coordinate reference system
+ * to another. The geometry is modified in place.
+ * If you do not want the geometry modified in place, first clone() it and
+ * then use this function on the clone.
+ *
+ * Internally a circle is currently represented by two points: the center of
+ * the circle `[cx, cy]`, and the point to the right of the circle
+ * `[cx + r, cy]`. This `transform` function just transforms these two points.
+ * So the resulting geometry is also a circle, and that circle does not
+ * correspond to the shape that would be obtained by transforming every point
+ * of the original circle.
+ *
+ * @param {ol.ProjectionLike} source The current projection. Can be a
+ * string identifier or a {@link ol.proj.Projection} object.
+ * @param {ol.ProjectionLike} destination The desired projection. Can be a
+ * string identifier or a {@link ol.proj.Projection} object.
+ * @return {ol.geom.Circle} This geometry. Note that original geometry is
+ * modified in place.
+ * @function
+ * @api stable
+ */
+ol.geom.Circle.prototype.transform;
+
+goog.provide('ol.geom.flat.geodesic');
+
+goog.require('goog.asserts');
+goog.require('ol.math');
+goog.require('ol.proj');
+
+
+/**
+ * @private
+ * @param {function(number): ol.Coordinate} interpolate Interpolate function.
+ * @param {ol.TransformFunction} transform Transform from longitude/latitude to
+ * projected coordinates.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.geom.flat.geodesic.line_ = function(interpolate, transform, squaredTolerance) {
+ // FIXME reduce garbage generation
+ // FIXME optimize stack operations
+
+ /** @type {Array.<number>} */
+ var flatCoordinates = [];
+
+ var geoA = interpolate(0);
+ var geoB = interpolate(1);
+
+ var a = transform(geoA);
+ var b = transform(geoB);
+
+ /** @type {Array.<ol.Coordinate>} */
+ var geoStack = [geoB, geoA];
+ /** @type {Array.<ol.Coordinate>} */
+ var stack = [b, a];
+ /** @type {Array.<number>} */
+ var fractionStack = [1, 0];
+
+ /** @type {Object.<string, boolean>} */
+ var fractions = {};
+
+ var maxIterations = 1e5;
+ var geoM, m, fracA, fracB, fracM, key;
+
+ while (--maxIterations > 0 && fractionStack.length > 0) {
+ // Pop the a coordinate off the stack
+ fracA = fractionStack.pop();
+ geoA = geoStack.pop();
+ a = stack.pop();
+ // Add the a coordinate if it has not been added yet
+ key = fracA.toString();
+ if (!(key in fractions)) {
+ flatCoordinates.push(a[0], a[1]);
+ fractions[key] = true;
+ }
+ // Pop the b coordinate off the stack
+ fracB = fractionStack.pop();
+ geoB = geoStack.pop();
+ b = stack.pop();
+ // Find the m point between the a and b coordinates
+ fracM = (fracA + fracB) / 2;
+ geoM = interpolate(fracM);
+ m = transform(geoM);
+ if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1],
+ b[0], b[1]) < squaredTolerance) {
+ // If the m point is sufficiently close to the straight line, then we
+ // discard it. Just use the b coordinate and move on to the next line
+ // segment.
+ flatCoordinates.push(b[0], b[1]);
+ key = fracB.toString();
+ goog.asserts.assert(!(key in fractions),
+ 'fractions object should contain key : ' + key);
+ fractions[key] = true;
+ } else {
+ // Otherwise, we need to subdivide the current line segment. Split it
+ // into two and push the two line segments onto the stack.
+ fractionStack.push(fracB, fracM, fracM, fracA);
+ stack.push(b, m, m, a);
+ geoStack.push(geoB, geoM, geoM, geoA);
+ }
+ }
+ goog.asserts.assert(maxIterations > 0,
+ 'maxIterations should be more than 0');
+
+ return flatCoordinates;
+};
+
+
+/**
+* Generate a great-circle arcs between two lat/lon points.
+* @param {number} lon1 Longitude 1 in degrees.
+* @param {number} lat1 Latitude 1 in degrees.
+* @param {number} lon2 Longitude 2 in degrees.
+* @param {number} lat2 Latitude 2 in degrees.
+ * @param {ol.proj.Projection} projection Projection.
+* @param {number} squaredTolerance Squared tolerance.
+* @return {Array.<number>} Flat coordinates.
+*/
+ol.geom.flat.geodesic.greatCircleArc = function(
+ lon1, lat1, lon2, lat2, projection, squaredTolerance) {
+
+ var geoProjection = ol.proj.get('EPSG:4326');
+
+ var cosLat1 = Math.cos(ol.math.toRadians(lat1));
+ var sinLat1 = Math.sin(ol.math.toRadians(lat1));
+ var cosLat2 = Math.cos(ol.math.toRadians(lat2));
+ var sinLat2 = Math.sin(ol.math.toRadians(lat2));
+ var cosDeltaLon = Math.cos(ol.math.toRadians(lon2 - lon1));
+ var sinDeltaLon = Math.sin(ol.math.toRadians(lon2 - lon1));
+ var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon;
+
+ return ol.geom.flat.geodesic.line_(
+ /**
+ * @param {number} frac Fraction.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ function(frac) {
+ if (1 <= d) {
+ return [lon2, lat2];
+ }
+ var D = frac * Math.acos(d);
+ var cosD = Math.cos(D);
+ var sinD = Math.sin(D);
+ var y = sinDeltaLon * cosLat2;
+ var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon;
+ var theta = Math.atan2(y, x);
+ var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta));
+ var lon = ol.math.toRadians(lon1) +
+ Math.atan2(Math.sin(theta) * sinD * cosLat1,
+ cosD - sinLat1 * Math.sin(lat));
+ return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)];
+ }, ol.proj.getTransform(geoProjection, projection), squaredTolerance);
+};
+
+
+/**
+ * Generate a meridian (line at constant longitude).
+ * @param {number} lon Longitude.
+ * @param {number} lat1 Latitude 1.
+ * @param {number} lat2 Latitude 2.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.geom.flat.geodesic.meridian = function(lon, lat1, lat2, projection, squaredTolerance) {
+ var epsg4326Projection = ol.proj.get('EPSG:4326');
+ return ol.geom.flat.geodesic.line_(
+ /**
+ * @param {number} frac Fraction.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ function(frac) {
+ return [lon, lat1 + ((lat2 - lat1) * frac)];
+ },
+ ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);
+};
+
+
+/**
+ * Generate a parallel (line at constant latitude).
+ * @param {number} lat Latitude.
+ * @param {number} lon1 Longitude 1.
+ * @param {number} lon2 Longitude 2.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {Array.<number>} Flat coordinates.
+ */
+ol.geom.flat.geodesic.parallel = function(lat, lon1, lon2, projection, squaredTolerance) {
+ var epsg4326Projection = ol.proj.get('EPSG:4326');
+ return ol.geom.flat.geodesic.line_(
+ /**
+ * @param {number} frac Fraction.
+ * @return {ol.Coordinate} Coordinate.
+ */
+ function(frac) {
+ return [lon1 + ((lon2 - lon1) * frac), lat];
+ },
+ ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);
+};
+
+goog.provide('ol.Graticule');
+
+goog.require('goog.asserts');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.flat.geodesic');
+goog.require('ol.math');
+goog.require('ol.proj');
+goog.require('ol.render.EventType');
+goog.require('ol.style.Stroke');
+
+
+/**
+ * Render a grid for a coordinate system on a map.
+ * @constructor
+ * @param {olx.GraticuleOptions=} opt_options Options.
+ * @api
+ */
+ol.Graticule = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * @type {ol.Map}
+ * @private
+ */
+ this.map_ = null;
+
+ /**
+ * @type {ol.proj.Projection}
+ * @private
+ */
+ this.projection_ = null;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.maxLat_ = Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.maxLon_ = Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.minLat_ = -Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.minLon_ = -Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.maxLatP_ = Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.maxLonP_ = Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.minLatP_ = -Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.minLonP_ = -Infinity;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.targetSize_ = options.targetSize !== undefined ?
+ options.targetSize : 100;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100;
+ goog.asserts.assert(this.maxLines_ > 0,
+ 'this.maxLines_ should be more than 0');
+
+ /**
+ * @type {Array.<ol.geom.LineString>}
+ * @private
+ */
+ this.meridians_ = [];
+
+ /**
+ * @type {Array.<ol.geom.LineString>}
+ * @private
+ */
+ this.parallels_ = [];
+
+ /**
+ * @type {ol.style.Stroke}
+ * @private
+ */
+ this.strokeStyle_ = options.strokeStyle !== undefined ?
+ options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_;
+
+ /**
+ * @type {ol.TransformFunction|undefined}
+ * @private
+ */
+ this.fromLonLatTransform_ = undefined;
+
+ /**
+ * @type {ol.TransformFunction|undefined}
+ * @private
+ */
+ this.toLonLatTransform_ = undefined;
+
+ /**
+ * @type {ol.Coordinate}
+ * @private
+ */
+ this.projectionCenterLonLat_ = null;
+
+ this.setMap(options.map !== undefined ? options.map : null);
+};
+
+
+/**
+ * @type {ol.style.Stroke}
+ * @private
+ * @const
+ */
+ol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({
+ color: 'rgba(0,0,0,0.2)'
+});
+
+
+/**
+ * TODO can be configurable
+ * @type {Array.<number>}
+ * @private
+ */
+ol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05,
+ 0.01, 0.005, 0.002, 0.001];
+
+
+/**
+ * @param {number} lon Longitude.
+ * @param {number} minLat Minimal latitude.
+ * @param {number} maxLat Maximal latitude.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} index Index.
+ * @return {number} Index.
+ * @private
+ */
+ol.Graticule.prototype.addMeridian_ = function(lon, minLat, maxLat, squaredTolerance, extent, index) {
+ var lineString = this.getMeridian_(lon, minLat, maxLat,
+ squaredTolerance, index);
+ if (ol.extent.intersects(lineString.getExtent(), extent)) {
+ this.meridians_[index++] = lineString;
+ }
+ return index;
+};
+
+
+/**
+ * @param {number} lat Latitude.
+ * @param {number} minLon Minimal longitude.
+ * @param {number} maxLon Maximal longitude.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @param {ol.Extent} extent Extent.
+ * @param {number} index Index.
+ * @return {number} Index.
+ * @private
+ */
+ol.Graticule.prototype.addParallel_ = function(lat, minLon, maxLon, squaredTolerance, extent, index) {
+ var lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance,
+ index);
+ if (ol.extent.intersects(lineString.getExtent(), extent)) {
+ this.parallels_[index++] = lineString;
+ }
+ return index;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Coordinate} center Center.
+ * @param {number} resolution Resolution.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @private
+ */
+ol.Graticule.prototype.createGraticule_ = function(extent, center, resolution, squaredTolerance) {
+
+ var interval = this.getInterval_(resolution);
+ if (interval == -1) {
+ this.meridians_.length = this.parallels_.length = 0;
+ return;
+ }
+
+ var centerLonLat = this.toLonLatTransform_(center);
+ var centerLon = centerLonLat[0];
+ var centerLat = centerLonLat[1];
+ var maxLines = this.maxLines_;
+ var cnt, idx, lat, lon;
+
+ var validExtent = [
+ Math.max(extent[0], this.minLonP_),
+ Math.max(extent[1], this.minLatP_),
+ Math.min(extent[2], this.maxLonP_),
+ Math.min(extent[3], this.maxLatP_)
+ ];
+
+ validExtent = ol.proj.transformExtent(validExtent, this.projection_,
+ 'EPSG:4326');
+ var maxLat = validExtent[3];
+ var maxLon = validExtent[2];
+ var minLat = validExtent[1];
+ var minLon = validExtent[0];
+
+ // Create meridians
+
+ centerLon = Math.floor(centerLon / interval) * interval;
+ lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_);
+
+ idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0);
+
+ cnt = 0;
+ while (lon != this.minLon_ && cnt++ < maxLines) {
+ lon = Math.max(lon - interval, this.minLon_);
+ idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
+ }
+
+ lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_);
+
+ cnt = 0;
+ while (lon != this.maxLon_ && cnt++ < maxLines) {
+ lon = Math.min(lon + interval, this.maxLon_);
+ idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
+ }
+
+ this.meridians_.length = idx;
+
+ // Create parallels
+
+ centerLat = Math.floor(centerLat / interval) * interval;
+ lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_);
+
+ idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0);
+
+ cnt = 0;
+ while (lat != this.minLat_ && cnt++ < maxLines) {
+ lat = Math.max(lat - interval, this.minLat_);
+ idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);
+ }
+
+ lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_);
+
+ cnt = 0;
+ while (lat != this.maxLat_ && cnt++ < maxLines) {
+ lat = Math.min(lat + interval, this.maxLat_);
+ idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);
+ }
+
+ this.parallels_.length = idx;
+
+};
+
+
+/**
+ * @param {number} resolution Resolution.
+ * @return {number} The interval in degrees.
+ * @private
+ */
+ol.Graticule.prototype.getInterval_ = function(resolution) {
+ var centerLon = this.projectionCenterLonLat_[0];
+ var centerLat = this.projectionCenterLonLat_[1];
+ var interval = -1;
+ var i, ii, delta, dist;
+ var target = Math.pow(this.targetSize_ * resolution, 2);
+ /** @type {Array.<number>} **/
+ var p1 = [];
+ /** @type {Array.<number>} **/
+ var p2 = [];
+ for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) {
+ delta = ol.Graticule.intervals_[i] / 2;
+ p1[0] = centerLon - delta;
+ p1[1] = centerLat - delta;
+ p2[0] = centerLon + delta;
+ p2[1] = centerLat + delta;
+ this.fromLonLatTransform_(p1, p1);
+ this.fromLonLatTransform_(p2, p2);
+ dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
+ if (dist <= target) {
+ break;
+ }
+ interval = ol.Graticule.intervals_[i];
+ }
+ return interval;
+};
+
+
+/**
+ * Get the map associated with this graticule.
+ * @return {ol.Map} The map.
+ * @api
+ */
+ol.Graticule.prototype.getMap = function() {
+ return this.map_;
+};
+
+
+/**
+ * @param {number} lon Longitude.
+ * @param {number} minLat Minimal latitude.
+ * @param {number} maxLat Maximal latitude.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {ol.geom.LineString} The meridian line string.
+ * @param {number} index Index.
+ * @private
+ */
+ol.Graticule.prototype.getMeridian_ = function(lon, minLat, maxLat,
+ squaredTolerance, index) {
+ goog.asserts.assert(lon >= this.minLon_,
+ 'lon should be larger than or equal to this.minLon_');
+ goog.asserts.assert(lon <= this.maxLon_,
+ 'lon should be smaller than or equal to this.maxLon_');
+ var flatCoordinates = ol.geom.flat.geodesic.meridian(lon,
+ minLat, maxLat, this.projection_, squaredTolerance);
+ goog.asserts.assert(flatCoordinates.length > 0,
+ 'flatCoordinates cannot be empty');
+ var lineString = this.meridians_[index] !== undefined ?
+ this.meridians_[index] : new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
+ return lineString;
+};
+
+
+/**
+ * Get the list of meridians. Meridians are lines of equal longitude.
+ * @return {Array.<ol.geom.LineString>} The meridians.
+ * @api
+ */
+ol.Graticule.prototype.getMeridians = function() {
+ return this.meridians_;
+};
+
+
+/**
+ * @param {number} lat Latitude.
+ * @param {number} minLon Minimal longitude.
+ * @param {number} maxLon Maximal longitude.
+ * @param {number} squaredTolerance Squared tolerance.
+ * @return {ol.geom.LineString} The parallel line string.
+ * @param {number} index Index.
+ * @private
+ */
+ol.Graticule.prototype.getParallel_ = function(lat, minLon, maxLon,
+ squaredTolerance, index) {
+ goog.asserts.assert(lat >= this.minLat_,
+ 'lat should be larger than or equal to this.minLat_');
+ goog.asserts.assert(lat <= this.maxLat_,
+ 'lat should be smaller than or equal to this.maxLat_');
+ var flatCoordinates = ol.geom.flat.geodesic.parallel(lat,
+ this.minLon_, this.maxLon_, this.projection_, squaredTolerance);
+ goog.asserts.assert(flatCoordinates.length > 0,
+ 'flatCoordinates cannot be empty');
+ var lineString = this.parallels_[index] !== undefined ?
+ this.parallels_[index] : new ol.geom.LineString(null);
+ lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
+ return lineString;
+};
+
+
+/**
+ * Get the list of parallels. Pallels are lines of equal latitude.
+ * @return {Array.<ol.geom.LineString>} The parallels.
+ * @api
+ */
+ol.Graticule.prototype.getParallels = function() {
+ return this.parallels_;
+};
+
+
+/**
+ * @param {ol.render.Event} e Event.
+ * @private
+ */
+ol.Graticule.prototype.handlePostCompose_ = function(e) {
+ var vectorContext = e.vectorContext;
+ var frameState = e.frameState;
+ var extent = frameState.extent;
+ var viewState = frameState.viewState;
+ var center = viewState.center;
+ var projection = viewState.projection;
+ var resolution = viewState.resolution;
+ var pixelRatio = frameState.pixelRatio;
+ var squaredTolerance =
+ resolution * resolution / (4 * pixelRatio * pixelRatio);
+
+ var updateProjectionInfo = !this.projection_ ||
+ !ol.proj.equivalent(this.projection_, projection);
+
+ if (updateProjectionInfo) {
+ this.updateProjectionInfo_(projection);
+ }
+
+ //Fix the extent if wrapped.
+ //(note: this is the same extent as vectorContext.extent_)
+ var offsetX = 0;
+ if (projection.canWrapX()) {
+ var projectionExtent = projection.getExtent();
+ var worldWidth = ol.extent.getWidth(projectionExtent);
+ var x = frameState.focus[0];
+ if (x < projectionExtent[0] || x > projectionExtent[2]) {
+ var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
+ offsetX = worldWidth * worldsAway;
+ extent = [
+ extent[0] + offsetX, extent[1],
+ extent[2] + offsetX, extent[3]
+ ];
+ }
+ }
+
+ this.createGraticule_(extent, center, resolution, squaredTolerance);
+
+ // Draw the lines
+ vectorContext.setFillStrokeStyle(null, this.strokeStyle_);
+ var i, l, line;
+ for (i = 0, l = this.meridians_.length; i < l; ++i) {
+ line = this.meridians_[i];
+ vectorContext.drawLineString(line, null);
+ }
+ for (i = 0, l = this.parallels_.length; i < l; ++i) {
+ line = this.parallels_[i];
+ vectorContext.drawLineString(line, null);
+ }
+};
+
+
+/**
+ * @param {ol.proj.Projection} projection Projection.
+ * @private
+ */
+ol.Graticule.prototype.updateProjectionInfo_ = function(projection) {
+ goog.asserts.assert(projection, 'projection cannot be null');
+
+ var epsg4326Projection = ol.proj.get('EPSG:4326');
+
+ var extent = projection.getExtent();
+ var worldExtent = projection.getWorldExtent();
+ var worldExtentP = ol.proj.transformExtent(worldExtent,
+ epsg4326Projection, projection);
+
+ var maxLat = worldExtent[3];
+ var maxLon = worldExtent[2];
+ var minLat = worldExtent[1];
+ var minLon = worldExtent[0];
+
+ var maxLatP = worldExtentP[3];
+ var maxLonP = worldExtentP[2];
+ var minLatP = worldExtentP[1];
+ var minLonP = worldExtentP[0];
+
+ goog.asserts.assert(extent, 'extent cannot be null');
+ goog.asserts.assert(maxLat !== undefined, 'maxLat should be defined');
+ goog.asserts.assert(maxLon !== undefined, 'maxLon should be defined');
+ goog.asserts.assert(minLat !== undefined, 'minLat should be defined');
+ goog.asserts.assert(minLon !== undefined, 'minLon should be defined');
+
+ goog.asserts.assert(maxLatP !== undefined,
+ 'projected maxLat should be defined');
+ goog.asserts.assert(maxLonP !== undefined,
+ 'projected maxLon should be defined');
+ goog.asserts.assert(minLatP !== undefined,
+ 'projected minLat should be defined');
+ goog.asserts.assert(minLonP !== undefined,
+ 'projected minLon should be defined');
+
+ this.maxLat_ = maxLat;
+ this.maxLon_ = maxLon;
+ this.minLat_ = minLat;
+ this.minLon_ = minLon;
+
+ this.maxLatP_ = maxLatP;
+ this.maxLonP_ = maxLonP;
+ this.minLatP_ = minLatP;
+ this.minLonP_ = minLonP;
+
+
+ this.fromLonLatTransform_ = ol.proj.getTransform(
+ epsg4326Projection, projection);
+
+ this.toLonLatTransform_ = ol.proj.getTransform(
+ projection, epsg4326Projection);
+
+ this.projectionCenterLonLat_ = this.toLonLatTransform_(
+ ol.extent.getCenter(extent));
+
+ this.projection_ = projection;
+};
+
+
+/**
+ * Set the map for this graticule. The graticule will be rendered on the
+ * provided map.
+ * @param {ol.Map} map Map.
+ * @api
+ */
+ol.Graticule.prototype.setMap = function(map) {
+ if (this.map_) {
+ this.map_.un(ol.render.EventType.POSTCOMPOSE,
+ this.handlePostCompose_, this);
+ this.map_.render();
+ }
+ if (map) {
+ map.on(ol.render.EventType.POSTCOMPOSE,
+ this.handlePostCompose_, this);
+ map.render();
+ }
+ this.map_ = map;
+};
+
+goog.provide('ol.Image');
+
+goog.require('goog.asserts');
+goog.require('ol.ImageBase');
+goog.require('ol.ImageState');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.object');
+
+
+/**
+ * @constructor
+ * @extends {ol.ImageBase}
+ * @param {ol.Extent} extent Extent.
+ * @param {number|undefined} resolution Resolution.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {Array.<ol.Attribution>} attributions Attributions.
+ * @param {string} src Image source URI.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
+ */
+ol.Image = function(extent, resolution, pixelRatio, attributions, src,
+ crossOrigin, imageLoadFunction) {
+
+ ol.ImageBase.call(this, extent, resolution, pixelRatio, ol.ImageState.IDLE,
+ attributions);
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.src_ = src;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement|Image|HTMLVideoElement}
+ */
+ this.image_ = new Image();
+ if (crossOrigin !== null) {
+ this.image_.crossOrigin = crossOrigin;
+ }
+
+ /**
+ * @private
+ * @type {Object.<number, (HTMLCanvasElement|Image|HTMLVideoElement)>}
+ */
+ this.imageByContext_ = {};
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.imageListenerKeys_ = null;
+
+ /**
+ * @protected
+ * @type {ol.ImageState}
+ */
+ this.state = ol.ImageState.IDLE;
+
+ /**
+ * @private
+ * @type {ol.ImageLoadFunctionType}
+ */
+ this.imageLoadFunction_ = imageLoadFunction;
+
+};
+ol.inherits(ol.Image, ol.ImageBase);
+
+
+/**
+ * Get the HTML image element (may be a Canvas, Image, or Video).
+ * @param {Object=} opt_context Object.
+ * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.
+ * @api
+ */
+ol.Image.prototype.getImage = function(opt_context) {
+ if (opt_context !== undefined) {
+ var image;
+ var key = goog.getUid(opt_context);
+ if (key in this.imageByContext_) {
+ return this.imageByContext_[key];
+ } else if (ol.object.isEmpty(this.imageByContext_)) {
+ image = this.image_;
+ } else {
+ image = /** @type {Image} */ (this.image_.cloneNode(false));
+ }
+ this.imageByContext_[key] = image;
+ return image;
+ } else {
+ return this.image_;
+ }
+};
+
+
+/**
+ * Tracks loading or read errors.
+ *
+ * @private
+ */
+ol.Image.prototype.handleImageError_ = function() {
+ this.state = ol.ImageState.ERROR;
+ this.unlistenImage_();
+ this.changed();
+};
+
+
+/**
+ * Tracks successful image load.
+ *
+ * @private
+ */
+ol.Image.prototype.handleImageLoad_ = function() {
+ if (this.resolution === undefined) {
+ this.resolution = ol.extent.getHeight(this.extent) / this.image_.height;
+ }
+ this.state = ol.ImageState.LOADED;
+ this.unlistenImage_();
+ this.changed();
+};
+
+
+/**
+ * Load the image or retry if loading previously failed.
+ * Loading is taken care of by the tile queue, and calling this method is
+ * only needed for preloading or for reloading in case of an error.
+ * @api
+ */
+ol.Image.prototype.load = function() {
+ if (this.state == ol.ImageState.IDLE || this.state == ol.ImageState.ERROR) {
+ this.state = ol.ImageState.LOADING;
+ this.changed();
+ goog.asserts.assert(!this.imageListenerKeys_,
+ 'this.imageListenerKeys_ should be null');
+ this.imageListenerKeys_ = [
+ ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,
+ this.handleImageError_, this),
+ ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,
+ this.handleImageLoad_, this)
+ ];
+ this.imageLoadFunction_(this, this.src_);
+ }
+};
+
+
+/**
+ * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image.
+ */
+ol.Image.prototype.setImage = function(image) {
+ this.image_ = image;
+};
+
+
+/**
+ * Discards event handlers which listen for load completion or errors.
+ *
+ * @private
+ */
+ol.Image.prototype.unlistenImage_ = function() {
+ goog.asserts.assert(this.imageListenerKeys_,
+ 'this.imageListenerKeys_ should not be null');
+ this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.imageListenerKeys_ = null;
+};
+
+goog.provide('ol.ImageTile');
+
+goog.require('goog.asserts');
+goog.require('ol.Tile');
+goog.require('ol.TileState');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.object');
+
+
+/**
+ * @constructor
+ * @extends {ol.Tile}
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.TileState} state State.
+ * @param {string} src Image source URI.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
+ */
+ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) {
+
+ ol.Tile.call(this, tileCoord, state);
+
+ /**
+ * Image URI
+ *
+ * @private
+ * @type {string}
+ */
+ this.src_ = src;
+
+ /**
+ * @private
+ * @type {Image}
+ */
+ this.image_ = new Image();
+ if (crossOrigin !== null) {
+ this.image_.crossOrigin = crossOrigin;
+ }
+
+ /**
+ * @private
+ * @type {Object.<number, Image>}
+ */
+ this.imageByContext_ = {};
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.imageListenerKeys_ = null;
+
+ /**
+ * @private
+ * @type {ol.TileLoadFunctionType}
+ */
+ this.tileLoadFunction_ = tileLoadFunction;
+
+};
+ol.inherits(ol.ImageTile, ol.Tile);
+
+
+/**
+ * @inheritDoc
+ */
+ol.ImageTile.prototype.disposeInternal = function() {
+ if (this.state == ol.TileState.LOADING) {
+ this.unlistenImage_();
+ }
+ if (this.interimTile) {
+ this.interimTile.dispose();
+ }
+ this.state = ol.TileState.ABORT;
+ this.changed();
+ ol.Tile.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * Get the image element for this tile.
+ * @inheritDoc
+ * @api
+ */
+ol.ImageTile.prototype.getImage = function(opt_context) {
+ if (opt_context !== undefined) {
+ var image;
+ var key = goog.getUid(opt_context);
+ if (key in this.imageByContext_) {
+ return this.imageByContext_[key];
+ } else if (ol.object.isEmpty(this.imageByContext_)) {
+ image = this.image_;
+ } else {
+ image = /** @type {Image} */ (this.image_.cloneNode(false));
+ }
+ this.imageByContext_[key] = image;
+ return image;
+ } else {
+ return this.image_;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.ImageTile.prototype.getKey = function() {
+ return this.src_;
+};
+
+
+/**
+ * Tracks loading or read errors.
+ *
+ * @private
+ */
+ol.ImageTile.prototype.handleImageError_ = function() {
+ this.state = ol.TileState.ERROR;
+ this.unlistenImage_();
+ this.changed();
+};
+
+
+/**
+ * Tracks successful image load.
+ *
+ * @private
+ */
+ol.ImageTile.prototype.handleImageLoad_ = function() {
+ if (this.image_.naturalWidth && this.image_.naturalHeight) {
+ this.state = ol.TileState.LOADED;
+ } else {
+ this.state = ol.TileState.EMPTY;
+ }
+ this.unlistenImage_();
+ this.changed();
+};
+
+
+/**
+ * Load the image or retry if loading previously failed.
+ * Loading is taken care of by the tile queue, and calling this method is
+ * only needed for preloading or for reloading in case of an error.
+ * @api
+ */
+ol.ImageTile.prototype.load = function() {
+ if (this.state == ol.TileState.IDLE || this.state == ol.TileState.ERROR) {
+ this.state = ol.TileState.LOADING;
+ this.changed();
+ goog.asserts.assert(!this.imageListenerKeys_,
+ 'this.imageListenerKeys_ should be null');
+ this.imageListenerKeys_ = [
+ ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,
+ this.handleImageError_, this),
+ ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,
+ this.handleImageLoad_, this)
+ ];
+ this.tileLoadFunction_(this, this.src_);
+ }
+};
+
+
+/**
+ * Discards event handlers which listen for load completion or errors.
+ *
+ * @private
+ */
+ol.ImageTile.prototype.unlistenImage_ = function() {
+ goog.asserts.assert(this.imageListenerKeys_,
+ 'this.imageListenerKeys_ should not be null');
+ this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.imageListenerKeys_ = null;
+};
+
+// FIXME should handle all geo-referenced data, not just vector data
+
+goog.provide('ol.interaction.DragAndDrop');
+goog.provide('ol.interaction.DragAndDropEvent');
+
+goog.require('goog.asserts');
+goog.require('ol.functions');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.proj');
+
+
+/**
+ * @classdesc
+ * Handles input of vector data by drag and drop.
+ *
+ * @constructor
+ * @extends {ol.interaction.Interaction}
+ * @fires ol.interaction.DragAndDropEvent
+ * @param {olx.interaction.DragAndDropOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DragAndDrop = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: ol.interaction.DragAndDrop.handleEvent
+ });
+
+ /**
+ * @private
+ * @type {Array.<function(new: ol.format.Feature)>}
+ */
+ this.formatConstructors_ = options.formatConstructors ?
+ options.formatConstructors : [];
+
+ /**
+ * @private
+ * @type {ol.proj.Projection}
+ */
+ this.projection_ = options.projection ?
+ ol.proj.get(options.projection) : null;
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.dropListenKeys_ = null;
+
+ /**
+ * @private
+ * @type {Element}
+ */
+ this.target = options.target ? options.target : null;
+
+};
+ol.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction);
+
+
+/**
+ * @param {Event} event Event.
+ * @this {ol.interaction.DragAndDrop}
+ * @private
+ */
+ol.interaction.DragAndDrop.handleDrop_ = function(event) {
+ var files = event.dataTransfer.files;
+ var i, ii, file;
+ for (i = 0, ii = files.length; i < ii; ++i) {
+ file = files.item(i);
+ var reader = new FileReader();
+ reader.addEventListener(ol.events.EventType.LOAD,
+ this.handleResult_.bind(this, file));
+ reader.readAsText(file);
+ }
+};
+
+
+/**
+ * @param {Event} event Event.
+ * @private
+ */
+ol.interaction.DragAndDrop.handleStop_ = function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ event.dataTransfer.dropEffect = 'copy';
+};
+
+
+/**
+ * @param {File} file File.
+ * @param {Event} event Load event.
+ * @private
+ */
+ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, event) {
+ var result = event.target.result;
+ var map = this.getMap();
+ goog.asserts.assert(map, 'map must be set');
+ var projection = this.projection_;
+ if (!projection) {
+ var view = map.getView();
+ goog.asserts.assert(view, 'map must have view');
+ projection = view.getProjection();
+ goog.asserts.assert(projection !== undefined,
+ 'projection should be defined');
+ }
+ var formatConstructors = this.formatConstructors_;
+ var features = [];
+ var i, ii;
+ for (i = 0, ii = formatConstructors.length; i < ii; ++i) {
+ var formatConstructor = formatConstructors[i];
+ var format = new formatConstructor();
+ features = this.tryReadFeatures_(format, result, {
+ featureProjection: projection
+ });
+ if (features && features.length > 0) {
+ break;
+ }
+ }
+ this.dispatchEvent(
+ new ol.interaction.DragAndDropEvent(
+ ol.interaction.DragAndDropEventType.ADD_FEATURES, this, file,
+ features, projection));
+};
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and
+ * neither prevents the browser default nor stops event propagation.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.DragAndDrop}
+ * @api
+ */
+ol.interaction.DragAndDrop.handleEvent = ol.functions.TRUE;
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.DragAndDrop.prototype.setMap = function(map) {
+ if (this.dropListenKeys_) {
+ this.dropListenKeys_.forEach(ol.events.unlistenByKey);
+ this.dropListenKeys_ = null;
+ }
+ ol.interaction.Interaction.prototype.setMap.call(this, map);
+ if (map) {
+ var dropArea = this.target ? this.target : map.getViewport();
+ this.dropListenKeys_ = [
+ ol.events.listen(dropArea, ol.events.EventType.DROP,
+ ol.interaction.DragAndDrop.handleDrop_, this),
+ ol.events.listen(dropArea, ol.events.EventType.DRAGENTER,
+ ol.interaction.DragAndDrop.handleStop_, this),
+ ol.events.listen(dropArea, ol.events.EventType.DRAGOVER,
+ ol.interaction.DragAndDrop.handleStop_, this),
+ ol.events.listen(dropArea, ol.events.EventType.DROP,
+ ol.interaction.DragAndDrop.handleStop_, this)
+ ];
+ }
+};
+
+
+/**
+ * @param {ol.format.Feature} format Format.
+ * @param {string} text Text.
+ * @param {olx.format.ReadOptions} options Read options.
+ * @private
+ * @return {Array.<ol.Feature>} Features.
+ */
+ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text, options) {
+ try {
+ return format.readFeatures(text, options);
+ } catch (e) {
+ return null;
+ }
+};
+
+
+/**
+ * @enum {string}
+ */
+ol.interaction.DragAndDropEventType = {
+ /**
+ * Triggered when features are added
+ * @event ol.interaction.DragAndDropEvent#addfeatures
+ * @api stable
+ */
+ ADD_FEATURES: 'addfeatures'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances
+ * of this type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.interaction.DragAndDropEvent}
+ * @param {ol.interaction.DragAndDropEventType} type Type.
+ * @param {Object} target Target.
+ * @param {File} file File.
+ * @param {Array.<ol.Feature>=} opt_features Features.
+ * @param {ol.proj.Projection=} opt_projection Projection.
+ */
+ol.interaction.DragAndDropEvent = function(type, target, file, opt_features, opt_projection) {
+
+ ol.events.Event.call(this, type, target);
+
+ /**
+ * The features parsed from dropped data.
+ * @type {Array.<ol.Feature>|undefined}
+ * @api stable
+ */
+ this.features = opt_features;
+
+ /**
+ * The dropped file.
+ * @type {File}
+ * @api stable
+ */
+ this.file = file;
+
+ /**
+ * The feature projection.
+ * @type {ol.proj.Projection|undefined}
+ * @api
+ */
+ this.projection = opt_projection;
+
+};
+ol.inherits(ol.interaction.DragAndDropEvent, ol.events.Event);
+
+goog.provide('ol.interaction.DragRotateAndZoom');
+
+goog.require('ol');
+goog.require('ol.ViewHint');
+goog.require('ol.events.condition');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.interaction.Pointer');
+
+
+/**
+ * @classdesc
+ * Allows the user to zoom and rotate the map by clicking and dragging
+ * on the map. By default, this interaction is limited to when the shift
+ * key is held down.
+ *
+ * This interaction is only supported for mouse devices.
+ *
+ * And this interaction is not included in the default interactions.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.DragRotateAndZoomOptions=} opt_options Options.
+ * @api stable
+ */
+ol.interaction.DragRotateAndZoom = function(opt_options) {
+
+ var options = opt_options ? opt_options : {};
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_,
+ handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_,
+ handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_
+ });
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.shiftKeyOnly;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastAngle_ = undefined;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastMagnitude_ = undefined;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.lastScaleDelta_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.duration_ = options.duration !== undefined ? options.duration : 400;
+
+};
+ol.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @this {ol.interaction.DragRotateAndZoom}
+ * @private
+ */
+ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return;
+ }
+
+ var map = mapBrowserEvent.map;
+ var size = map.getSize();
+ var offset = mapBrowserEvent.pixel;
+ var deltaX = offset[0] - size[0] / 2;
+ var deltaY = size[1] / 2 - offset[1];
+ var theta = Math.atan2(deltaY, deltaX);
+ var magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+ var view = map.getView();
+ map.render();
+ if (this.lastAngle_ !== undefined) {
+ var angleDelta = theta - this.lastAngle_;
+ ol.interaction.Interaction.rotateWithoutConstraints(
+ map, view, view.getRotation() - angleDelta);
+ }
+ this.lastAngle_ = theta;
+ if (this.lastMagnitude_ !== undefined) {
+ var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude);
+ ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution);
+ }
+ if (this.lastMagnitude_ !== undefined) {
+ this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
+ }
+ this.lastMagnitude_ = magnitude;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.DragRotateAndZoom}
+ * @private
+ */
+ol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return true;
+ }
+
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ view.setHint(ol.ViewHint.INTERACTING, -1);
+ var direction = this.lastScaleDelta_ - 1;
+ ol.interaction.Interaction.rotate(map, view, view.getRotation());
+ ol.interaction.Interaction.zoom(map, view, view.getResolution(),
+ undefined, this.duration_, direction);
+ this.lastScaleDelta_ = 0;
+ return false;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.DragRotateAndZoom}
+ * @private
+ */
+ol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) {
+ if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
+ return false;
+ }
+
+ if (this.condition_(mapBrowserEvent)) {
+ mapBrowserEvent.map.getView().setHint(ol.ViewHint.INTERACTING, 1);
+ this.lastAngle_ = undefined;
+ this.lastMagnitude_ = undefined;
+ return true;
+ } else {
+ return false;
+ }
+};
+
+goog.provide('ol.interaction.Draw');
+goog.provide('ol.interaction.DrawEvent');
+goog.provide('ol.interaction.DrawEventType');
+goog.provide('ol.interaction.DrawMode');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.Collection');
+goog.require('ol.Feature');
+goog.require('ol.MapBrowserEvent');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.Object');
+goog.require('ol.coordinate');
+goog.require('ol.functions');
+goog.require('ol.events.condition');
+goog.require('ol.geom.Circle');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.interaction.InteractionProperty');
+goog.require('ol.interaction.Pointer');
+goog.require('ol.layer.Vector');
+goog.require('ol.source.Vector');
+
+
+/**
+ * @enum {string}
+ */
+ol.interaction.DrawEventType = {
+ /**
+ * Triggered upon feature draw start
+ * @event ol.interaction.DrawEvent#drawstart
+ * @api stable
+ */
+ DRAWSTART: 'drawstart',
+ /**
+ * Triggered upon feature draw end
+ * @event ol.interaction.DrawEvent#drawend
+ * @api stable
+ */
+ DRAWEND: 'drawend'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.interaction.Draw} instances are instances of
+ * this type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.DrawEvent}
+ * @param {ol.interaction.DrawEventType} type Type.
+ * @param {ol.Feature} feature The feature drawn.
+ */
+ol.interaction.DrawEvent = function(type, feature) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The feature being drawn.
+ * @type {ol.Feature}
+ * @api stable
+ */
+ this.feature = feature;
+
+};
+ol.inherits(ol.interaction.DrawEvent, ol.events.Event);
+
+
+/**
+ * @classdesc
+ * Interaction for drawing feature geometries.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @fires ol.interaction.DrawEvent
+ * @param {olx.interaction.DrawOptions} options Options.
+ * @api stable
+ */
+ol.interaction.Draw = function(options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.Draw.handleDownEvent_,
+ handleEvent: ol.interaction.Draw.handleEvent,
+ handleUpEvent: ol.interaction.Draw.handleUpEvent_
+ });
+
+ /**
+ * @type {ol.Pixel}
+ * @private
+ */
+ this.downPx_ = null;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.freehand_ = false;
+
+ /**
+ * Target source for drawn features.
+ * @type {ol.source.Vector}
+ * @private
+ */
+ this.source_ = options.source ? options.source : null;
+
+ /**
+ * Target collection for drawn features.
+ * @type {ol.Collection.<ol.Feature>}
+ * @private
+ */
+ this.features_ = options.features ? options.features : null;
+
+ /**
+ * Pixel distance for snapping.
+ * @type {number}
+ * @private
+ */
+ this.snapTolerance_ = options.snapTolerance ? options.snapTolerance : 12;
+
+ /**
+ * Geometry type.
+ * @type {ol.geom.GeometryType}
+ * @private
+ */
+ this.type_ = options.type;
+
+ /**
+ * Drawing mode (derived from geometry type.
+ * @type {ol.interaction.DrawMode}
+ * @private
+ */
+ this.mode_ = ol.interaction.Draw.getMode_(this.type_);
+
+ /**
+ * The number of points that must be drawn before a polygon ring or line
+ * string can be finished. The default is 3 for polygon rings and 2 for
+ * line strings.
+ * @type {number}
+ * @private
+ */
+ this.minPoints_ = options.minPoints ?
+ options.minPoints :
+ (this.mode_ === ol.interaction.DrawMode.POLYGON ? 3 : 2);
+
+ /**
+ * The number of points that can be drawn before a polygon ring or line string
+ * is finished. The default is no restriction.
+ * @type {number}
+ * @private
+ */
+ this.maxPoints_ = options.maxPoints ? options.maxPoints : Infinity;
+
+ /**
+ * A function to decide if a potential finish coordinate is permissable
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.finishCondition_ = options.finishCondition ? options.finishCondition : ol.functions.TRUE;
+
+ var geometryFunction = options.geometryFunction;
+ if (!geometryFunction) {
+ if (this.type_ === ol.geom.GeometryType.CIRCLE) {
+ /**
+ * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
+ * The coordinates.
+ * @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.
+ * @return {ol.geom.SimpleGeometry} A geometry.
+ */
+ geometryFunction = function(coordinates, opt_geometry) {
+ var circle = opt_geometry ? opt_geometry :
+ new ol.geom.Circle([NaN, NaN]);
+ goog.asserts.assertInstanceof(circle, ol.geom.Circle,
+ 'geometry must be an ol.geom.Circle');
+ var squaredLength = ol.coordinate.squaredDistance(
+ coordinates[0], coordinates[1]);
+ circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength));
+ return circle;
+ };
+ } else {
+ var Constructor;
+ var mode = this.mode_;
+ if (mode === ol.interaction.DrawMode.POINT) {
+ Constructor = ol.geom.Point;
+ } else if (mode === ol.interaction.DrawMode.LINE_STRING) {
+ Constructor = ol.geom.LineString;
+ } else if (mode === ol.interaction.DrawMode.POLYGON) {
+ Constructor = ol.geom.Polygon;
+ }
+ /**
+ * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
+ * The coordinates.
+ * @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.
+ * @return {ol.geom.SimpleGeometry} A geometry.
+ */
+ geometryFunction = function(coordinates, opt_geometry) {
+ var geometry = opt_geometry;
+ if (geometry) {
+ geometry.setCoordinates(coordinates);
+ } else {
+ geometry = new Constructor(coordinates);
+ }
+ return geometry;
+ };
+ }
+ }
+
+ /**
+ * @type {ol.DrawGeometryFunctionType}
+ * @private
+ */
+ this.geometryFunction_ = geometryFunction;
+
+ /**
+ * Finish coordinate for the feature (first point for polygons, last point for
+ * linestrings).
+ * @type {ol.Coordinate}
+ * @private
+ */
+ this.finishCoordinate_ = null;
+
+ /**
+ * Sketch feature.
+ * @type {ol.Feature}
+ * @private
+ */
+ this.sketchFeature_ = null;
+
+ /**
+ * Sketch point.
+ * @type {ol.Feature}
+ * @private
+ */
+ this.sketchPoint_ = null;
+
+ /**
+ * Sketch coordinates. Used when drawing a line or polygon.
+ * @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>}
+ * @private
+ */
+ this.sketchCoords_ = null;
+
+ /**
+ * Sketch line. Used when drawing polygon.
+ * @type {ol.Feature}
+ * @private
+ */
+ this.sketchLine_ = null;
+
+ /**
+ * Sketch line coordinates. Used when drawing a polygon or circle.
+ * @type {Array.<ol.Coordinate>}
+ * @private
+ */
+ this.sketchLineCoords_ = null;
+
+ /**
+ * Squared tolerance for handling up events. If the squared distance
+ * between a down and up event is greater than this tolerance, up events
+ * will not be handled.
+ * @type {number}
+ * @private
+ */
+ this.squaredClickTolerance_ = options.clickTolerance ?
+ options.clickTolerance * options.clickTolerance : 36;
+
+ /**
+ * Draw overlay where our sketch features are drawn.
+ * @type {ol.layer.Vector}
+ * @private
+ */
+ this.overlay_ = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ useSpatialIndex: false,
+ wrapX: options.wrapX ? options.wrapX : false
+ }),
+ style: options.style ? options.style :
+ ol.interaction.Draw.getDefaultStyleFunction()
+ });
+
+ /**
+ * Name of the geometry attribute for newly created features.
+ * @type {string|undefined}
+ * @private
+ */
+ this.geometryName_ = options.geometryName;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.noModifierKeys;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.freehandCondition_ = options.freehandCondition ?
+ options.freehandCondition : ol.events.condition.shiftKeyOnly;
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.interaction.InteractionProperty.ACTIVE),
+ this.updateState_, this);
+
+};
+ol.inherits(ol.interaction.Draw, ol.interaction.Pointer);
+
+
+/**
+ * @return {ol.StyleFunction} Styles.
+ */
+ol.interaction.Draw.getDefaultStyleFunction = function() {
+ var styles = ol.style.createDefaultEditingStyles();
+ return function(feature, resolution) {
+ return styles[feature.getGeometry().getType()];
+ };
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.Draw.prototype.setMap = function(map) {
+ ol.interaction.Pointer.prototype.setMap.call(this, map);
+ this.updateState_();
+};
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} and may actually
+ * draw or finish the drawing.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.Draw}
+ * @api
+ */
+ol.interaction.Draw.handleEvent = function(mapBrowserEvent) {
+ if ((this.mode_ === ol.interaction.DrawMode.LINE_STRING ||
+ this.mode_ === ol.interaction.DrawMode.POLYGON) &&
+ this.freehandCondition_(mapBrowserEvent)) {
+ this.freehand_ = true;
+ }
+ var pass = !this.freehand_;
+ if (this.freehand_ &&
+ mapBrowserEvent.type === ol.MapBrowserEvent.EventType.POINTERDRAG) {
+ this.addToDrawing_(mapBrowserEvent);
+ pass = false;
+ } else if (mapBrowserEvent.type ===
+ ol.MapBrowserEvent.EventType.POINTERMOVE) {
+ pass = this.handlePointerMove_(mapBrowserEvent);
+ } else if (mapBrowserEvent.type === ol.MapBrowserEvent.EventType.DBLCLICK) {
+ pass = false;
+ }
+ return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) && pass;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} event Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.Draw}
+ * @private
+ */
+ol.interaction.Draw.handleDownEvent_ = function(event) {
+ if (this.condition_(event)) {
+ this.downPx_ = event.pixel;
+ return true;
+ } else if (this.freehand_) {
+ this.downPx_ = event.pixel;
+ if (!this.finishCoordinate_) {
+ this.startDrawing_(event);
+ }
+ return true;
+ } else {
+ return false;
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} event Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.Draw}
+ * @private
+ */
+ol.interaction.Draw.handleUpEvent_ = function(event) {
+ this.freehand_ = false;
+ var downPx = this.downPx_;
+ var clickPx = event.pixel;
+ var dx = downPx[0] - clickPx[0];
+ var dy = downPx[1] - clickPx[1];
+ var squaredDistance = dx * dx + dy * dy;
+ var pass = true;
+ if (squaredDistance <= this.squaredClickTolerance_) {
+ this.handlePointerMove_(event);
+ if (!this.finishCoordinate_) {
+ this.startDrawing_(event);
+ if (this.mode_ === ol.interaction.DrawMode.POINT) {
+ this.finishDrawing();
+ }
+ } else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
+ this.finishDrawing();
+ } else if (this.atFinish_(event)) {
+ if (this.finishCondition_(event)) {
+ this.finishDrawing();
+ }
+ } else {
+ this.addToDrawing_(event);
+ }
+ pass = false;
+ }
+ return pass;
+};
+
+
+/**
+ * Handle move events.
+ * @param {ol.MapBrowserEvent} event A move event.
+ * @return {boolean} Pass the event to other interactions.
+ * @private
+ */
+ol.interaction.Draw.prototype.handlePointerMove_ = function(event) {
+ if (this.finishCoordinate_) {
+ this.modifyDrawing_(event);
+ } else {
+ this.createOrUpdateSketchPoint_(event);
+ }
+ return true;
+};
+
+
+/**
+ * Determine if an event is within the snapping tolerance of the start coord.
+ * @param {ol.MapBrowserEvent} event Event.
+ * @return {boolean} The event is within the snapping tolerance of the start.
+ * @private
+ */
+ol.interaction.Draw.prototype.atFinish_ = function(event) {
+ var at = false;
+ if (this.sketchFeature_) {
+ var potentiallyDone = false;
+ var potentiallyFinishCoordinates = [this.finishCoordinate_];
+ if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
+ potentiallyDone = this.sketchCoords_.length > this.minPoints_;
+ } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
+ potentiallyDone = this.sketchCoords_[0].length >
+ this.minPoints_;
+ potentiallyFinishCoordinates = [this.sketchCoords_[0][0],
+ this.sketchCoords_[0][this.sketchCoords_[0].length - 2]];
+ }
+ if (potentiallyDone) {
+ var map = event.map;
+ for (var i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) {
+ var finishCoordinate = potentiallyFinishCoordinates[i];
+ var finishPixel = map.getPixelFromCoordinate(finishCoordinate);
+ var pixel = event.pixel;
+ var dx = pixel[0] - finishPixel[0];
+ var dy = pixel[1] - finishPixel[1];
+ var freehand = this.freehand_ && this.freehandCondition_(event);
+ var snapTolerance = freehand ? 1 : this.snapTolerance_;
+ at = Math.sqrt(dx * dx + dy * dy) <= snapTolerance;
+ if (at) {
+ this.finishCoordinate_ = finishCoordinate;
+ break;
+ }
+ }
+ }
+ }
+ return at;
+};
+
+
+/**
+ * @param {ol.MapBrowserEvent} event Event.
+ * @private
+ */
+ol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) {
+ var coordinates = event.coordinate.slice();
+ if (!this.sketchPoint_) {
+ this.sketchPoint_ = new ol.Feature(new ol.geom.Point(coordinates));
+ this.updateSketchFeatures_();
+ } else {
+ var sketchPointGeom = this.sketchPoint_.getGeometry();
+ goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point,
+ 'sketchPointGeom should be an ol.geom.Point');
+ sketchPointGeom.setCoordinates(coordinates);
+ }
+};
+
+
+/**
+ * Start the drawing.
+ * @param {ol.MapBrowserEvent} event Event.
+ * @private
+ */
+ol.interaction.Draw.prototype.startDrawing_ = function(event) {
+ var start = event.coordinate;
+ this.finishCoordinate_ = start;
+ if (this.mode_ === ol.interaction.DrawMode.POINT) {
+ this.sketchCoords_ = start.slice();
+ } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
+ this.sketchCoords_ = [[start.slice(), start.slice()]];
+ this.sketchLineCoords_ = this.sketchCoords_[0];
+ } else {
+ this.sketchCoords_ = [start.slice(), start.slice()];
+ if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
+ this.sketchLineCoords_ = this.sketchCoords_;
+ }
+ }
+ if (this.sketchLineCoords_) {
+ this.sketchLine_ = new ol.Feature(
+ new ol.geom.LineString(this.sketchLineCoords_));
+ }
+ var geometry = this.geometryFunction_(this.sketchCoords_);
+ goog.asserts.assert(geometry !== undefined, 'geometry should be defined');
+ this.sketchFeature_ = new ol.Feature();
+ if (this.geometryName_) {
+ this.sketchFeature_.setGeometryName(this.geometryName_);
+ }
+ this.sketchFeature_.setGeometry(geometry);
+ this.updateSketchFeatures_();
+ this.dispatchEvent(new ol.interaction.DrawEvent(
+ ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_));
+};
+
+
+/**
+ * Modify the drawing.
+ * @param {ol.MapBrowserEvent} event Event.
+ * @private
+ */
+ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
+ var coordinate = event.coordinate;
+ var geometry = this.sketchFeature_.getGeometry();
+ goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
+ 'geometry should be ol.geom.SimpleGeometry or subclass');
+ var coordinates, last;
+ if (this.mode_ === ol.interaction.DrawMode.POINT) {
+ last = this.sketchCoords_;
+ } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
+ coordinates = this.sketchCoords_[0];
+ last = coordinates[coordinates.length - 1];
+ if (this.atFinish_(event)) {
+ // snap to finish
+ coordinate = this.finishCoordinate_.slice();
+ }
+ } else {
+ coordinates = this.sketchCoords_;
+ last = coordinates[coordinates.length - 1];
+ }
+ last[0] = coordinate[0];
+ last[1] = coordinate[1];
+ goog.asserts.assert(this.sketchCoords_, 'sketchCoords_ expected');
+ this.geometryFunction_(this.sketchCoords_, geometry);
+ if (this.sketchPoint_) {
+ var sketchPointGeom = this.sketchPoint_.getGeometry();
+ goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point,
+ 'sketchPointGeom should be an ol.geom.Point');
+ sketchPointGeom.setCoordinates(coordinate);
+ }
+ var sketchLineGeom;
+ if (geometry instanceof ol.geom.Polygon &&
+ this.mode_ !== ol.interaction.DrawMode.POLYGON) {
+ if (!this.sketchLine_) {
+ this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null));
+ }
+ var ring = geometry.getLinearRing(0);
+ sketchLineGeom = this.sketchLine_.getGeometry();
+ goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
+ 'sketchLineGeom must be an ol.geom.LineString');
+ sketchLineGeom.setFlatCoordinates(
+ ring.getLayout(), ring.getFlatCoordinates());
+ } else if (this.sketchLineCoords_) {
+ sketchLineGeom = this.sketchLine_.getGeometry();
+ goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
+ 'sketchLineGeom must be an ol.geom.LineString');
+ sketchLineGeom.setCoordinates(this.sketchLineCoords_);
+ }
+ this.updateSketchFeatures_();
+};
+
+
+/**
+ * Add a new coordinate to the drawing.
+ * @param {ol.MapBrowserEvent} event Event.
+ * @private
+ */
+ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
+ var coordinate = event.coordinate;
+ var geometry = this.sketchFeature_.getGeometry();
+ goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
+ 'geometry must be an ol.geom.SimpleGeometry');
+ var done;
+ var coordinates;
+ if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
+ this.finishCoordinate_ = coordinate.slice();
+ coordinates = this.sketchCoords_;
+ coordinates.push(coordinate.slice());
+ done = coordinates.length > this.maxPoints_;
+ this.geometryFunction_(coordinates, geometry);
+ } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
+ coordinates = this.sketchCoords_[0];
+ coordinates.push(coordinate.slice());
+ done = coordinates.length > this.maxPoints_;
+ if (done) {
+ this.finishCoordinate_ = coordinates[0];
+ }
+ this.geometryFunction_(this.sketchCoords_, geometry);
+ }
+ this.updateSketchFeatures_();
+ if (done) {
+ this.finishDrawing();
+ }
+};
+
+
+/**
+ * Remove last point of the feature currently being drawn.
+ * @api
+ */
+ol.interaction.Draw.prototype.removeLastPoint = function() {
+ var geometry = this.sketchFeature_.getGeometry();
+ goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
+ 'geometry must be an ol.geom.SimpleGeometry');
+ var coordinates, sketchLineGeom;
+ if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
+ coordinates = this.sketchCoords_;
+ coordinates.splice(-2, 1);
+ this.geometryFunction_(coordinates, geometry);
+ } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
+ coordinates = this.sketchCoords_[0];
+ coordinates.splice(-2, 1);
+ sketchLineGeom = this.sketchLine_.getGeometry();
+ goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
+ 'sketchLineGeom must be an ol.geom.LineString');
+ sketchLineGeom.setCoordinates(coordinates);
+ this.geometryFunction_(this.sketchCoords_, geometry);
+ }
+
+ if (coordinates.length === 0) {
+ this.finishCoordinate_ = null;
+ }
+
+ this.updateSketchFeatures_();
+};
+
+
+/**
+ * Stop drawing and add the sketch feature to the target layer.
+ * The {@link ol.interaction.DrawEventType.DRAWEND} event is dispatched before
+ * inserting the feature.
+ * @api
+ */
+ol.interaction.Draw.prototype.finishDrawing = function() {
+ var sketchFeature = this.abortDrawing_();
+ goog.asserts.assert(sketchFeature, 'sketchFeature expected to be truthy');
+ var coordinates = this.sketchCoords_;
+ var geometry = sketchFeature.getGeometry();
+ goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
+ 'geometry must be an ol.geom.SimpleGeometry');
+ if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
+ // remove the redundant last point
+ coordinates.pop();
+ this.geometryFunction_(coordinates, geometry);
+ } else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
+ // When we finish drawing a polygon on the last point,
+ // the last coordinate is duplicated as for LineString
+ // we force the replacement by the first point
+ coordinates[0].pop();
+ coordinates[0].push(coordinates[0][0]);
+ this.geometryFunction_(coordinates, geometry);
+ }
+
+ // cast multi-part geometries
+ if (this.type_ === ol.geom.GeometryType.MULTI_POINT) {
+ sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates]));
+ } else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) {
+ sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates]));
+ } else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) {
+ sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates]));
+ }
+
+ // First dispatch event to allow full set up of feature
+ this.dispatchEvent(new ol.interaction.DrawEvent(
+ ol.interaction.DrawEventType.DRAWEND, sketchFeature));
+
+ // Then insert feature
+ if (this.features_) {
+ this.features_.push(sketchFeature);
+ }
+ if (this.source_) {
+ this.source_.addFeature(sketchFeature);
+ }
+};
+
+
+/**
+ * Stop drawing without adding the sketch feature to the target layer.
+ * @return {ol.Feature} The sketch feature (or null if none).
+ * @private
+ */
+ol.interaction.Draw.prototype.abortDrawing_ = function() {
+ this.finishCoordinate_ = null;
+ var sketchFeature = this.sketchFeature_;
+ if (sketchFeature) {
+ this.sketchFeature_ = null;
+ this.sketchPoint_ = null;
+ this.sketchLine_ = null;
+ this.overlay_.getSource().clear(true);
+ }
+ return sketchFeature;
+};
+
+
+/**
+ * Extend an existing geometry by adding additional points. This only works
+ * on features with `LineString` geometries, where the interaction will
+ * extend lines by adding points to the end of the coordinates array.
+ * @param {!ol.Feature} feature Feature to be extended.
+ * @api
+ */
+ol.interaction.Draw.prototype.extend = function(feature) {
+ var geometry = feature.getGeometry();
+ goog.asserts.assert(this.mode_ == ol.interaction.DrawMode.LINE_STRING,
+ 'interaction mode must be "line"');
+ goog.asserts.assert(geometry, 'feature must have a geometry');
+ goog.asserts.assert(geometry.getType() == ol.geom.GeometryType.LINE_STRING,
+ 'feature geometry must be a line string');
+ var lineString = /** @type {ol.geom.LineString} */ (geometry);
+ this.sketchFeature_ = feature;
+ this.sketchCoords_ = lineString.getCoordinates();
+ var last = this.sketchCoords_[this.sketchCoords_.length - 1];
+ this.finishCoordinate_ = last.slice();
+ this.sketchCoords_.push(last.slice());
+ this.updateSketchFeatures_();
+ this.dispatchEvent(new ol.interaction.DrawEvent(
+ ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_));
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.Draw.prototype.shouldStopEvent = ol.functions.FALSE;
+
+
+/**
+ * Redraw the sketch features.
+ * @private
+ */
+ol.interaction.Draw.prototype.updateSketchFeatures_ = function() {
+ var sketchFeatures = [];
+ if (this.sketchFeature_) {
+ sketchFeatures.push(this.sketchFeature_);
+ }
+ if (this.sketchLine_) {
+ sketchFeatures.push(this.sketchLine_);
+ }
+ if (this.sketchPoint_) {
+ sketchFeatures.push(this.sketchPoint_);
+ }
+ var overlaySource = this.overlay_.getSource();
+ overlaySource.clear(true);
+ overlaySource.addFeatures(sketchFeatures);
+};
+
+
+/**
+ * @private
+ */
+ol.interaction.Draw.prototype.updateState_ = function() {
+ var map = this.getMap();
+ var active = this.getActive();
+ if (!map || !active) {
+ this.abortDrawing_();
+ }
+ this.overlay_.setMap(active ? map : null);
+};
+
+
+/**
+ * Create a `geometryFunction` for `mode: 'Circle'` that will create a regular
+ * polygon with a user specified number of sides and start angle instead of an
+ * `ol.geom.Circle` geometry.
+ * @param {number=} opt_sides Number of sides of the regular polygon. Default is
+ * 32.
+ * @param {number=} opt_angle Angle of the first point in radians. 0 means East.
+ * Default is the angle defined by the heading from the center of the
+ * regular polygon to the current pointer position.
+ * @return {ol.DrawGeometryFunctionType} Function that draws a
+ * polygon.
+ * @api
+ */
+ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) {
+ return (
+ /**
+ * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
+ * @param {ol.geom.SimpleGeometry=} opt_geometry
+ * @return {ol.geom.SimpleGeometry}
+ */
+ function(coordinates, opt_geometry) {
+ var center = coordinates[0];
+ var end = coordinates[1];
+ var radius = Math.sqrt(
+ ol.coordinate.squaredDistance(center, end));
+ var geometry = opt_geometry ? opt_geometry :
+ ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides);
+ goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
+ 'geometry must be a polygon');
+ var angle = opt_angle ? opt_angle :
+ Math.atan((end[1] - center[1]) / (end[0] - center[0]));
+ ol.geom.Polygon.makeRegular(geometry, center, radius, angle);
+ return geometry;
+ }
+ );
+};
+
+
+/**
+ * Get the drawing mode. The mode for mult-part geometries is the same as for
+ * their single-part cousins.
+ * @param {ol.geom.GeometryType} type Geometry type.
+ * @return {ol.interaction.DrawMode} Drawing mode.
+ * @private
+ */
+ol.interaction.Draw.getMode_ = function(type) {
+ var mode;
+ if (type === ol.geom.GeometryType.POINT ||
+ type === ol.geom.GeometryType.MULTI_POINT) {
+ mode = ol.interaction.DrawMode.POINT;
+ } else if (type === ol.geom.GeometryType.LINE_STRING ||
+ type === ol.geom.GeometryType.MULTI_LINE_STRING) {
+ mode = ol.interaction.DrawMode.LINE_STRING;
+ } else if (type === ol.geom.GeometryType.POLYGON ||
+ type === ol.geom.GeometryType.MULTI_POLYGON) {
+ mode = ol.interaction.DrawMode.POLYGON;
+ } else if (type === ol.geom.GeometryType.CIRCLE) {
+ mode = ol.interaction.DrawMode.CIRCLE;
+ }
+ goog.asserts.assert(mode !== undefined, 'mode should be defined');
+ return mode;
+};
+
+
+/**
+ * Draw mode. This collapses multi-part geometry types with their single-part
+ * cousins.
+ * @enum {string}
+ */
+ol.interaction.DrawMode = {
+ POINT: 'Point',
+ LINE_STRING: 'LineString',
+ POLYGON: 'Polygon',
+ CIRCLE: 'Circle'
+};
+
+goog.provide('ol.interaction.Modify');
+goog.provide('ol.interaction.ModifyEvent');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('ol');
+goog.require('ol.Collection');
+goog.require('ol.CollectionEventType');
+goog.require('ol.Feature');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.MapBrowserPointerEvent');
+goog.require('ol.ViewHint');
+goog.require('ol.array');
+goog.require('ol.coordinate');
+goog.require('ol.events.condition');
+goog.require('ol.extent');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.interaction.Pointer');
+goog.require('ol.layer.Vector');
+goog.require('ol.source.Vector');
+goog.require('ol.structs.RBush');
+
+
+/**
+ * @enum {string}
+ */
+ol.ModifyEventType = {
+ /**
+ * Triggered upon feature modification start
+ * @event ol.interaction.ModifyEvent#modifystart
+ * @api
+ */
+ MODIFYSTART: 'modifystart',
+ /**
+ * Triggered upon feature modification end
+ * @event ol.interaction.ModifyEvent#modifyend
+ * @api
+ */
+ MODIFYEND: 'modifyend'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.interaction.Modify} instances are instances of
+ * this type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.ModifyEvent}
+ * @param {ol.ModifyEventType} type Type.
+ * @param {ol.Collection.<ol.Feature>} features The features modified.
+ * @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated
+ * {@link ol.MapBrowserPointerEvent}.
+ */
+ol.interaction.ModifyEvent = function(type, features, mapBrowserPointerEvent) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The features being modified.
+ * @type {ol.Collection.<ol.Feature>}
+ * @api
+ */
+ this.features = features;
+
+ /**
+ * Associated {@link ol.MapBrowserEvent}.
+ * @type {ol.MapBrowserEvent}
+ * @api
+ */
+ this.mapBrowserEvent = mapBrowserPointerEvent;
+};
+ol.inherits(ol.interaction.ModifyEvent, ol.events.Event);
+
+
+/**
+ * @classdesc
+ * Interaction for modifying feature geometries.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.ModifyOptions} options Options.
+ * @fires ol.interaction.ModifyEvent
+ * @api
+ */
+ol.interaction.Modify = function(options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.Modify.handleDownEvent_,
+ handleDragEvent: ol.interaction.Modify.handleDragEvent_,
+ handleEvent: ol.interaction.Modify.handleEvent,
+ handleUpEvent: ol.interaction.Modify.handleUpEvent_
+ });
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.primaryAction;
+
+
+ /**
+ * @private
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
+ * @return {boolean} Combined condition result.
+ */
+ this.defaultDeleteCondition_ = function(mapBrowserEvent) {
+ return ol.events.condition.noModifierKeys(mapBrowserEvent) &&
+ ol.events.condition.singleClick(mapBrowserEvent);
+ };
+
+ /**
+ * @type {ol.EventsConditionType}
+ * @private
+ */
+ this.deleteCondition_ = options.deleteCondition ?
+ options.deleteCondition : this.defaultDeleteCondition_;
+
+ /**
+ * Editing vertex.
+ * @type {ol.Feature}
+ * @private
+ */
+ this.vertexFeature_ = null;
+
+ /**
+ * Segments intersecting {@link this.vertexFeature_} by segment uid.
+ * @type {Object.<string, boolean>}
+ * @private
+ */
+ this.vertexSegments_ = null;
+
+ /**
+ * @type {ol.Pixel}
+ * @private
+ */
+ this.lastPixel_ = [0, 0];
+
+ /**
+ * Tracks if the next `singleclick` event should be ignored to prevent
+ * accidental deletion right after vertex creation.
+ * @type {boolean}
+ * @private
+ */
+ this.ignoreNextSingleClick_ = false;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.modified_ = false;
+
+ /**
+ * Segment RTree for each layer
+ * @type {ol.structs.RBush.<ol.ModifySegmentDataType>}
+ * @private
+ */
+ this.rBush_ = new ol.structs.RBush();
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.pixelTolerance_ = options.pixelTolerance !== undefined ?
+ options.pixelTolerance : 10;
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.snappedToVertex_ = false;
+
+ /**
+ * Indicate whether the interaction is currently changing a feature's
+ * coordinates.
+ * @type {boolean}
+ * @private
+ */
+ this.changingFeature_ = false;
+
+ /**
+ * @type {Array}
+ * @private
+ */
+ this.dragSegments_ = [];
+
+ /**
+ * Draw overlay where sketch features are drawn.
+ * @type {ol.layer.Vector}
+ * @private
+ */
+ this.overlay_ = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ useSpatialIndex: false,
+ wrapX: !!options.wrapX
+ }),
+ style: options.style ? options.style :
+ ol.interaction.Modify.getDefaultStyleFunction(),
+ updateWhileAnimating: true,
+ updateWhileInteracting: true
+ });
+
+ /**
+ * @const
+ * @private
+ * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>}
+ */
+ this.SEGMENT_WRITERS_ = {
+ 'Point': this.writePointGeometry_,
+ 'LineString': this.writeLineStringGeometry_,
+ 'LinearRing': this.writeLineStringGeometry_,
+ 'Polygon': this.writePolygonGeometry_,
+ 'MultiPoint': this.writeMultiPointGeometry_,
+ 'MultiLineString': this.writeMultiLineStringGeometry_,
+ 'MultiPolygon': this.writeMultiPolygonGeometry_,
+ 'GeometryCollection': this.writeGeometryCollectionGeometry_
+ };
+
+ /**
+ * @type {ol.Collection.<ol.Feature>}
+ * @private
+ */
+ this.features_ = options.features;
+
+ this.features_.forEach(this.addFeature_, this);
+ ol.events.listen(this.features_, ol.CollectionEventType.ADD,
+ this.handleFeatureAdd_, this);
+ ol.events.listen(this.features_, ol.CollectionEventType.REMOVE,
+ this.handleFeatureRemove_, this);
+
+ /**
+ * @type {ol.MapBrowserPointerEvent}
+ * @private
+ */
+ this.lastPointerEvent_ = null;
+
+};
+ol.inherits(ol.interaction.Modify, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.interaction.Modify.prototype.addFeature_ = function(feature) {
+ var geometry = feature.getGeometry();
+ if (geometry.getType() in this.SEGMENT_WRITERS_) {
+ this.SEGMENT_WRITERS_[geometry.getType()].call(this, feature, geometry);
+ }
+ var map = this.getMap();
+ if (map) {
+ this.handlePointerAtPixel_(this.lastPixel_, map);
+ }
+ ol.events.listen(feature, ol.events.EventType.CHANGE,
+ this.handleFeatureChange_, this);
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} evt Map browser event
+ * @private
+ */
+ol.interaction.Modify.prototype.willModifyFeatures_ = function(evt) {
+ if (!this.modified_) {
+ this.modified_ = true;
+ this.dispatchEvent(new ol.interaction.ModifyEvent(
+ ol.ModifyEventType.MODIFYSTART, this.features_, evt));
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.interaction.Modify.prototype.removeFeature_ = function(feature) {
+ this.removeFeatureSegmentData_(feature);
+ // Remove the vertex feature if the collection of canditate features
+ // is empty.
+ if (this.vertexFeature_ && this.features_.getLength() === 0) {
+ this.overlay_.getSource().removeFeature(this.vertexFeature_);
+ this.vertexFeature_ = null;
+ }
+ ol.events.unlisten(feature, ol.events.EventType.CHANGE,
+ this.handleFeatureChange_, this);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) {
+ var rBush = this.rBush_;
+ var /** @type {Array.<ol.ModifySegmentDataType>} */ nodesToRemove = [];
+ rBush.forEach(
+ /**
+ * @param {ol.ModifySegmentDataType} node RTree node.
+ */
+ function(node) {
+ if (feature === node.feature) {
+ nodesToRemove.push(node);
+ }
+ });
+ for (var i = nodesToRemove.length - 1; i >= 0; --i) {
+ rBush.remove(nodesToRemove[i]);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.Modify.prototype.setMap = function(map) {
+ this.overlay_.setMap(map);
+ ol.interaction.Pointer.prototype.setMap.call(this, map);
+};
+
+
+/**
+ * @param {ol.CollectionEvent} evt Event.
+ * @private
+ */
+ol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) {
+ var feature = evt.element;
+ goog.asserts.assertInstanceof(feature, ol.Feature,
+ 'feature should be an ol.Feature');
+ this.addFeature_(feature);
+};
+
+
+/**
+ * @param {ol.events.Event} evt Event.
+ * @private
+ */
+ol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) {
+ if (!this.changingFeature_) {
+ var feature = /** @type {ol.Feature} */ (evt.target);
+ this.removeFeature_(feature);
+ this.addFeature_(feature);
+ }
+};
+
+
+/**
+ * @param {ol.CollectionEvent} evt Event.
+ * @private
+ */
+ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) {
+ var feature = /** @type {ol.Feature} */ (evt.element);
+ this.removeFeature_(feature);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.Point} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writePointGeometry_ = function(feature, geometry) {
+ var coordinates = geometry.getCoordinates();
+ var segmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ feature: feature,
+ geometry: geometry,
+ segment: [coordinates, coordinates]
+ });
+ this.rBush_.insert(geometry.getExtent(), segmentData);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.MultiPoint} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writeMultiPointGeometry_ = function(feature, geometry) {
+ var points = geometry.getCoordinates();
+ var coordinates, i, ii, segmentData;
+ for (i = 0, ii = points.length; i < ii; ++i) {
+ coordinates = points[i];
+ segmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ feature: feature,
+ geometry: geometry,
+ depth: [i],
+ index: i,
+ segment: [coordinates, coordinates]
+ });
+ this.rBush_.insert(geometry.getExtent(), segmentData);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.LineString} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writeLineStringGeometry_ = function(feature, geometry) {
+ var coordinates = geometry.getCoordinates();
+ var i, ii, segment, segmentData;
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ feature: feature,
+ geometry: geometry,
+ index: i,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.MultiLineString} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writeMultiLineStringGeometry_ = function(feature, geometry) {
+ var lines = geometry.getCoordinates();
+ var coordinates, i, ii, j, jj, segment, segmentData;
+ for (j = 0, jj = lines.length; j < jj; ++j) {
+ coordinates = lines[j];
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ feature: feature,
+ geometry: geometry,
+ depth: [j],
+ index: i,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.Polygon} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writePolygonGeometry_ = function(feature, geometry) {
+ var rings = geometry.getCoordinates();
+ var coordinates, i, ii, j, jj, segment, segmentData;
+ for (j = 0, jj = rings.length; j < jj; ++j) {
+ coordinates = rings[j];
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ feature: feature,
+ geometry: geometry,
+ depth: [j],
+ index: i,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.MultiPolygon} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writeMultiPolygonGeometry_ = function(feature, geometry) {
+ var polygons = geometry.getCoordinates();
+ var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData;
+ for (k = 0, kk = polygons.length; k < kk; ++k) {
+ rings = polygons[k];
+ for (j = 0, jj = rings.length; j < jj; ++j) {
+ coordinates = rings[j];
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ feature: feature,
+ geometry: geometry,
+ depth: [j, k],
+ index: i,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+ }
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.GeometryCollection} geometry Geometry.
+ * @private
+ */
+ol.interaction.Modify.prototype.writeGeometryCollectionGeometry_ = function(feature, geometry) {
+ var i, geometries = geometry.getGeometriesArray();
+ for (i = 0; i < geometries.length; ++i) {
+ this.SEGMENT_WRITERS_[geometries[i].getType()].call(
+ this, feature, geometries[i]);
+ }
+};
+
+
+/**
+ * @param {ol.Coordinate} coordinates Coordinates.
+ * @return {ol.Feature} Vertex feature.
+ * @private
+ */
+ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = function(coordinates) {
+ var vertexFeature = this.vertexFeature_;
+ if (!vertexFeature) {
+ vertexFeature = new ol.Feature(new ol.geom.Point(coordinates));
+ this.vertexFeature_ = vertexFeature;
+ this.overlay_.getSource().addFeature(vertexFeature);
+ } else {
+ var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());
+ geometry.setCoordinates(coordinates);
+ }
+ return vertexFeature;
+};
+
+
+/**
+ * @param {ol.ModifySegmentDataType} a The first segment data.
+ * @param {ol.ModifySegmentDataType} b The second segment data.
+ * @return {number} The difference in indexes.
+ * @private
+ */
+ol.interaction.Modify.compareIndexes_ = function(a, b) {
+ return a.index - b.index;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} evt Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.Modify}
+ * @private
+ */
+ol.interaction.Modify.handleDownEvent_ = function(evt) {
+ if (!this.condition_(evt)) {
+ return false;
+ }
+ this.handlePointerAtPixel_(evt.pixel, evt.map);
+ this.dragSegments_.length = 0;
+ this.modified_ = false;
+ var vertexFeature = this.vertexFeature_;
+ if (vertexFeature) {
+ var insertVertices = [];
+ var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());
+ var vertex = geometry.getCoordinates();
+ var vertexExtent = ol.extent.boundingExtent([vertex]);
+ var segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
+ var componentSegments = {};
+ segmentDataMatches.sort(ol.interaction.Modify.compareIndexes_);
+ for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
+ var segmentDataMatch = segmentDataMatches[i];
+ var segment = segmentDataMatch.segment;
+ var uid = goog.getUid(segmentDataMatch.feature);
+ var depth = segmentDataMatch.depth;
+ if (depth) {
+ uid += '-' + depth.join('-'); // separate feature components
+ }
+ if (!componentSegments[uid]) {
+ componentSegments[uid] = new Array(2);
+ }
+ if (ol.coordinate.equals(segment[0], vertex) &&
+ !componentSegments[uid][0]) {
+ this.dragSegments_.push([segmentDataMatch, 0]);
+ componentSegments[uid][0] = segmentDataMatch;
+ } else if (ol.coordinate.equals(segment[1], vertex) &&
+ !componentSegments[uid][1]) {
+
+ // prevent dragging closed linestrings by the connecting node
+ if ((segmentDataMatch.geometry.getType() ===
+ ol.geom.GeometryType.LINE_STRING ||
+ segmentDataMatch.geometry.getType() ===
+ ol.geom.GeometryType.MULTI_LINE_STRING) &&
+ componentSegments[uid][0] &&
+ componentSegments[uid][0].index === 0) {
+ continue;
+ }
+
+ this.dragSegments_.push([segmentDataMatch, 1]);
+ componentSegments[uid][1] = segmentDataMatch;
+ } else if (goog.getUid(segment) in this.vertexSegments_ &&
+ (!componentSegments[uid][0] && !componentSegments[uid][1])) {
+ insertVertices.push([segmentDataMatch, vertex]);
+ }
+ }
+ if (insertVertices.length) {
+ this.willModifyFeatures_(evt);
+ }
+ for (var j = insertVertices.length - 1; j >= 0; --j) {
+ this.insertVertex_.apply(this, insertVertices[j]);
+ }
+ }
+ return !!this.vertexFeature_;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} evt Event.
+ * @this {ol.interaction.Modify}
+ * @private
+ */
+ol.interaction.Modify.handleDragEvent_ = function(evt) {
+ this.ignoreNextSingleClick_ = false;
+ this.willModifyFeatures_(evt);
+
+ var vertex = evt.coordinate;
+ for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
+ var dragSegment = this.dragSegments_[i];
+ var segmentData = dragSegment[0];
+ var depth = segmentData.depth;
+ var geometry = segmentData.geometry;
+ var coordinates = geometry.getCoordinates();
+ var segment = segmentData.segment;
+ var index = dragSegment[1];
+
+ while (vertex.length < geometry.getStride()) {
+ vertex.push(0);
+ }
+
+ switch (geometry.getType()) {
+ case ol.geom.GeometryType.POINT:
+ coordinates = vertex;
+ segment[0] = segment[1] = vertex;
+ break;
+ case ol.geom.GeometryType.MULTI_POINT:
+ coordinates[segmentData.index] = vertex;
+ segment[0] = segment[1] = vertex;
+ break;
+ case ol.geom.GeometryType.LINE_STRING:
+ coordinates[segmentData.index + index] = vertex;
+ segment[index] = vertex;
+ break;
+ case ol.geom.GeometryType.MULTI_LINE_STRING:
+ coordinates[depth[0]][segmentData.index + index] = vertex;
+ segment[index] = vertex;
+ break;
+ case ol.geom.GeometryType.POLYGON:
+ coordinates[depth[0]][segmentData.index + index] = vertex;
+ segment[index] = vertex;
+ break;
+ case ol.geom.GeometryType.MULTI_POLYGON:
+ coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
+ segment[index] = vertex;
+ break;
+ default:
+ // pass
+ }
+
+ this.setGeometryCoordinates_(geometry, coordinates);
+ }
+ this.createOrUpdateVertexFeature_(vertex);
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} evt Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.Modify}
+ * @private
+ */
+ol.interaction.Modify.handleUpEvent_ = function(evt) {
+ var segmentData;
+ for (var i = this.dragSegments_.length - 1; i >= 0; --i) {
+ segmentData = this.dragSegments_[i][0];
+ this.rBush_.update(ol.extent.boundingExtent(segmentData.segment),
+ segmentData);
+ }
+ if (this.modified_) {
+ this.dispatchEvent(new ol.interaction.ModifyEvent(
+ ol.ModifyEventType.MODIFYEND, this.features_, evt));
+ this.modified_ = false;
+ }
+ return false;
+};
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} and may modify the
+ * geometry.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.Modify}
+ * @api
+ */
+ol.interaction.Modify.handleEvent = function(mapBrowserEvent) {
+ if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
+ return true;
+ }
+ this.lastPointerEvent_ = mapBrowserEvent;
+
+ var handled;
+ if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] &&
+ mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE &&
+ !this.handlingDownUpSequence) {
+ this.handlePointerMove_(mapBrowserEvent);
+ }
+ if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) {
+ if (mapBrowserEvent.type != ol.MapBrowserEvent.EventType.SINGLECLICK ||
+ !this.ignoreNextSingleClick_) {
+ var geometry = this.vertexFeature_.getGeometry();
+ goog.asserts.assertInstanceof(geometry, ol.geom.Point,
+ 'geometry should be an ol.geom.Point');
+ handled = this.removePoint();
+ } else {
+ handled = true;
+ }
+ }
+
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.SINGLECLICK) {
+ this.ignoreNextSingleClick_ = false;
+ }
+
+ return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) &&
+ !handled;
+};
+
+
+/**
+ * @param {ol.MapBrowserEvent} evt Event.
+ * @private
+ */
+ol.interaction.Modify.prototype.handlePointerMove_ = function(evt) {
+ this.lastPixel_ = evt.pixel;
+ this.handlePointerAtPixel_(evt.pixel, evt.map);
+};
+
+
+/**
+ * @param {ol.Pixel} pixel Pixel
+ * @param {ol.Map} map Map.
+ * @private
+ */
+ol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) {
+ var pixelCoordinate = map.getCoordinateFromPixel(pixel);
+ var sortByDistance = function(a, b) {
+ return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a.segment) -
+ ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b.segment);
+ };
+
+ var lowerLeft = map.getCoordinateFromPixel(
+ [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
+ var upperRight = map.getCoordinateFromPixel(
+ [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
+ var box = ol.extent.boundingExtent([lowerLeft, upperRight]);
+
+ var rBush = this.rBush_;
+ var nodes = rBush.getInExtent(box);
+ if (nodes.length > 0) {
+ nodes.sort(sortByDistance);
+ var node = nodes[0];
+ var closestSegment = node.segment;
+ var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,
+ closestSegment));
+ var vertexPixel = map.getPixelFromCoordinate(vertex);
+ if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <=
+ this.pixelTolerance_) {
+ var pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
+ var pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
+ var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
+ var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
+ var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
+ this.snappedToVertex_ = dist <= this.pixelTolerance_;
+ if (this.snappedToVertex_) {
+ vertex = squaredDist1 > squaredDist2 ?
+ closestSegment[1] : closestSegment[0];
+ }
+ this.createOrUpdateVertexFeature_(vertex);
+ var vertexSegments = {};
+ vertexSegments[goog.getUid(closestSegment)] = true;
+ var segment;
+ for (var i = 1, ii = nodes.length; i < ii; ++i) {
+ segment = nodes[i].segment;
+ if ((ol.coordinate.equals(closestSegment[0], segment[0]) &&
+ ol.coordinate.equals(closestSegment[1], segment[1]) ||
+ (ol.coordinate.equals(closestSegment[0], segment[1]) &&
+ ol.coordinate.equals(closestSegment[1], segment[0])))) {
+ vertexSegments[goog.getUid(segment)] = true;
+ } else {
+ break;
+ }
+ }
+ this.vertexSegments_ = vertexSegments;
+ return;
+ }
+ }
+ if (this.vertexFeature_) {
+ this.overlay_.getSource().removeFeature(this.vertexFeature_);
+ this.vertexFeature_ = null;
+ }
+};
+
+
+/**
+ * @param {ol.ModifySegmentDataType} segmentData Segment data.
+ * @param {ol.Coordinate} vertex Vertex.
+ * @private
+ */
+ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) {
+ var segment = segmentData.segment;
+ var feature = segmentData.feature;
+ var geometry = segmentData.geometry;
+ var depth = segmentData.depth;
+ var index = segmentData.index;
+ var coordinates;
+
+ while (vertex.length < geometry.getStride()) {
+ vertex.push(0);
+ }
+
+ switch (geometry.getType()) {
+ case ol.geom.GeometryType.MULTI_LINE_STRING:
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString,
+ 'geometry should be an ol.geom.MultiLineString');
+ coordinates = geometry.getCoordinates();
+ coordinates[depth[0]].splice(index + 1, 0, vertex);
+ break;
+ case ol.geom.GeometryType.POLYGON:
+ goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
+ 'geometry should be an ol.geom.Polygon');
+ coordinates = geometry.getCoordinates();
+ coordinates[depth[0]].splice(index + 1, 0, vertex);
+ break;
+ case ol.geom.GeometryType.MULTI_POLYGON:
+ goog.asserts.assertInstanceof(geometry, ol.geom.MultiPolygon,
+ 'geometry should be an ol.geom.MultiPolygon');
+ coordinates = geometry.getCoordinates();
+ coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex);
+ break;
+ case ol.geom.GeometryType.LINE_STRING:
+ goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
+ 'geometry should be an ol.geom.LineString');
+ coordinates = geometry.getCoordinates();
+ coordinates.splice(index + 1, 0, vertex);
+ break;
+ default:
+ return;
+ }
+
+ this.setGeometryCoordinates_(geometry, coordinates);
+ var rTree = this.rBush_;
+ goog.asserts.assert(segment !== undefined, 'segment should be defined');
+ rTree.remove(segmentData);
+ goog.asserts.assert(index !== undefined, 'index should be defined');
+ this.updateSegmentIndices_(geometry, index, depth, 1);
+ var newSegmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ segment: [segment[0], vertex],
+ feature: feature,
+ geometry: geometry,
+ depth: depth,
+ index: index
+ });
+ rTree.insert(ol.extent.boundingExtent(newSegmentData.segment),
+ newSegmentData);
+ this.dragSegments_.push([newSegmentData, 1]);
+
+ var newSegmentData2 = /** @type {ol.ModifySegmentDataType} */ ({
+ segment: [vertex, segment[1]],
+ feature: feature,
+ geometry: geometry,
+ depth: depth,
+ index: index + 1
+ });
+ rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment),
+ newSegmentData2);
+ this.dragSegments_.push([newSegmentData2, 0]);
+ this.ignoreNextSingleClick_ = true;
+};
+
+/**
+ * Removes the vertex currently being pointed.
+ * @return {boolean} True when a vertex was removed.
+ * @api
+ */
+ol.interaction.Modify.prototype.removePoint = function() {
+ var handled = false;
+ if (this.lastPointerEvent_ && this.lastPointerEvent_.type != ol.MapBrowserEvent.EventType.POINTERDRAG) {
+ var evt = this.lastPointerEvent_;
+ this.willModifyFeatures_(evt);
+ handled = this.removeVertex_();
+ this.dispatchEvent(new ol.interaction.ModifyEvent(
+ ol.ModifyEventType.MODIFYEND, this.features_, evt));
+ this.modified_ = false;
+ }
+ return handled;
+};
+
+/**
+ * Removes a vertex from all matching features.
+ * @return {boolean} True when a vertex was removed.
+ * @private
+ */
+ol.interaction.Modify.prototype.removeVertex_ = function() {
+ var dragSegments = this.dragSegments_;
+ var segmentsByFeature = {};
+ var component, coordinates, dragSegment, geometry, i, index, left;
+ var newIndex, right, segmentData, uid, deleted;
+ for (i = dragSegments.length - 1; i >= 0; --i) {
+ dragSegment = dragSegments[i];
+ segmentData = dragSegment[0];
+ uid = goog.getUid(segmentData.feature);
+ if (segmentData.depth) {
+ // separate feature components
+ uid += '-' + segmentData.depth.join('-');
+ }
+ if (!(uid in segmentsByFeature)) {
+ segmentsByFeature[uid] = {};
+ }
+ if (dragSegment[1] === 0) {
+ segmentsByFeature[uid].right = segmentData;
+ segmentsByFeature[uid].index = segmentData.index;
+ } else if (dragSegment[1] == 1) {
+ segmentsByFeature[uid].left = segmentData;
+ segmentsByFeature[uid].index = segmentData.index + 1;
+ }
+
+ }
+ for (uid in segmentsByFeature) {
+ right = segmentsByFeature[uid].right;
+ left = segmentsByFeature[uid].left;
+ index = segmentsByFeature[uid].index;
+ newIndex = index - 1;
+ if (left !== undefined) {
+ segmentData = left;
+ } else {
+ segmentData = right;
+ }
+ if (newIndex < 0) {
+ newIndex = 0;
+ }
+ geometry = segmentData.geometry;
+ coordinates = geometry.getCoordinates();
+ component = coordinates;
+ deleted = false;
+ switch (geometry.getType()) {
+ case ol.geom.GeometryType.MULTI_LINE_STRING:
+ if (coordinates[segmentData.depth[0]].length > 2) {
+ coordinates[segmentData.depth[0]].splice(index, 1);
+ deleted = true;
+ }
+ break;
+ case ol.geom.GeometryType.LINE_STRING:
+ if (coordinates.length > 2) {
+ coordinates.splice(index, 1);
+ deleted = true;
+ }
+ break;
+ case ol.geom.GeometryType.MULTI_POLYGON:
+ component = component[segmentData.depth[1]];
+ /* falls through */
+ case ol.geom.GeometryType.POLYGON:
+ component = component[segmentData.depth[0]];
+ if (component.length > 4) {
+ if (index == component.length - 1) {
+ index = 0;
+ }
+ component.splice(index, 1);
+ deleted = true;
+ if (index === 0) {
+ // close the ring again
+ component.pop();
+ component.push(component[0]);
+ newIndex = component.length - 1;
+ }
+ }
+ break;
+ default:
+ // pass
+ }
+
+ if (deleted) {
+ this.setGeometryCoordinates_(geometry, coordinates);
+ var segments = [];
+ if (left !== undefined) {
+ this.rBush_.remove(left);
+ segments.push(left.segment[0]);
+ }
+ if (right !== undefined) {
+ this.rBush_.remove(right);
+ segments.push(right.segment[1]);
+ }
+ if (left !== undefined && right !== undefined) {
+ goog.asserts.assert(newIndex >= 0, 'newIndex should be larger than 0');
+
+ var newSegmentData = /** @type {ol.ModifySegmentDataType} */ ({
+ depth: segmentData.depth,
+ feature: segmentData.feature,
+ geometry: segmentData.geometry,
+ index: newIndex,
+ segment: segments
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment),
+ newSegmentData);
+ }
+ this.updateSegmentIndices_(geometry, index, segmentData.depth, -1);
+ if (this.vertexFeature_) {
+ this.overlay_.getSource().removeFeature(this.vertexFeature_);
+ this.vertexFeature_ = null;
+ }
+ }
+
+ }
+ return true;
+};
+
+
+/**
+ * @param {ol.geom.SimpleGeometry} geometry Geometry.
+ * @param {Array} coordinates Coordinates.
+ * @private
+ */
+ol.interaction.Modify.prototype.setGeometryCoordinates_ = function(geometry, coordinates) {
+ this.changingFeature_ = true;
+ geometry.setCoordinates(coordinates);
+ this.changingFeature_ = false;
+};
+
+
+/**
+ * @param {ol.geom.SimpleGeometry} geometry Geometry.
+ * @param {number} index Index.
+ * @param {Array.<number>|undefined} depth Depth.
+ * @param {number} delta Delta (1 or -1).
+ * @private
+ */
+ol.interaction.Modify.prototype.updateSegmentIndices_ = function(
+ geometry, index, depth, delta) {
+ this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) {
+ if (segmentDataMatch.geometry === geometry &&
+ (depth === undefined || segmentDataMatch.depth === undefined ||
+ ol.array.equals(segmentDataMatch.depth, depth)) &&
+ segmentDataMatch.index > index) {
+ segmentDataMatch.index += delta;
+ }
+ });
+};
+
+
+/**
+ * @return {ol.StyleFunction} Styles.
+ */
+ol.interaction.Modify.getDefaultStyleFunction = function() {
+ var style = ol.style.createDefaultEditingStyles();
+ return function(feature, resolution) {
+ return style[ol.geom.GeometryType.POINT];
+ };
+};
+
+goog.provide('ol.interaction.Select');
+goog.provide('ol.interaction.SelectEvent');
+goog.provide('ol.interaction.SelectEventType');
+
+goog.require('goog.asserts');
+goog.require('ol.functions');
+goog.require('ol.CollectionEventType');
+goog.require('ol.Feature');
+goog.require('ol.array');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.condition');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.layer.Vector');
+goog.require('ol.object');
+goog.require('ol.source.Vector');
+
+
+/**
+ * @enum {string}
+ */
+ol.interaction.SelectEventType = {
+ /**
+ * Triggered when feature(s) has been (de)selected.
+ * @event ol.interaction.SelectEvent#select
+ * @api
+ */
+ SELECT: 'select'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.interaction.Select} instances are instances of
+ * this type.
+ *
+ * @param {string} type The event type.
+ * @param {Array.<ol.Feature>} selected Selected features.
+ * @param {Array.<ol.Feature>} deselected Deselected features.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Associated
+ * {@link ol.MapBrowserEvent}.
+ * @implements {oli.SelectEvent}
+ * @extends {ol.events.Event}
+ * @constructor
+ */
+ol.interaction.SelectEvent = function(type, selected, deselected, mapBrowserEvent) {
+ ol.events.Event.call(this, type);
+
+ /**
+ * Selected features array.
+ * @type {Array.<ol.Feature>}
+ * @api
+ */
+ this.selected = selected;
+
+ /**
+ * Deselected features array.
+ * @type {Array.<ol.Feature>}
+ * @api
+ */
+ this.deselected = deselected;
+
+ /**
+ * Associated {@link ol.MapBrowserEvent}.
+ * @type {ol.MapBrowserEvent}
+ * @api
+ */
+ this.mapBrowserEvent = mapBrowserEvent;
+};
+ol.inherits(ol.interaction.SelectEvent, ol.events.Event);
+
+
+/**
+ * @classdesc
+ * Interaction for selecting vector features. By default, selected features are
+ * styled differently, so this interaction can be used for visual highlighting,
+ * as well as selecting features for other actions, such as modification or
+ * output. There are three ways of controlling which features are selected:
+ * using the browser event as defined by the `condition` and optionally the
+ * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a
+ * further feature filter using the `filter` option.
+ *
+ * Selected features are added to an internal unmanaged layer.
+ *
+ * @constructor
+ * @extends {ol.interaction.Interaction}
+ * @param {olx.interaction.SelectOptions=} opt_options Options.
+ * @fires ol.interaction.SelectEvent
+ * @api stable
+ */
+ol.interaction.Select = function(opt_options) {
+
+ ol.interaction.Interaction.call(this, {
+ handleEvent: ol.interaction.Select.handleEvent
+ });
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.condition_ = options.condition ?
+ options.condition : ol.events.condition.singleClick;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.addCondition_ = options.addCondition ?
+ options.addCondition : ol.events.condition.never;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.removeCondition_ = options.removeCondition ?
+ options.removeCondition : ol.events.condition.never;
+
+ /**
+ * @private
+ * @type {ol.EventsConditionType}
+ */
+ this.toggleCondition_ = options.toggleCondition ?
+ options.toggleCondition : ol.events.condition.shiftKeyOnly;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.multi_ = options.multi ? options.multi : false;
+
+ /**
+ * @private
+ * @type {ol.SelectFilterFunction}
+ */
+ this.filter_ = options.filter ? options.filter :
+ ol.functions.TRUE;
+
+ var featureOverlay = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ useSpatialIndex: false,
+ features: options.features,
+ wrapX: options.wrapX
+ }),
+ style: options.style ? options.style :
+ ol.interaction.Select.getDefaultStyleFunction(),
+ updateWhileAnimating: true,
+ updateWhileInteracting: true
+ });
+
+ /**
+ * @private
+ * @type {ol.layer.Vector}
+ */
+ this.featureOverlay_ = featureOverlay;
+
+ var layerFilter;
+ if (options.layers) {
+ if (typeof options.layers === 'function') {
+ /**
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {boolean} Include.
+ */
+ layerFilter = function(layer) {
+ goog.asserts.assertFunction(options.layers);
+ return options.layers(layer);
+ };
+ } else {
+ var layers = options.layers;
+ /**
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {boolean} Include.
+ */
+ layerFilter = function(layer) {
+ return ol.array.includes(layers, layer);
+ };
+ }
+ } else {
+ layerFilter = ol.functions.TRUE;
+ }
+
+ /**
+ * @private
+ * @type {function(ol.layer.Layer): boolean}
+ */
+ this.layerFilter_ = layerFilter;
+
+ /**
+ * An association between selected feature (key)
+ * and layer (value)
+ * @private
+ * @type {Object.<number, ol.layer.Layer>}
+ */
+ this.featureLayerAssociation_ = {};
+
+ var features = this.featureOverlay_.getSource().getFeaturesCollection();
+ ol.events.listen(features, ol.CollectionEventType.ADD,
+ this.addFeature_, this);
+ ol.events.listen(features, ol.CollectionEventType.REMOVE,
+ this.removeFeature_, this);
+
+};
+ol.inherits(ol.interaction.Select, ol.interaction.Interaction);
+
+
+/**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {ol.layer.Layer} layer Layer.
+ * @private
+ */
+ol.interaction.Select.prototype.addFeatureLayerAssociation_ = function(feature, layer) {
+ var key = goog.getUid(feature);
+ this.featureLayerAssociation_[key] = layer;
+};
+
+
+/**
+ * Get the selected features.
+ * @return {ol.Collection.<ol.Feature>} Features collection.
+ * @api stable
+ */
+ol.interaction.Select.prototype.getFeatures = function() {
+ return this.featureOverlay_.getSource().getFeaturesCollection();
+};
+
+
+/**
+ * Returns the associated {@link ol.layer.Vector vectorlayer} of
+ * the (last) selected feature. Note that this will not work with any
+ * programmatic method like pushing features to
+ * {@link ol.interaction.Select#getFeatures collection}.
+ * @param {ol.Feature|ol.render.Feature} feature Feature
+ * @return {ol.layer.Vector} Layer.
+ * @api
+ */
+ol.interaction.Select.prototype.getLayer = function(feature) {
+ goog.asserts.assertInstanceof(feature, ol.Feature,
+ 'feature should be an ol.Feature');
+ var key = goog.getUid(feature);
+ return /** @type {ol.layer.Vector} */ (this.featureLayerAssociation_[key]);
+};
+
+
+/**
+ * Handles the {@link ol.MapBrowserEvent map browser event} and may change the
+ * selected state of features.
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
+ * @return {boolean} `false` to stop event propagation.
+ * @this {ol.interaction.Select}
+ * @api
+ */
+ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
+ if (!this.condition_(mapBrowserEvent)) {
+ return true;
+ }
+ var add = this.addCondition_(mapBrowserEvent);
+ var remove = this.removeCondition_(mapBrowserEvent);
+ var toggle = this.toggleCondition_(mapBrowserEvent);
+ var set = !add && !remove && !toggle;
+ var map = mapBrowserEvent.map;
+ var features = this.featureOverlay_.getSource().getFeaturesCollection();
+ var deselected = [];
+ var selected = [];
+ if (set) {
+ // Replace the currently selected feature(s) with the feature(s) at the
+ // pixel, or clear the selected feature(s) if there is no feature at
+ // the pixel.
+ ol.object.clear(this.featureLayerAssociation_);
+ map.forEachFeatureAtPixel(mapBrowserEvent.pixel,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {boolean|undefined} Continue to iterate over the features.
+ */
+ function(feature, layer) {
+ if (this.filter_(feature, layer)) {
+ selected.push(feature);
+ this.addFeatureLayerAssociation_(feature, layer);
+ return !this.multi_;
+ }
+ }, this, this.layerFilter_);
+ if (selected.length > 0 && features.getLength() == 1 && features.item(0) == selected[0]) {
+ // No change; an already selected feature is selected again
+ selected.length = 0;
+ } else {
+ if (features.getLength() !== 0) {
+ deselected = Array.prototype.concat(features.getArray());
+ features.clear();
+ }
+ features.extend(selected);
+ }
+ } else {
+ // Modify the currently selected feature(s).
+ map.forEachFeatureAtPixel(mapBrowserEvent.pixel,
+ /**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {boolean|undefined} Continue to iterate over the features.
+ */
+ function(feature, layer) {
+ if (this.filter_(feature, layer)) {
+ if ((add || toggle) &&
+ !ol.array.includes(features.getArray(), feature)) {
+ selected.push(feature);
+ this.addFeatureLayerAssociation_(feature, layer);
+ } else if ((remove || toggle) &&
+ ol.array.includes(features.getArray(), feature)) {
+ deselected.push(feature);
+ this.removeFeatureLayerAssociation_(feature);
+ }
+ return !this.multi_;
+ }
+ }, this, this.layerFilter_);
+ var i;
+ for (i = deselected.length - 1; i >= 0; --i) {
+ features.remove(deselected[i]);
+ }
+ features.extend(selected);
+ }
+ if (selected.length > 0 || deselected.length > 0) {
+ this.dispatchEvent(
+ new ol.interaction.SelectEvent(ol.interaction.SelectEventType.SELECT,
+ selected, deselected, mapBrowserEvent));
+ }
+ return ol.events.condition.pointerMove(mapBrowserEvent);
+};
+
+
+/**
+ * Remove the interaction from its current map, if any, and attach it to a new
+ * map, if any. Pass `null` to just remove the interaction from the current map.
+ * @param {ol.Map} map Map.
+ * @api stable
+ */
+ol.interaction.Select.prototype.setMap = function(map) {
+ var currentMap = this.getMap();
+ var selectedFeatures =
+ this.featureOverlay_.getSource().getFeaturesCollection();
+ if (currentMap) {
+ selectedFeatures.forEach(currentMap.unskipFeature, currentMap);
+ }
+ ol.interaction.Interaction.prototype.setMap.call(this, map);
+ this.featureOverlay_.setMap(map);
+ if (map) {
+ selectedFeatures.forEach(map.skipFeature, map);
+ }
+};
+
+
+/**
+ * @return {ol.StyleFunction} Styles.
+ */
+ol.interaction.Select.getDefaultStyleFunction = function() {
+ var styles = ol.style.createDefaultEditingStyles();
+ ol.array.extend(styles[ol.geom.GeometryType.POLYGON],
+ styles[ol.geom.GeometryType.LINE_STRING]);
+ ol.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION],
+ styles[ol.geom.GeometryType.LINE_STRING]);
+
+ return function(feature, resolution) {
+ return styles[feature.getGeometry().getType()];
+ };
+};
+
+
+/**
+ * @param {ol.CollectionEvent} evt Event.
+ * @private
+ */
+ol.interaction.Select.prototype.addFeature_ = function(evt) {
+ var feature = evt.element;
+ var map = this.getMap();
+ goog.asserts.assertInstanceof(feature, ol.Feature,
+ 'feature should be an ol.Feature');
+ if (map) {
+ map.skipFeature(feature);
+ }
+};
+
+
+/**
+ * @param {ol.CollectionEvent} evt Event.
+ * @private
+ */
+ol.interaction.Select.prototype.removeFeature_ = function(evt) {
+ var feature = evt.element;
+ var map = this.getMap();
+ goog.asserts.assertInstanceof(feature, ol.Feature,
+ 'feature should be an ol.Feature');
+ if (map) {
+ map.unskipFeature(feature);
+ }
+};
+
+
+/**
+ * @param {ol.Feature|ol.render.Feature} feature Feature.
+ * @private
+ */
+ol.interaction.Select.prototype.removeFeatureLayerAssociation_ = function(feature) {
+ var key = goog.getUid(feature);
+ delete this.featureLayerAssociation_[key];
+};
+
+goog.provide('ol.interaction.Snap');
+goog.provide('ol.interaction.SnapProperty');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.Collection');
+goog.require('ol.CollectionEvent');
+goog.require('ol.CollectionEventType');
+goog.require('ol.Feature');
+goog.require('ol.Object');
+goog.require('ol.Observable');
+goog.require('ol.coordinate');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.geom.Geometry');
+goog.require('ol.interaction.Pointer');
+goog.require('ol.functions');
+goog.require('ol.object');
+goog.require('ol.source.Vector');
+goog.require('ol.source.VectorEvent');
+goog.require('ol.source.VectorEventType');
+goog.require('ol.structs.RBush');
+
+
+/**
+ * @classdesc
+ * Handles snapping of vector features while modifying or drawing them. The
+ * features can come from a {@link ol.source.Vector} or {@link ol.Collection}
+ * Any interaction object that allows the user to interact
+ * with the features using the mouse can benefit from the snapping, as long
+ * as it is added before.
+ *
+ * The snap interaction modifies map browser event `coordinate` and `pixel`
+ * properties to force the snap to occur to any interaction that them.
+ *
+ * Example:
+ *
+ * var snap = new ol.interaction.Snap({
+ * source: source
+ * });
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @param {olx.interaction.SnapOptions=} opt_options Options.
+ * @api
+ */
+ol.interaction.Snap = function(opt_options) {
+
+ ol.interaction.Pointer.call(this, {
+ handleEvent: ol.interaction.Snap.handleEvent_,
+ handleDownEvent: ol.functions.TRUE,
+ handleUpEvent: ol.interaction.Snap.handleUpEvent_
+ });
+
+ var options = opt_options ? opt_options : {};
+
+ /**
+ * @type {ol.source.Vector}
+ * @private
+ */
+ this.source_ = options.source ? options.source : null;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.vertex_ = options.vertex !== undefined ? options.vertex : true;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.edge_ = options.edge !== undefined ? options.edge : true;
+
+ /**
+ * @type {ol.Collection.<ol.Feature>}
+ * @private
+ */
+ this.features_ = options.features ? options.features : null;
+
+ /**
+ * @type {Array.<ol.EventsKey>}
+ * @private
+ */
+ this.featuresListenerKeys_ = [];
+
+ /**
+ * @type {Object.<number, ol.EventsKey>}
+ * @private
+ */
+ this.geometryChangeListenerKeys_ = {};
+
+ /**
+ * @type {Object.<number, ol.EventsKey>}
+ * @private
+ */
+ this.geometryModifyListenerKeys_ = {};
+
+ /**
+ * Extents are preserved so indexed segment can be quickly removed
+ * when its feature geometry changes
+ * @type {Object.<number, ol.Extent>}
+ * @private
+ */
+ this.indexedFeaturesExtents_ = {};
+
+ /**
+ * If a feature geometry changes while a pointer drag|move event occurs, the
+ * feature doesn't get updated right away. It will be at the next 'pointerup'
+ * event fired.
+ * @type {Object.<number, ol.Feature>}
+ * @private
+ */
+ this.pendingFeatures_ = {};
+
+ /**
+ * Used for distance sorting in sortByDistance_
+ * @type {ol.Coordinate}
+ * @private
+ */
+ this.pixelCoordinate_ = null;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.pixelTolerance_ = options.pixelTolerance !== undefined ?
+ options.pixelTolerance : 10;
+
+ /**
+ * @type {function(ol.SnapSegmentDataType, ol.SnapSegmentDataType): number}
+ * @private
+ */
+ this.sortByDistance_ = ol.interaction.Snap.sortByDistance.bind(this);
+
+
+ /**
+ * Segment RTree for each layer
+ * @type {ol.structs.RBush.<ol.SnapSegmentDataType>}
+ * @private
+ */
+ this.rBush_ = new ol.structs.RBush();
+
+
+ /**
+ * @const
+ * @private
+ * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>}
+ */
+ this.SEGMENT_WRITERS_ = {
+ 'Point': this.writePointGeometry_,
+ 'LineString': this.writeLineStringGeometry_,
+ 'LinearRing': this.writeLineStringGeometry_,
+ 'Polygon': this.writePolygonGeometry_,
+ 'MultiPoint': this.writeMultiPointGeometry_,
+ 'MultiLineString': this.writeMultiLineStringGeometry_,
+ 'MultiPolygon': this.writeMultiPolygonGeometry_,
+ 'GeometryCollection': this.writeGeometryCollectionGeometry_
+ };
+};
+ol.inherits(ol.interaction.Snap, ol.interaction.Pointer);
+
+
+/**
+ * Add a feature to the collection of features that we may snap to.
+ * @param {ol.Feature} feature Feature.
+ * @param {boolean=} opt_listen Whether to listen to the geometry change or not
+ * Defaults to `true`.
+ * @api
+ */
+ol.interaction.Snap.prototype.addFeature = function(feature, opt_listen) {
+ var listen = opt_listen !== undefined ? opt_listen : true;
+ var feature_uid = goog.getUid(feature);
+ var geometry = feature.getGeometry();
+ if (geometry) {
+ var segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()];
+ if (segmentWriter) {
+ this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(
+ ol.extent.createEmpty());
+ segmentWriter.call(this, feature, geometry);
+
+ if (listen) {
+ this.geometryModifyListenerKeys_[feature_uid] = ol.events.listen(
+ geometry,
+ ol.events.EventType.CHANGE,
+ this.handleGeometryModify_.bind(this, feature),
+ this);
+ }
+ }
+ }
+
+ if (listen) {
+ this.geometryChangeListenerKeys_[feature_uid] = ol.events.listen(
+ feature,
+ ol.Object.getChangeEventType(feature.getGeometryName()),
+ this.handleGeometryChange_, this);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.interaction.Snap.prototype.forEachFeatureAdd_ = function(feature) {
+ this.addFeature(feature);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @private
+ */
+ol.interaction.Snap.prototype.forEachFeatureRemove_ = function(feature) {
+ this.removeFeature(feature);
+};
+
+
+/**
+ * @return {ol.Collection.<ol.Feature>|Array.<ol.Feature>} Features.
+ * @private
+ */
+ol.interaction.Snap.prototype.getFeatures_ = function() {
+ var features;
+ if (this.features_) {
+ features = this.features_;
+ } else if (this.source_) {
+ features = this.source_.getFeatures();
+ }
+ goog.asserts.assert(features !== undefined, 'features should be defined');
+ return features;
+};
+
+
+/**
+ * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event.
+ * @private
+ */
+ol.interaction.Snap.prototype.handleFeatureAdd_ = function(evt) {
+ var feature;
+ if (evt instanceof ol.source.VectorEvent) {
+ feature = evt.feature;
+ } else if (evt instanceof ol.CollectionEvent) {
+ feature = evt.element;
+ }
+ goog.asserts.assertInstanceof(feature, ol.Feature,
+ 'feature should be an ol.Feature');
+ this.addFeature(feature);
+};
+
+
+/**
+ * @param {ol.source.VectorEvent|ol.CollectionEvent} evt Event.
+ * @private
+ */
+ol.interaction.Snap.prototype.handleFeatureRemove_ = function(evt) {
+ var feature;
+ if (evt instanceof ol.source.VectorEvent) {
+ feature = evt.feature;
+ } else if (evt instanceof ol.CollectionEvent) {
+ feature = evt.element;
+ }
+ goog.asserts.assertInstanceof(feature, ol.Feature,
+ 'feature should be an ol.Feature');
+ this.removeFeature(feature);
+};
+
+
+/**
+ * @param {ol.events.Event} evt Event.
+ * @private
+ */
+ol.interaction.Snap.prototype.handleGeometryChange_ = function(evt) {
+ var feature = evt.target;
+ goog.asserts.assertInstanceof(feature, ol.Feature);
+ this.removeFeature(feature, true);
+ this.addFeature(feature, true);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature which geometry was modified.
+ * @param {ol.events.Event} evt Event.
+ * @private
+ */
+ol.interaction.Snap.prototype.handleGeometryModify_ = function(feature, evt) {
+ if (this.handlingDownUpSequence) {
+ var uid = goog.getUid(feature);
+ if (!(uid in this.pendingFeatures_)) {
+ this.pendingFeatures_[uid] = feature;
+ }
+ } else {
+ this.updateFeature_(feature);
+ }
+};
+
+
+/**
+ * Remove a feature from the collection of features that we may snap to.
+ * @param {ol.Feature} feature Feature
+ * @param {boolean=} opt_unlisten Whether to unlisten to the geometry change
+ * or not. Defaults to `true`.
+ * @api
+ */
+ol.interaction.Snap.prototype.removeFeature = function(feature, opt_unlisten) {
+ var unlisten = opt_unlisten !== undefined ? opt_unlisten : true;
+ var feature_uid = goog.getUid(feature);
+ var extent = this.indexedFeaturesExtents_[feature_uid];
+ if (extent) {
+ var rBush = this.rBush_;
+ var i, nodesToRemove = [];
+ rBush.forEachInExtent(extent, function(node) {
+ if (feature === node.feature) {
+ nodesToRemove.push(node);
+ }
+ });
+ for (i = nodesToRemove.length - 1; i >= 0; --i) {
+ rBush.remove(nodesToRemove[i]);
+ }
+ if (unlisten) {
+ ol.Observable.unByKey(this.geometryModifyListenerKeys_[feature_uid]);
+ delete this.geometryModifyListenerKeys_[feature_uid];
+ }
+ }
+
+ if (unlisten) {
+ ol.Observable.unByKey(this.geometryChangeListenerKeys_[feature_uid]);
+ delete this.geometryChangeListenerKeys_[feature_uid];
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.Snap.prototype.setMap = function(map) {
+ var currentMap = this.getMap();
+ var keys = this.featuresListenerKeys_;
+ var features = this.getFeatures_();
+
+ if (currentMap) {
+ keys.forEach(ol.Observable.unByKey);
+ keys.length = 0;
+ features.forEach(this.forEachFeatureRemove_, this);
+ }
+ ol.interaction.Pointer.prototype.setMap.call(this, map);
+
+ if (map) {
+ if (this.features_) {
+ keys.push(
+ ol.events.listen(this.features_, ol.CollectionEventType.ADD,
+ this.handleFeatureAdd_, this),
+ ol.events.listen(this.features_, ol.CollectionEventType.REMOVE,
+ this.handleFeatureRemove_, this)
+ );
+ } else if (this.source_) {
+ keys.push(
+ ol.events.listen(this.source_, ol.source.VectorEventType.ADDFEATURE,
+ this.handleFeatureAdd_, this),
+ ol.events.listen(this.source_, ol.source.VectorEventType.REMOVEFEATURE,
+ this.handleFeatureRemove_, this)
+ );
+ }
+ features.forEach(this.forEachFeatureAdd_, this);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.Snap.prototype.shouldStopEvent = ol.functions.FALSE;
+
+
+/**
+ * @param {ol.Pixel} pixel Pixel
+ * @param {ol.Coordinate} pixelCoordinate Coordinate
+ * @param {ol.Map} map Map.
+ * @return {ol.SnapResultType} Snap result
+ */
+ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) {
+
+ var lowerLeft = map.getCoordinateFromPixel(
+ [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
+ var upperRight = map.getCoordinateFromPixel(
+ [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
+ var box = ol.extent.boundingExtent([lowerLeft, upperRight]);
+
+ var segments = this.rBush_.getInExtent(box);
+ var snappedToVertex = false;
+ var snapped = false;
+ var vertex = null;
+ var vertexPixel = null;
+ var dist, pixel1, pixel2, squaredDist1, squaredDist2;
+ if (segments.length > 0) {
+ this.pixelCoordinate_ = pixelCoordinate;
+ segments.sort(this.sortByDistance_);
+ var closestSegment = segments[0].segment;
+ if (this.vertex_ && !this.edge_) {
+ pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
+ pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
+ squaredDist1 = ol.coordinate.squaredDistance(pixel, pixel1);
+ squaredDist2 = ol.coordinate.squaredDistance(pixel, pixel2);
+ dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
+ snappedToVertex = dist <= this.pixelTolerance_;
+ if (snappedToVertex) {
+ snapped = true;
+ vertex = squaredDist1 > squaredDist2 ?
+ closestSegment[1] : closestSegment[0];
+ vertexPixel = map.getPixelFromCoordinate(vertex);
+ }
+ } else if (this.edge_) {
+ vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,
+ closestSegment));
+ vertexPixel = map.getPixelFromCoordinate(vertex);
+ if (Math.sqrt(ol.coordinate.squaredDistance(pixel, vertexPixel)) <=
+ this.pixelTolerance_) {
+ snapped = true;
+ if (this.vertex_) {
+ pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
+ pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
+ squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
+ squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
+ dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
+ snappedToVertex = dist <= this.pixelTolerance_;
+ if (snappedToVertex) {
+ vertex = squaredDist1 > squaredDist2 ?
+ closestSegment[1] : closestSegment[0];
+ vertexPixel = map.getPixelFromCoordinate(vertex);
+ }
+ }
+ }
+ }
+ if (snapped) {
+ vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
+ }
+ }
+ return /** @type {ol.SnapResultType} */ ({
+ snapped: snapped,
+ vertex: vertex,
+ vertexPixel: vertexPixel
+ });
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @private
+ */
+ol.interaction.Snap.prototype.updateFeature_ = function(feature) {
+ this.removeFeature(feature, false);
+ this.addFeature(feature, false);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.GeometryCollection} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writeGeometryCollectionGeometry_ = function(feature, geometry) {
+ var i, geometries = geometry.getGeometriesArray();
+ for (i = 0; i < geometries.length; ++i) {
+ this.SEGMENT_WRITERS_[geometries[i].getType()].call(
+ this, feature, geometries[i]);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.LineString} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writeLineStringGeometry_ = function(feature, geometry) {
+ var coordinates = geometry.getCoordinates();
+ var i, ii, segment, segmentData;
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.SnapSegmentDataType} */ ({
+ feature: feature,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.MultiLineString} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writeMultiLineStringGeometry_ = function(feature, geometry) {
+ var lines = geometry.getCoordinates();
+ var coordinates, i, ii, j, jj, segment, segmentData;
+ for (j = 0, jj = lines.length; j < jj; ++j) {
+ coordinates = lines[j];
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.SnapSegmentDataType} */ ({
+ feature: feature,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.MultiPoint} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writeMultiPointGeometry_ = function(feature, geometry) {
+ var points = geometry.getCoordinates();
+ var coordinates, i, ii, segmentData;
+ for (i = 0, ii = points.length; i < ii; ++i) {
+ coordinates = points[i];
+ segmentData = /** @type {ol.SnapSegmentDataType} */ ({
+ feature: feature,
+ segment: [coordinates, coordinates]
+ });
+ this.rBush_.insert(geometry.getExtent(), segmentData);
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.MultiPolygon} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writeMultiPolygonGeometry_ = function(feature, geometry) {
+ var polygons = geometry.getCoordinates();
+ var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData;
+ for (k = 0, kk = polygons.length; k < kk; ++k) {
+ rings = polygons[k];
+ for (j = 0, jj = rings.length; j < jj; ++j) {
+ coordinates = rings[j];
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.SnapSegmentDataType} */ ({
+ feature: feature,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+ }
+ }
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.Point} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writePointGeometry_ = function(feature, geometry) {
+ var coordinates = geometry.getCoordinates();
+ var segmentData = /** @type {ol.SnapSegmentDataType} */ ({
+ feature: feature,
+ segment: [coordinates, coordinates]
+ });
+ this.rBush_.insert(geometry.getExtent(), segmentData);
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature
+ * @param {ol.geom.Polygon} geometry Geometry.
+ * @private
+ */
+ol.interaction.Snap.prototype.writePolygonGeometry_ = function(feature, geometry) {
+ var rings = geometry.getCoordinates();
+ var coordinates, i, ii, j, jj, segment, segmentData;
+ for (j = 0, jj = rings.length; j < jj; ++j) {
+ coordinates = rings[j];
+ for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
+ segment = coordinates.slice(i, i + 2);
+ segmentData = /** @type {ol.SnapSegmentDataType} */ ({
+ feature: feature,
+ segment: segment
+ });
+ this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
+ }
+ }
+};
+
+
+/**
+ * Handle all pointer events events.
+ * @param {ol.MapBrowserEvent} evt A move event.
+ * @return {boolean} Pass the event to other interactions.
+ * @this {ol.interaction.Snap}
+ * @private
+ */
+ol.interaction.Snap.handleEvent_ = function(evt) {
+ var result = this.snapTo(evt.pixel, evt.coordinate, evt.map);
+ if (result.snapped) {
+ evt.coordinate = result.vertex.slice(0, 2);
+ evt.pixel = result.vertexPixel;
+ }
+ return ol.interaction.Pointer.handleEvent.call(this, evt);
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} evt Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.Snap}
+ * @private
+ */
+ol.interaction.Snap.handleUpEvent_ = function(evt) {
+ var featuresToUpdate = ol.object.getValues(this.pendingFeatures_);
+ if (featuresToUpdate.length) {
+ featuresToUpdate.forEach(this.updateFeature_, this);
+ this.pendingFeatures_ = {};
+ }
+ return false;
+};
+
+
+/**
+ * Sort segments by distance, helper function
+ * @param {ol.SnapSegmentDataType} a The first segment data.
+ * @param {ol.SnapSegmentDataType} b The second segment data.
+ * @return {number} The difference in distance.
+ * @this {ol.interaction.Snap}
+ */
+ol.interaction.Snap.sortByDistance = function(a, b) {
+ return ol.coordinate.squaredDistanceToSegment(
+ this.pixelCoordinate_, a.segment) -
+ ol.coordinate.squaredDistanceToSegment(
+ this.pixelCoordinate_, b.segment);
+};
+
+goog.provide('ol.interaction.Translate');
+goog.provide('ol.interaction.TranslateEvent');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.array');
+goog.require('ol.interaction.Pointer');
+
+
+/**
+ * @enum {string}
+ */
+ol.interaction.TranslateEventType = {
+ /**
+ * Triggered upon feature translation start.
+ * @event ol.interaction.TranslateEvent#translatestart
+ * @api
+ */
+ TRANSLATESTART: 'translatestart',
+ /**
+ * Triggered upon feature translation.
+ * @event ol.interaction.TranslateEvent#translating
+ * @api
+ */
+ TRANSLATING: 'translating',
+ /**
+ * Triggered upon feature translation end.
+ * @event ol.interaction.TranslateEvent#translateend
+ * @api
+ */
+ TRANSLATEEND: 'translateend'
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.interaction.Translate} instances are instances of
+ * this type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.interaction.TranslateEvent}
+ * @param {ol.interaction.TranslateEventType} type Type.
+ * @param {ol.Collection.<ol.Feature>} features The features translated.
+ * @param {ol.Coordinate} coordinate The event coordinate.
+ */
+ol.interaction.TranslateEvent = function(type, features, coordinate) {
+
+ ol.events.Event.call(this, type);
+
+ /**
+ * The features being translated.
+ * @type {ol.Collection.<ol.Feature>}
+ * @api
+ */
+ this.features = features;
+
+ /**
+ * The coordinate of the drag event.
+ * @const
+ * @type {ol.Coordinate}
+ * @api
+ */
+ this.coordinate = coordinate;
+};
+ol.inherits(ol.interaction.TranslateEvent, ol.events.Event);
+
+
+/**
+ * @classdesc
+ * Interaction for translating (moving) features.
+ *
+ * @constructor
+ * @extends {ol.interaction.Pointer}
+ * @fires ol.interaction.TranslateEvent
+ * @param {olx.interaction.TranslateOptions} options Options.
+ * @api
+ */
+ol.interaction.Translate = function(options) {
+ ol.interaction.Pointer.call(this, {
+ handleDownEvent: ol.interaction.Translate.handleDownEvent_,
+ handleDragEvent: ol.interaction.Translate.handleDragEvent_,
+ handleMoveEvent: ol.interaction.Translate.handleMoveEvent_,
+ handleUpEvent: ol.interaction.Translate.handleUpEvent_
+ });
+
+
+ /**
+ * @type {string|undefined}
+ * @private
+ */
+ this.previousCursor_ = undefined;
+
+
+ /**
+ * The last position we translated to.
+ * @type {ol.Coordinate}
+ * @private
+ */
+ this.lastCoordinate_ = null;
+
+
+ /**
+ * @type {ol.Collection.<ol.Feature>}
+ * @private
+ */
+ this.features_ = options.features !== undefined ? options.features : null;
+
+ var layerFilter;
+ if (options.layers) {
+ if (typeof options.layers === 'function') {
+ /**
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {boolean} Include.
+ */
+ layerFilter = function(layer) {
+ goog.asserts.assertFunction(options.layers);
+ return options.layers(layer);
+ };
+ } else {
+ var layers = options.layers;
+ /**
+ * @param {ol.layer.Layer} layer Layer.
+ * @return {boolean} Include.
+ */
+ layerFilter = function(layer) {
+ return ol.array.includes(layers, layer);
+ };
+ }
+ } else {
+ layerFilter = ol.functions.TRUE;
+ }
+
+ /**
+ * @private
+ * @type {function(ol.layer.Layer): boolean}
+ */
+ this.layerFilter_ = layerFilter;
+
+ /**
+ * @type {ol.Feature}
+ * @private
+ */
+ this.lastFeature_ = null;
+};
+ol.inherits(ol.interaction.Translate, ol.interaction.Pointer);
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} event Event.
+ * @return {boolean} Start drag sequence?
+ * @this {ol.interaction.Translate}
+ * @private
+ */
+ol.interaction.Translate.handleDownEvent_ = function(event) {
+ this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
+ if (!this.lastCoordinate_ && this.lastFeature_) {
+ this.lastCoordinate_ = event.coordinate;
+ ol.interaction.Translate.handleMoveEvent_.call(this, event);
+ this.dispatchEvent(
+ new ol.interaction.TranslateEvent(
+ ol.interaction.TranslateEventType.TRANSLATESTART, this.features_,
+ event.coordinate));
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} event Event.
+ * @return {boolean} Stop drag sequence?
+ * @this {ol.interaction.Translate}
+ * @private
+ */
+ol.interaction.Translate.handleUpEvent_ = function(event) {
+ if (this.lastCoordinate_) {
+ this.lastCoordinate_ = null;
+ ol.interaction.Translate.handleMoveEvent_.call(this, event);
+ this.dispatchEvent(
+ new ol.interaction.TranslateEvent(
+ ol.interaction.TranslateEventType.TRANSLATEEND, this.features_,
+ event.coordinate));
+ return true;
+ }
+ return false;
+};
+
+
+/**
+ * @param {ol.MapBrowserPointerEvent} event Event.
+ * @this {ol.interaction.Translate}
+ * @private
+ */
+ol.interaction.Translate.handleDragEvent_ = function(event) {
+ if (this.lastCoordinate_) {
+ var newCoordinate = event.coordinate;
+ var deltaX = newCoordinate[0] - this.lastCoordinate_[0];
+ var deltaY = newCoordinate[1] - this.lastCoordinate_[1];
+
+ if (this.features_) {
+ this.features_.forEach(function(feature) {
+ var geom = feature.getGeometry();
+ geom.translate(deltaX, deltaY);
+ feature.setGeometry(geom);
+ });
+ } else if (this.lastFeature_) {
+ var geom = this.lastFeature_.getGeometry();
+ geom.translate(deltaX, deltaY);
+ this.lastFeature_.setGeometry(geom);
+ }
+
+ this.lastCoordinate_ = newCoordinate;
+ this.dispatchEvent(
+ new ol.interaction.TranslateEvent(
+ ol.interaction.TranslateEventType.TRANSLATING, this.features_,
+ newCoordinate));
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserEvent} event Event.
+ * @this {ol.interaction.Translate}
+ * @private
+ */
+ol.interaction.Translate.handleMoveEvent_ = function(event) {
+ var elem = event.map.getTargetElement();
+ var intersectingFeature = event.map.forEachFeatureAtPixel(event.pixel,
+ function(feature) {
+ return feature;
+ });
+
+ if (intersectingFeature) {
+ var isSelected = false;
+
+ if (this.features_ &&
+ ol.array.includes(this.features_.getArray(), intersectingFeature)) {
+ isSelected = true;
+ }
+
+ this.previousCursor_ = elem.style.cursor;
+
+ // WebKit browsers don't support the grab icons without a prefix
+ elem.style.cursor = this.lastCoordinate_ ?
+ '-webkit-grabbing' : (isSelected ? '-webkit-grab' : 'pointer');
+
+ // Thankfully, attempting to set the standard ones will silently fail,
+ // keeping the prefixed icons
+ elem.style.cursor = !this.lastCoordinate_ ?
+ 'grabbing' : (isSelected ? 'grab' : 'pointer');
+
+ } else {
+ elem.style.cursor = this.previousCursor_ !== undefined ?
+ this.previousCursor_ : '';
+ this.previousCursor_ = undefined;
+ }
+};
+
+
+/**
+ * Tests to see if the given coordinates intersects any of our selected
+ * features.
+ * @param {ol.Pixel} pixel Pixel coordinate to test for intersection.
+ * @param {ol.Map} map Map to test the intersection on.
+ * @return {ol.Feature} Returns the feature found at the specified pixel
+ * coordinates.
+ * @private
+ */
+ol.interaction.Translate.prototype.featuresAtPixel_ = function(pixel, map) {
+ var found = null;
+
+ var intersectingFeature = map.forEachFeatureAtPixel(pixel,
+ function(feature) {
+ return feature;
+ }, this, this.layerFilter_);
+
+ if (this.features_ &&
+ ol.array.includes(this.features_.getArray(), intersectingFeature)) {
+ found = intersectingFeature;
+ }
+
+ return found;
+};
+
+goog.provide('ol.layer.Heatmap');
+
+goog.require('goog.asserts');
+goog.require('ol.events');
+goog.require('ol');
+goog.require('ol.Object');
+goog.require('ol.dom');
+goog.require('ol.layer.Vector');
+goog.require('ol.math');
+goog.require('ol.object');
+goog.require('ol.render.EventType');
+goog.require('ol.style.Icon');
+goog.require('ol.style.Style');
+
+
+/**
+ * @enum {string}
+ */
+ol.layer.HeatmapLayerProperty = {
+ BLUR: 'blur',
+ GRADIENT: 'gradient',
+ RADIUS: 'radius'
+};
+
+
+/**
+ * @classdesc
+ * Layer for rendering vector data as a heatmap.
+ * Note that any property set in the options is set as a {@link ol.Object}
+ * property on the layer object; for example, setting `title: 'My Title'` in the
+ * options means that `title` is observable, and has get/set accessors.
+ *
+ * @constructor
+ * @extends {ol.layer.Vector}
+ * @fires ol.render.Event
+ * @param {olx.layer.HeatmapOptions=} opt_options Options.
+ * @api
+ */
+ol.layer.Heatmap = function(opt_options) {
+ var options = opt_options ? opt_options : {};
+
+ var baseOptions = ol.object.assign({}, options);
+
+ delete baseOptions.gradient;
+ delete baseOptions.radius;
+ delete baseOptions.blur;
+ delete baseOptions.shadow;
+ delete baseOptions.weight;
+ ol.layer.Vector.call(this, /** @type {olx.layer.VectorOptions} */ (baseOptions));
+
+ /**
+ * @private
+ * @type {Uint8ClampedArray}
+ */
+ this.gradient_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.shadow_ = options.shadow !== undefined ? options.shadow : 250;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.circleImage_ = undefined;
+
+ /**
+ * @private
+ * @type {Array.<Array.<ol.style.Style>>}
+ */
+ this.styleCache_ = null;
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT),
+ this.handleGradientChanged_, this);
+
+ this.setGradient(options.gradient ?
+ options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT);
+
+ this.setBlur(options.blur !== undefined ? options.blur : 15);
+
+ this.setRadius(options.radius !== undefined ? options.radius : 8);
+
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.BLUR),
+ this.handleStyleChanged_, this);
+ ol.events.listen(this,
+ ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.RADIUS),
+ this.handleStyleChanged_, this);
+
+ this.handleStyleChanged_();
+
+ var weight = options.weight ? options.weight : 'weight';
+ var weightFunction;
+ if (typeof weight === 'string') {
+ weightFunction = function(feature) {
+ return feature.get(weight);
+ };
+ } else {
+ weightFunction = weight;
+ }
+ goog.asserts.assert(typeof weightFunction === 'function',
+ 'weightFunction should be a function');
+
+ this.setStyle(function(feature, resolution) {
+ goog.asserts.assert(this.styleCache_, 'this.styleCache_ expected');
+ goog.asserts.assert(this.circleImage_ !== undefined,
+ 'this.circleImage_ should be defined');
+ var weight = weightFunction(feature);
+ var opacity = weight !== undefined ? ol.math.clamp(weight, 0, 1) : 1;
+ // cast to 8 bits
+ var index = (255 * opacity) | 0;
+ var style = this.styleCache_[index];
+ if (!style) {
+ style = [
+ new ol.style.Style({
+ image: new ol.style.Icon({
+ opacity: opacity,
+ src: this.circleImage_
+ })
+ })
+ ];
+ this.styleCache_[index] = style;
+ }
+ return style;
+ }.bind(this));
+
+ // For performance reasons, don't sort the features before rendering.
+ // The render order is not relevant for a heatmap representation.
+ this.setRenderOrder(null);
+
+ ol.events.listen(this, ol.render.EventType.RENDER, this.handleRender_, this);
+
+};
+ol.inherits(ol.layer.Heatmap, ol.layer.Vector);
+
+
+/**
+ * @const
+ * @type {Array.<string>}
+ */
+ol.layer.Heatmap.DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00'];
+
+
+/**
+ * @param {Array.<string>} colors A list of colored.
+ * @return {Uint8ClampedArray} An array.
+ * @private
+ */
+ol.layer.Heatmap.createGradient_ = function(colors) {
+ var width = 1;
+ var height = 256;
+ var context = ol.dom.createCanvasContext2D(width, height);
+
+ var gradient = context.createLinearGradient(0, 0, width, height);
+ var step = 1 / (colors.length - 1);
+ for (var i = 0, ii = colors.length; i < ii; ++i) {
+ gradient.addColorStop(i * step, colors[i]);
+ }
+
+ context.fillStyle = gradient;
+ context.fillRect(0, 0, width, height);
+
+ return context.getImageData(0, 0, width, height).data;
+};
+
+
+/**
+ * @return {string} Data URL for a circle.
+ * @private
+ */
+ol.layer.Heatmap.prototype.createCircle_ = function() {
+ var radius = this.getRadius();
+ var blur = this.getBlur();
+ goog.asserts.assert(radius !== undefined && blur !== undefined,
+ 'radius and blur should be defined');
+ var halfSize = radius + blur + 1;
+ var size = 2 * halfSize;
+ var context = ol.dom.createCanvasContext2D(size, size);
+ context.shadowOffsetX = context.shadowOffsetY = this.shadow_;
+ context.shadowBlur = blur;
+ context.shadowColor = '#000';
+ context.beginPath();
+ var center = halfSize - this.shadow_;
+ context.arc(center, center, radius, 0, Math.PI * 2, true);
+ context.fill();
+ return context.canvas.toDataURL();
+};
+
+
+/**
+ * Return the blur size in pixels.
+ * @return {number} Blur size in pixels.
+ * @api
+ * @observable
+ */
+ol.layer.Heatmap.prototype.getBlur = function() {
+ return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.BLUR));
+};
+
+
+/**
+ * Return the gradient colors as array of strings.
+ * @return {Array.<string>} Colors.
+ * @api
+ * @observable
+ */
+ol.layer.Heatmap.prototype.getGradient = function() {
+ return /** @type {Array.<string>} */ (
+ this.get(ol.layer.HeatmapLayerProperty.GRADIENT));
+};
+
+
+/**
+ * Return the size of the radius in pixels.
+ * @return {number} Radius size in pixel.
+ * @api
+ * @observable
+ */
+ol.layer.Heatmap.prototype.getRadius = function() {
+ return /** @type {number} */ (this.get(ol.layer.HeatmapLayerProperty.RADIUS));
+};
+
+
+/**
+ * @private
+ */
+ol.layer.Heatmap.prototype.handleGradientChanged_ = function() {
+ this.gradient_ = ol.layer.Heatmap.createGradient_(this.getGradient());
+};
+
+
+/**
+ * @private
+ */
+ol.layer.Heatmap.prototype.handleStyleChanged_ = function() {
+ this.circleImage_ = this.createCircle_();
+ this.styleCache_ = new Array(256);
+ this.changed();
+};
+
+
+/**
+ * @param {ol.render.Event} event Post compose event
+ * @private
+ */
+ol.layer.Heatmap.prototype.handleRender_ = function(event) {
+ goog.asserts.assert(event.type == ol.render.EventType.RENDER,
+ 'event.type should be RENDER');
+ goog.asserts.assert(this.gradient_, 'this.gradient_ expected');
+ var context = event.context;
+ var canvas = context.canvas;
+ var image = context.getImageData(0, 0, canvas.width, canvas.height);
+ var view8 = image.data;
+ var i, ii, alpha;
+ for (i = 0, ii = view8.length; i < ii; i += 4) {
+ alpha = view8[i + 3] * 4;
+ if (alpha) {
+ view8[i] = this.gradient_[alpha];
+ view8[i + 1] = this.gradient_[alpha + 1];
+ view8[i + 2] = this.gradient_[alpha + 2];
+ }
+ }
+ context.putImageData(image, 0, 0);
+};
+
+
+/**
+ * Set the blur size in pixels.
+ * @param {number} blur Blur size in pixels.
+ * @api
+ * @observable
+ */
+ol.layer.Heatmap.prototype.setBlur = function(blur) {
+ this.set(ol.layer.HeatmapLayerProperty.BLUR, blur);
+};
+
+
+/**
+ * Set the gradient colors as array of strings.
+ * @param {Array.<string>} colors Gradient.
+ * @api
+ * @observable
+ */
+ol.layer.Heatmap.prototype.setGradient = function(colors) {
+ this.set(ol.layer.HeatmapLayerProperty.GRADIENT, colors);
+};
+
+
+/**
+ * Set the size of the radius in pixels.
+ * @param {number} radius Radius size in pixel.
+ * @api
+ * @observable
+ */
+ol.layer.Heatmap.prototype.setRadius = function(radius) {
+ this.set(ol.layer.HeatmapLayerProperty.RADIUS, radius);
+};
+
+goog.provide('ol.net');
+
+
+/**
+ * Simple JSONP helper. Supports error callbacks and a custom callback param.
+ * The error callback will be called when no JSONP is executed after 10 seconds.
+ *
+ * @param {string} url Request url. A 'callback' query parameter will be
+ * appended.
+ * @param {Function} callback Callback on success.
+ * @param {function()=} opt_errback Callback on error.
+ * @param {string=} opt_callbackParam Custom query parameter for the JSONP
+ * callback. Default is 'callback'.
+ */
+ol.net.jsonp = function(url, callback, opt_errback, opt_callbackParam) {
+ var script = ol.global.document.createElement('script');
+ var key = 'olc_' + goog.getUid(callback);
+ function cleanup() {
+ delete ol.global[key];
+ script.parentNode.removeChild(script);
+ }
+ script.async = true;
+ script.src = url + (url.indexOf('?') == -1 ? '?' : '&') +
+ (opt_callbackParam || 'callback') + '=' + key;
+ var timer = ol.global.setTimeout(function() {
+ cleanup();
+ if (opt_errback) {
+ opt_errback();
+ }
+ }, 10000);
+ ol.global[key] = function(data) {
+ ol.global.clearTimeout(timer);
+ cleanup();
+ callback(data);
+ };
+ ol.global.document.getElementsByTagName('head')[0].appendChild(script);
+};
+
+goog.provide('ol.render');
+
+goog.require('goog.vec.Mat4');
+goog.require('ol.render.canvas.Immediate');
+goog.require('ol.vec.Mat4');
+
+
+/**
+ * Binds a Canvas Immediate API to a canvas context, to allow drawing geometries
+ * to the context's canvas.
+ *
+ * The units for geometry coordinates are css pixels relative to the top left
+ * corner of the canvas element.
+ * ```js
+ * var canvas = document.createElement('canvas');
+ * var render = ol.render.toContext(canvas.getContext('2d'),
+ * { size: [100, 100] });
+ * render.setFillStrokeStyle(new ol.style.Fill({ color: blue }));
+ * render.drawPolygon(
+ * new ol.geom.Polygon([[[0, 0], [100, 100], [100, 0], [0, 0]]]));
+ * ```
+ *
+ * @param {CanvasRenderingContext2D} context Canvas context.
+ * @param {olx.render.ToContextOptions=} opt_options Options.
+ * @return {ol.render.canvas.Immediate} Canvas Immediate.
+ * @api
+ */
+ol.render.toContext = function(context, opt_options) {
+ var canvas = context.canvas;
+ var options = opt_options ? opt_options : {};
+ var pixelRatio = options.pixelRatio || ol.has.DEVICE_PIXEL_RATIO;
+ var size = options.size;
+ if (size) {
+ canvas.width = size[0] * pixelRatio;
+ canvas.height = size[1] * pixelRatio;
+ canvas.style.width = size[0] + 'px';
+ canvas.style.height = size[1] + 'px';
+ }
+ var extent = [0, 0, canvas.width, canvas.height];
+ var transform = ol.vec.Mat4.makeTransform2D(goog.vec.Mat4.createNumber(),
+ 0, 0, pixelRatio, pixelRatio, 0, 0, 0);
+ return new ol.render.canvas.Immediate(context, pixelRatio, extent, transform,
+ 0);
+};
+
+goog.provide('ol.reproj.Tile');
+
+goog.require('goog.asserts');
+goog.require('ol.Tile');
+goog.require('ol.TileState');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.math');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.reproj');
+goog.require('ol.reproj.Triangulation');
+
+
+/**
+ * @classdesc
+ * Class encapsulating single reprojected tile.
+ * See {@link ol.source.TileImage}.
+ *
+ * @constructor
+ * @extends {ol.Tile}
+ * @param {ol.proj.Projection} sourceProj Source projection.
+ * @param {ol.tilegrid.TileGrid} sourceTileGrid Source tile grid.
+ * @param {ol.proj.Projection} targetProj Target projection.
+ * @param {ol.tilegrid.TileGrid} targetTileGrid Target tile grid.
+ * @param {ol.TileCoord} tileCoord Coordinate of the tile.
+ * @param {ol.TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {number} gutter Gutter of the source tiles.
+ * @param {ol.ReprojTileFunctionType} getTileFunction
+ * Function returning source tiles (z, x, y, pixelRatio).
+ * @param {number=} opt_errorThreshold Acceptable reprojection error (in px).
+ * @param {boolean=} opt_renderEdges Render reprojection edges.
+ */
+ol.reproj.Tile = function(sourceProj, sourceTileGrid,
+ targetProj, targetTileGrid, tileCoord, wrappedTileCoord,
+ pixelRatio, gutter, getTileFunction,
+ opt_errorThreshold,
+ opt_renderEdges) {
+ ol.Tile.call(this, tileCoord, ol.TileState.IDLE);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderEdges_ = opt_renderEdges !== undefined ? opt_renderEdges : false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.pixelRatio_ = pixelRatio;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.gutter_ = gutter;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = null;
+
+ /**
+ * @private
+ * @type {Object.<number, HTMLCanvasElement>}
+ */
+ this.canvasByContext_ = {};
+
+ /**
+ * @private
+ * @type {ol.tilegrid.TileGrid}
+ */
+ this.sourceTileGrid_ = sourceTileGrid;
+
+ /**
+ * @private
+ * @type {ol.tilegrid.TileGrid}
+ */
+ this.targetTileGrid_ = targetTileGrid;
+
+ /**
+ * @private
+ * @type {ol.TileCoord}
+ */
+ this.wrappedTileCoord_ = wrappedTileCoord ? wrappedTileCoord : tileCoord;
+
+ /**
+ * @private
+ * @type {!Array.<ol.Tile>}
+ */
+ this.sourceTiles_ = [];
+
+ /**
+ * @private
+ * @type {Array.<ol.EventsKey>}
+ */
+ this.sourcesListenerKeys_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.sourceZ_ = 0;
+
+ var targetExtent = targetTileGrid.getTileCoordExtent(this.wrappedTileCoord_);
+ var maxTargetExtent = this.targetTileGrid_.getExtent();
+ var maxSourceExtent = this.sourceTileGrid_.getExtent();
+
+ var limitedTargetExtent = maxTargetExtent ?
+ ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent;
+
+ if (ol.extent.getArea(limitedTargetExtent) === 0) {
+ // Tile is completely outside range -> EMPTY
+ // TODO: is it actually correct that the source even creates the tile ?
+ this.state = ol.TileState.EMPTY;
+ return;
+ }
+
+ var sourceProjExtent = sourceProj.getExtent();
+ if (sourceProjExtent) {
+ if (!maxSourceExtent) {
+ maxSourceExtent = sourceProjExtent;
+ } else {
+ maxSourceExtent = ol.extent.getIntersection(
+ maxSourceExtent, sourceProjExtent);
+ }
+ }
+
+ var targetResolution = targetTileGrid.getResolution(
+ this.wrappedTileCoord_[0]);
+
+ var targetCenter = ol.extent.getCenter(limitedTargetExtent);
+ var sourceResolution = ol.reproj.calculateSourceResolution(
+ sourceProj, targetProj, targetCenter, targetResolution);
+
+ if (!isFinite(sourceResolution) || sourceResolution <= 0) {
+ // invalid sourceResolution -> EMPTY
+ // probably edges of the projections when no extent is defined
+ this.state = ol.TileState.EMPTY;
+ return;
+ }
+
+ var errorThresholdInPixels = opt_errorThreshold !== undefined ?
+ opt_errorThreshold : ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD;
+
+ /**
+ * @private
+ * @type {!ol.reproj.Triangulation}
+ */
+ this.triangulation_ = new ol.reproj.Triangulation(
+ sourceProj, targetProj, limitedTargetExtent, maxSourceExtent,
+ sourceResolution * errorThresholdInPixels);
+
+ if (this.triangulation_.getTriangles().length === 0) {
+ // no valid triangles -> EMPTY
+ this.state = ol.TileState.EMPTY;
+ return;
+ }
+
+ this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution);
+ var sourceExtent = this.triangulation_.calculateSourceExtent();
+
+ if (maxSourceExtent) {
+ if (sourceProj.canWrapX()) {
+ sourceExtent[1] = ol.math.clamp(
+ sourceExtent[1], maxSourceExtent[1], maxSourceExtent[3]);
+ sourceExtent[3] = ol.math.clamp(
+ sourceExtent[3], maxSourceExtent[1], maxSourceExtent[3]);
+ } else {
+ sourceExtent = ol.extent.getIntersection(sourceExtent, maxSourceExtent);
+ }
+ }
+
+ if (!ol.extent.getArea(sourceExtent)) {
+ this.state = ol.TileState.EMPTY;
+ } else {
+ var sourceRange = sourceTileGrid.getTileRangeForExtentAndZ(
+ sourceExtent, this.sourceZ_);
+
+ var tilesRequired = sourceRange.getWidth() * sourceRange.getHeight();
+ if (!goog.asserts.assert(
+ tilesRequired < ol.RASTER_REPROJECTION_MAX_SOURCE_TILES,
+ 'reasonable number of tiles is required')) {
+ this.state = ol.TileState.ERROR;
+ return;
+ }
+ for (var srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) {
+ for (var srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) {
+ var tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio);
+ if (tile) {
+ this.sourceTiles_.push(tile);
+ }
+ }
+ }
+
+ if (this.sourceTiles_.length === 0) {
+ this.state = ol.TileState.EMPTY;
+ }
+ }
+};
+ol.inherits(ol.reproj.Tile, ol.Tile);
+
+
+/**
+ * @inheritDoc
+ */
+ol.reproj.Tile.prototype.disposeInternal = function() {
+ if (this.state == ol.TileState.LOADING) {
+ this.unlistenSources_();
+ }
+ ol.Tile.prototype.disposeInternal.call(this);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.reproj.Tile.prototype.getImage = function(opt_context) {
+ if (opt_context !== undefined) {
+ var image;
+ var key = goog.getUid(opt_context);
+ if (key in this.canvasByContext_) {
+ return this.canvasByContext_[key];
+ } else if (ol.object.isEmpty(this.canvasByContext_)) {
+ image = this.canvas_;
+ } else {
+ image = /** @type {HTMLCanvasElement} */ (this.canvas_.cloneNode(false));
+ }
+ this.canvasByContext_[key] = image;
+ return image;
+ } else {
+ return this.canvas_;
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.reproj.Tile.prototype.reproject_ = function() {
+ var sources = [];
+ this.sourceTiles_.forEach(function(tile, i, arr) {
+ if (tile && tile.getState() == ol.TileState.LOADED) {
+ sources.push({
+ extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord),
+ image: tile.getImage()
+ });
+ }
+ }, this);
+ this.sourceTiles_.length = 0;
+
+ if (sources.length === 0) {
+ this.state = ol.TileState.ERROR;
+ } else {
+ var z = this.wrappedTileCoord_[0];
+ var size = this.targetTileGrid_.getTileSize(z);
+ var width = goog.isNumber(size) ? size : size[0];
+ var height = goog.isNumber(size) ? size : size[1];
+ var targetResolution = this.targetTileGrid_.getResolution(z);
+ var sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_);
+
+ var targetExtent = this.targetTileGrid_.getTileCoordExtent(
+ this.wrappedTileCoord_);
+ this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_,
+ sourceResolution, this.sourceTileGrid_.getExtent(),
+ targetResolution, targetExtent, this.triangulation_, sources,
+ this.gutter_, this.renderEdges_);
+
+ this.state = ol.TileState.LOADED;
+ }
+ this.changed();
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.reproj.Tile.prototype.load = function() {
+ if (this.state == ol.TileState.IDLE) {
+ this.state = ol.TileState.LOADING;
+ this.changed();
+
+ var leftToLoad = 0;
+
+ goog.asserts.assert(!this.sourcesListenerKeys_,
+ 'this.sourcesListenerKeys_ should be null');
+
+ this.sourcesListenerKeys_ = [];
+ this.sourceTiles_.forEach(function(tile, i, arr) {
+ var state = tile.getState();
+ if (state == ol.TileState.IDLE || state == ol.TileState.LOADING) {
+ leftToLoad++;
+
+ var sourceListenKey;
+ sourceListenKey = ol.events.listen(tile, ol.events.EventType.CHANGE,
+ function(e) {
+ var state = tile.getState();
+ if (state == ol.TileState.LOADED ||
+ state == ol.TileState.ERROR ||
+ state == ol.TileState.EMPTY) {
+ ol.events.unlistenByKey(sourceListenKey);
+ leftToLoad--;
+ goog.asserts.assert(leftToLoad >= 0,
+ 'leftToLoad should not be negative');
+ if (leftToLoad === 0) {
+ this.unlistenSources_();
+ this.reproject_();
+ }
+ }
+ }, this);
+ this.sourcesListenerKeys_.push(sourceListenKey);
+ }
+ }, this);
+
+ this.sourceTiles_.forEach(function(tile, i, arr) {
+ var state = tile.getState();
+ if (state == ol.TileState.IDLE) {
+ tile.load();
+ }
+ });
+
+ if (leftToLoad === 0) {
+ ol.global.setTimeout(this.reproject_.bind(this), 0);
+ }
+ }
+};
+
+
+/**
+ * @private
+ */
+ol.reproj.Tile.prototype.unlistenSources_ = function() {
+ goog.asserts.assert(this.sourcesListenerKeys_,
+ 'this.sourcesListenerKeys_ should not be null');
+ this.sourcesListenerKeys_.forEach(ol.events.unlistenByKey);
+ this.sourcesListenerKeys_ = null;
+};
+
+goog.provide('ol.source.TileImage');
+
+goog.require('goog.asserts');
+goog.require('ol.ImageTile');
+goog.require('ol.TileCache');
+goog.require('ol.TileState');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.proj');
+goog.require('ol.reproj.Tile');
+goog.require('ol.source.UrlTile');
+
+
+/**
+ * @classdesc
+ * Base class for sources providing images divided into a tile grid.
+ *
+ * @constructor
+ * @fires ol.source.TileEvent
+ * @extends {ol.source.UrlTile}
+ * @param {olx.source.TileImageOptions} options Image tile options.
+ * @api
+ */
+ol.source.TileImage = function(options) {
+
+ ol.source.UrlTile.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ extent: options.extent,
+ logo: options.logo,
+ opaque: options.opaque,
+ projection: options.projection,
+ state: options.state,
+ tileGrid: options.tileGrid,
+ tileLoadFunction: options.tileLoadFunction ?
+ options.tileLoadFunction : ol.source.TileImage.defaultTileLoadFunction,
+ tilePixelRatio: options.tilePixelRatio,
+ tileUrlFunction: options.tileUrlFunction,
+ url: options.url,
+ urls: options.urls,
+ wrapX: options.wrapX
+ });
+
+ /**
+ * @protected
+ * @type {?string}
+ */
+ this.crossOrigin =
+ options.crossOrigin !== undefined ? options.crossOrigin : null;
+
+ /**
+ * @protected
+ * @type {function(new: ol.ImageTile, ol.TileCoord, ol.TileState, string,
+ * ?string, ol.TileLoadFunctionType)}
+ */
+ this.tileClass = options.tileClass !== undefined ?
+ options.tileClass : ol.ImageTile;
+
+ /**
+ * @protected
+ * @type {Object.<string, ol.TileCache>}
+ */
+ this.tileCacheForProjection = {};
+
+ /**
+ * @protected
+ * @type {Object.<string, ol.tilegrid.TileGrid>}
+ */
+ this.tileGridForProjection = {};
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.renderReprojectionEdges_ = false;
+};
+ol.inherits(ol.source.TileImage, ol.source.UrlTile);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.canExpireCache = function() {
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ return ol.source.UrlTile.prototype.canExpireCache.call(this);
+ }
+ if (this.tileCache.canExpireCache()) {
+ return true;
+ } else {
+ for (var key in this.tileCacheForProjection) {
+ if (this.tileCacheForProjection[key].canExpireCache()) {
+ return true;
+ }
+ }
+ }
+ return false;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.expireCache = function(projection, usedTiles) {
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ ol.source.UrlTile.prototype.expireCache.call(this, projection, usedTiles);
+ return;
+ }
+ var usedTileCache = this.getTileCacheForProjection(projection);
+
+ this.tileCache.expireCache(this.tileCache == usedTileCache ? usedTiles : {});
+ for (var id in this.tileCacheForProjection) {
+ var tileCache = this.tileCacheForProjection[id];
+ tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {});
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.getGutter = function(projection) {
+ if (ol.ENABLE_RASTER_REPROJECTION &&
+ this.getProjection() && projection &&
+ !ol.proj.equivalent(this.getProjection(), projection)) {
+ return 0;
+ } else {
+ return this.getGutterInternal();
+ }
+};
+
+
+/**
+ * @protected
+ * @return {number} Gutter.
+ */
+ol.source.TileImage.prototype.getGutterInternal = function() {
+ return 0;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.getOpaque = function(projection) {
+ if (ol.ENABLE_RASTER_REPROJECTION &&
+ this.getProjection() && projection &&
+ !ol.proj.equivalent(this.getProjection(), projection)) {
+ return false;
+ } else {
+ return ol.source.UrlTile.prototype.getOpaque.call(this, projection);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.getTileGridForProjection = function(projection) {
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ return ol.source.UrlTile.prototype.getTileGridForProjection.call(this, projection);
+ }
+ var thisProj = this.getProjection();
+ if (this.tileGrid &&
+ (!thisProj || ol.proj.equivalent(thisProj, projection))) {
+ return this.tileGrid;
+ } else {
+ var projKey = goog.getUid(projection).toString();
+ if (!(projKey in this.tileGridForProjection)) {
+ this.tileGridForProjection[projKey] =
+ ol.tilegrid.getForProjection(projection);
+ }
+ return this.tileGridForProjection[projKey];
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.getTileCacheForProjection = function(projection) {
+ if (!ol.ENABLE_RASTER_REPROJECTION) {
+ return ol.source.UrlTile.prototype.getTileCacheForProjection.call(this, projection);
+ }
+ var thisProj = this.getProjection();
+ if (!thisProj || ol.proj.equivalent(thisProj, projection)) {
+ return this.tileCache;
+ } else {
+ var projKey = goog.getUid(projection).toString();
+ if (!(projKey in this.tileCacheForProjection)) {
+ this.tileCacheForProjection[projKey] = new ol.TileCache();
+ }
+ return this.tileCacheForProjection[projKey];
+ }
+};
+
+
+/**
+ * @param {number} z Tile coordinate z.
+ * @param {number} x Tile coordinate x.
+ * @param {number} y Tile coordinate y.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {string} key The key set on the tile.
+ * @return {ol.Tile} Tile.
+ * @private
+ */
+ol.source.TileImage.prototype.createTile_ = function(z, x, y, pixelRatio, projection, key) {
+ var tileCoord = [z, x, y];
+ var urlTileCoord = this.getTileCoordForTileUrlFunction(
+ tileCoord, projection);
+ var tileUrl = urlTileCoord ?
+ this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
+ var tile = new this.tileClass(
+ tileCoord,
+ tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
+ tileUrl !== undefined ? tileUrl : '',
+ this.crossOrigin,
+ this.tileLoadFunction);
+ tile.key = key;
+ ol.events.listen(tile, ol.events.EventType.CHANGE,
+ this.handleTileChange, this);
+ return tile;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileImage.prototype.getTile = function(z, x, y, pixelRatio, projection) {
+ if (!ol.ENABLE_RASTER_REPROJECTION ||
+ !this.getProjection() ||
+ !projection ||
+ ol.proj.equivalent(this.getProjection(), projection)) {
+ return this.getTileInternal(z, x, y, pixelRatio, projection);
+ } else {
+ var cache = this.getTileCacheForProjection(projection);
+ var tileCoord = [z, x, y];
+ var tileCoordKey = this.getKeyZXY.apply(this, tileCoord);
+ if (cache.containsKey(tileCoordKey)) {
+ return /** @type {!ol.Tile} */ (cache.get(tileCoordKey));
+ } else {
+ var sourceProjection = this.getProjection();
+ var sourceTileGrid = this.getTileGridForProjection(sourceProjection);
+ var targetTileGrid = this.getTileGridForProjection(projection);
+ var wrappedTileCoord =
+ this.getTileCoordForTileUrlFunction(tileCoord, projection);
+ var tile = new ol.reproj.Tile(
+ sourceProjection, sourceTileGrid,
+ projection, targetTileGrid,
+ tileCoord, wrappedTileCoord, this.getTilePixelRatio(pixelRatio),
+ this.getGutterInternal(),
+ function(z, x, y, pixelRatio) {
+ return this.getTileInternal(z, x, y, pixelRatio, sourceProjection);
+ }.bind(this), this.reprojectionErrorThreshold_,
+ this.renderReprojectionEdges_);
+
+ cache.set(tileCoordKey, tile);
+ return tile;
+ }
+ }
+};
+
+
+/**
+ * @param {number} z Tile coordinate z.
+ * @param {number} x Tile coordinate x.
+ * @param {number} y Tile coordinate y.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {!ol.Tile} Tile.
+ * @protected
+ */
+ol.source.TileImage.prototype.getTileInternal = function(z, x, y, pixelRatio, projection) {
+ var /** @type {ol.Tile} */ tile = null;
+ var tileCoordKey = this.getKeyZXY(z, x, y);
+ var key = this.getKey();
+ if (!this.tileCache.containsKey(tileCoordKey)) {
+ goog.asserts.assert(projection, 'argument projection is truthy');
+ tile = this.createTile_(z, x, y, pixelRatio, projection, key);
+ this.tileCache.set(tileCoordKey, tile);
+ } else {
+ tile = /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
+ if (tile.key != key) {
+ // The source's params changed. If the tile has an interim tile and if we
+ // can use it then we use it. Otherwise we create a new tile. In both
+ // cases we attempt to assign an interim tile to the new tile.
+ var /** @type {ol.Tile} */ interimTile = tile;
+ if (tile.interimTile && tile.interimTile.key == key) {
+ goog.asserts.assert(tile.interimTile.getState() == ol.TileState.LOADED);
+ goog.asserts.assert(tile.interimTile.interimTile === null);
+ tile = tile.interimTile;
+ if (interimTile.getState() == ol.TileState.LOADED) {
+ tile.interimTile = interimTile;
+ }
+ } else {
+ tile = this.createTile_(z, x, y, pixelRatio, projection, key);
+ if (interimTile.getState() == ol.TileState.LOADED) {
+ tile.interimTile = interimTile;
+ } else if (interimTile.interimTile &&
+ interimTile.interimTile.getState() == ol.TileState.LOADED) {
+ tile.interimTile = interimTile.interimTile;
+ interimTile.interimTile = null;
+ }
+ }
+ if (tile.interimTile) {
+ tile.interimTile.interimTile = null;
+ }
+ this.tileCache.replace(tileCoordKey, tile);
+ }
+ }
+ goog.asserts.assert(tile);
+ return tile;
+};
+
+
+/**
+ * Sets whether to render reprojection edges or not (usually for debugging).
+ * @param {boolean} render Render the edges.
+ * @api
+ */
+ol.source.TileImage.prototype.setRenderReprojectionEdges = function(render) {
+ if (!ol.ENABLE_RASTER_REPROJECTION ||
+ this.renderReprojectionEdges_ == render) {
+ return;
+ }
+ this.renderReprojectionEdges_ = render;
+ for (var id in this.tileCacheForProjection) {
+ this.tileCacheForProjection[id].clear();
+ }
+ this.changed();
+};
+
+
+/**
+ * Sets the tile grid to use when reprojecting the tiles to the given
+ * projection instead of the default tile grid for the projection.
+ *
+ * This can be useful when the default tile grid cannot be created
+ * (e.g. projection has no extent defined) or
+ * for optimization reasons (custom tile size, resolutions, ...).
+ *
+ * @param {ol.ProjectionLike} projection Projection.
+ * @param {ol.tilegrid.TileGrid} tilegrid Tile grid to use for the projection.
+ * @api
+ */
+ol.source.TileImage.prototype.setTileGridForProjection = function(projection, tilegrid) {
+ if (ol.ENABLE_RASTER_REPROJECTION) {
+ var proj = ol.proj.get(projection);
+ if (proj) {
+ var projKey = goog.getUid(proj).toString();
+ if (!(projKey in this.tileGridForProjection)) {
+ this.tileGridForProjection[projKey] = tilegrid;
+ }
+ }
+ }
+};
+
+
+/**
+ * @param {ol.ImageTile} imageTile Image tile.
+ * @param {string} src Source.
+ */
+ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) {
+ imageTile.getImage().src = src;
+};
+
+goog.provide('ol.source.BingMaps');
+
+goog.require('goog.asserts');
+goog.require('ol.Attribution');
+goog.require('ol.TileRange');
+goog.require('ol.TileUrlFunction');
+goog.require('ol.extent');
+goog.require('ol.net');
+goog.require('ol.proj');
+goog.require('ol.source.State');
+goog.require('ol.source.TileImage');
+goog.require('ol.tilecoord');
+
+
+/**
+ * @classdesc
+ * Layer source for Bing Maps tile data.
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.BingMapsOptions} options Bing Maps options.
+ * @api stable
+ */
+ol.source.BingMaps = function(options) {
+
+ ol.source.TileImage.call(this, {
+ cacheSize: options.cacheSize,
+ crossOrigin: 'anonymous',
+ opaque: true,
+ projection: ol.proj.get('EPSG:3857'),
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ state: ol.source.State.LOADING,
+ tileLoadFunction: options.tileLoadFunction,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.culture_ = options.culture !== undefined ? options.culture : 'en-us';
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1;
+
+ var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' +
+ options.imagerySet +
+ '?uriScheme=https&include=ImageryProviders&key=' + options.key;
+
+ ol.net.jsonp(url, this.handleImageryMetadataResponse.bind(this), undefined,
+ 'jsonp');
+
+};
+ol.inherits(ol.source.BingMaps, ol.source.TileImage);
+
+
+/**
+ * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’
+ * Terms Of Use.
+ * @const
+ * @type {ol.Attribution}
+ * @api
+ */
+ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({
+ html: '<a class="ol-attribution-bing-tos" ' +
+ 'href="http://www.microsoft.com/maps/product/terms.html">' +
+ 'Terms of Use</a>'
+});
+
+
+/**
+ * @param {BingMapsImageryMetadataResponse} response Response.
+ */
+ol.source.BingMaps.prototype.handleImageryMetadataResponse = function(response) {
+
+ if (response.statusCode != 200 ||
+ response.statusDescription != 'OK' ||
+ response.authenticationResultCode != 'ValidCredentials' ||
+ response.resourceSets.length != 1 ||
+ response.resourceSets[0].resources.length != 1) {
+ this.setState(ol.source.State.ERROR);
+ return;
+ }
+
+ var brandLogoUri = response.brandLogoUri;
+ if (brandLogoUri.indexOf('https') == -1) {
+ brandLogoUri = brandLogoUri.replace('http', 'https');
+ }
+ //var copyright = response.copyright; // FIXME do we need to display this?
+ var resource = response.resourceSets[0].resources[0];
+ goog.asserts.assert(resource.imageWidth == resource.imageHeight,
+ 'resource has imageWidth equal to imageHeight, i.e. is square');
+ var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_;
+
+ var sourceProjection = this.getProjection();
+ var extent = ol.tilegrid.extentFromProjection(sourceProjection);
+ var tileSize = resource.imageWidth == resource.imageHeight ?
+ resource.imageWidth : [resource.imageWidth, resource.imageHeight];
+ var tileGrid = ol.tilegrid.createXYZ({
+ extent: extent,
+ minZoom: resource.zoomMin,
+ maxZoom: maxZoom,
+ tileSize: tileSize
+ });
+ this.tileGrid = tileGrid;
+
+ var culture = this.culture_;
+ this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(
+ resource.imageUrlSubdomains.map(function(subdomain) {
+ var quadKeyTileCoord = [0, 0, 0];
+ var imageUrl = resource.imageUrl
+ .replace('{subdomain}', subdomain)
+ .replace('{culture}', culture);
+ return (
+ /**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string|undefined} Tile URL.
+ */
+ function(tileCoord, pixelRatio, projection) {
+ goog.asserts.assert(ol.proj.equivalent(
+ projection, sourceProjection),
+ 'projections are equivalent');
+ if (!tileCoord) {
+ return undefined;
+ } else {
+ ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1],
+ -tileCoord[2] - 1, quadKeyTileCoord);
+ return imageUrl.replace('{quadkey}', ol.tilecoord.quadKey(
+ quadKeyTileCoord));
+ }
+ });
+ }));
+
+ if (resource.imageryProviders) {
+ var transform = ol.proj.getTransformFromProjections(
+ ol.proj.get('EPSG:4326'), this.getProjection());
+
+ var attributions = resource.imageryProviders.map(function(imageryProvider) {
+ var html = imageryProvider.attribution;
+ /** @type {Object.<string, Array.<ol.TileRange>>} */
+ var tileRanges = {};
+ imageryProvider.coverageAreas.forEach(function(coverageArea) {
+ var minZ = coverageArea.zoomMin;
+ var maxZ = Math.min(coverageArea.zoomMax, maxZoom);
+ var bbox = coverageArea.bbox;
+ var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];
+ var extent = ol.extent.applyTransform(epsg4326Extent, transform);
+ var tileRange, z, zKey;
+ for (z = minZ; z <= maxZ; ++z) {
+ zKey = z.toString();
+ tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
+ if (zKey in tileRanges) {
+ tileRanges[zKey].push(tileRange);
+ } else {
+ tileRanges[zKey] = [tileRange];
+ }
+ }
+ });
+ return new ol.Attribution({html: html, tileRanges: tileRanges});
+ });
+ attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION);
+ this.setAttributions(attributions);
+ }
+
+ this.setLogo(brandLogoUri);
+
+ this.setState(ol.source.State.READY);
+
+};
+
+goog.provide('ol.source.XYZ');
+
+goog.require('ol.source.TileImage');
+
+
+/**
+ * @classdesc
+ * Layer source for tile data with URLs in a set XYZ format that are
+ * defined in a URL template. By default, this follows the widely-used
+ * Google grid where `x` 0 and `y` 0 are in the top left. Grids like
+ * TMS where `x` 0 and `y` 0 are in the bottom left can be used by
+ * using the `{-y}` placeholder in the URL template, so long as the
+ * source does not have a custom tile grid. In this case,
+ * {@link ol.source.TileImage} can be used with a `tileUrlFunction`
+ * such as:
+ *
+ * tileUrlFunction: function(coordinate) {
+ * return 'http://mapserver.com/' + coordinate[0] + '/' +
+ * coordinate[1] + '/' + coordinate[2] + '.png';
+ * }
+ *
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.XYZOptions=} opt_options XYZ options.
+ * @api stable
+ */
+ol.source.XYZ = function(opt_options) {
+ var options = opt_options || {};
+ var projection = options.projection !== undefined ?
+ options.projection : 'EPSG:3857';
+
+ var tileGrid = options.tileGrid !== undefined ? options.tileGrid :
+ ol.tilegrid.createXYZ({
+ extent: ol.tilegrid.extentFromProjection(projection),
+ maxZoom: options.maxZoom,
+ minZoom: options.minZoom,
+ tileSize: options.tileSize
+ });
+
+ ol.source.TileImage.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ logo: options.logo,
+ opaque: options.opaque,
+ projection: projection,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileGrid: tileGrid,
+ tileLoadFunction: options.tileLoadFunction,
+ tilePixelRatio: options.tilePixelRatio,
+ tileUrlFunction: options.tileUrlFunction,
+ url: options.url,
+ urls: options.urls,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+};
+ol.inherits(ol.source.XYZ, ol.source.TileImage);
+
+goog.provide('ol.source.CartoDB');
+
+goog.require('ol.object');
+goog.require('ol.source.State');
+goog.require('ol.source.XYZ');
+
+
+/**
+ * @classdesc
+ * Layer source for the CartoDB tiles.
+ *
+ * @constructor
+ * @extends {ol.source.XYZ}
+ * @param {olx.source.CartoDBOptions} options CartoDB options.
+ * @api
+ */
+ol.source.CartoDB = function(options) {
+
+ /**
+ * @type {string}
+ * @private
+ */
+ this.account_ = options.account;
+
+ /**
+ * @type {string}
+ * @private
+ */
+ this.mapId_ = options.map || '';
+
+ /**
+ * @type {!Object}
+ * @private
+ */
+ this.config_ = options.config || {};
+
+ /**
+ * @type {!Object.<string, CartoDBLayerInfo>}
+ * @private
+ */
+ this.templateCache_ = {};
+
+ ol.source.XYZ.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ logo: options.logo,
+ maxZoom: options.maxZoom !== undefined ? options.maxZoom : 18,
+ minZoom: options.minZoom,
+ projection: options.projection,
+ state: ol.source.State.LOADING,
+ wrapX: options.wrapX
+ });
+ this.initializeMap_();
+};
+ol.inherits(ol.source.CartoDB, ol.source.XYZ);
+
+
+/**
+ * Returns the current config.
+ * @return {!Object} The current configuration.
+ * @api
+ */
+ol.source.CartoDB.prototype.getConfig = function() {
+ return this.config_;
+};
+
+
+/**
+ * Updates the carto db config.
+ * @param {Object} config a key-value lookup. Values will replace current values
+ * in the config.
+ * @api
+ */
+ol.source.CartoDB.prototype.updateConfig = function(config) {
+ ol.object.assign(this.config_, config);
+ this.initializeMap_();
+};
+
+
+/**
+ * Sets the CartoDB config
+ * @param {Object} config In the case of anonymous maps, a CartoDB configuration
+ * object.
+ * If using named maps, a key-value lookup with the template parameters.
+ * @api
+ */
+ol.source.CartoDB.prototype.setConfig = function(config) {
+ this.config_ = config || {};
+ this.initializeMap_();
+};
+
+
+/**
+ * Issue a request to initialize the CartoDB map.
+ * @private
+ */
+ol.source.CartoDB.prototype.initializeMap_ = function() {
+ var paramHash = JSON.stringify(this.config_);
+ if (this.templateCache_[paramHash]) {
+ this.applyTemplate_(this.templateCache_[paramHash]);
+ return;
+ }
+ var mapUrl = 'https://' + this.account_ + '.cartodb.com/api/v1/map';
+
+ if (this.mapId_) {
+ mapUrl += '/named/' + this.mapId_;
+ }
+
+ var client = new XMLHttpRequest();
+ client.addEventListener('load', this.handleInitResponse_.bind(this, paramHash));
+ client.addEventListener('error', this.handleInitError_.bind(this));
+ client.open('POST', mapUrl);
+ client.setRequestHeader('Content-type', 'application/json');
+ client.send(JSON.stringify(this.config_));
+};
+
+
+/**
+ * Handle map initialization response.
+ * @param {string} paramHash a hash representing the parameter set that was used
+ * for the request
+ * @param {Event} event Event.
+ * @private
+ */
+ol.source.CartoDB.prototype.handleInitResponse_ = function(paramHash, event) {
+ var client = /** @type {XMLHttpRequest} */ (event.target);
+ if (client.status >= 200 && client.status < 300) {
+ var response;
+ try {
+ response = /** @type {CartoDBLayerInfo} */(JSON.parse(client.responseText));
+ } catch (err) {
+ this.setState(ol.source.State.ERROR);
+ return;
+ }
+ this.applyTemplate_(response);
+ this.templateCache_[paramHash] = response;
+ this.setState(ol.source.State.READY);
+ } else {
+ this.setState(ol.source.State.ERROR);
+ }
+};
+
+
+/**
+ * @private
+ * @param {Event} event Event.
+ */
+ol.source.CartoDB.prototype.handleInitError_ = function(event) {
+ this.setState(ol.source.State.ERROR);
+};
+
+
+/**
+ * Apply the new tile urls returned by carto db
+ * @param {CartoDBLayerInfo} data Result of carto db call.
+ * @private
+ */
+ol.source.CartoDB.prototype.applyTemplate_ = function(data) {
+ var tilesUrl = 'https://' + data.cdn_url.https + '/' + this.account_ +
+ '/api/v1/map/' + data.layergroupid + '/{z}/{x}/{y}.png';
+ this.setUrl(tilesUrl);
+};
+
+// FIXME keep cluster cache by resolution ?
+// FIXME distance not respected because of the centroid
+
+goog.provide('ol.source.Cluster');
+
+goog.require('goog.asserts');
+goog.require('ol.Feature');
+goog.require('ol.coordinate');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.geom.Point');
+goog.require('ol.source.Vector');
+
+
+/**
+ * @classdesc
+ * Layer source to cluster vector data. Works out of the box with point
+ * geometries. For other geometry types, or if not all geometries should be
+ * considered for clustering, a custom `geometryFunction` can be defined.
+ *
+ * @constructor
+ * @param {olx.source.ClusterOptions} options Constructor options.
+ * @extends {ol.source.Vector}
+ * @api
+ */
+ol.source.Cluster = function(options) {
+ ol.source.Vector.call(this, {
+ attributions: options.attributions,
+ extent: options.extent,
+ logo: options.logo,
+ projection: options.projection,
+ wrapX: options.wrapX
+ });
+
+ /**
+ * @type {number|undefined}
+ * @private
+ */
+ this.resolution_ = undefined;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.distance_ = options.distance !== undefined ? options.distance : 20;
+
+ /**
+ * @type {Array.<ol.Feature>}
+ * @private
+ */
+ this.features_ = [];
+
+ /**
+ * @param {ol.Feature} feature Feature.
+ * @return {ol.geom.Point} Cluster calculation point.
+ */
+ this.geometryFunction_ = options.geometryFunction || function(feature) {
+ var geometry = feature.getGeometry();
+ goog.asserts.assert(geometry instanceof ol.geom.Point,
+ 'feature geometry is a ol.geom.Point instance');
+ return geometry;
+ };
+
+ /**
+ * @type {ol.source.Vector}
+ * @private
+ */
+ this.source_ = options.source;
+
+ this.source_.on(ol.events.EventType.CHANGE,
+ ol.source.Cluster.prototype.onSourceChange_, this);
+};
+ol.inherits(ol.source.Cluster, ol.source.Vector);
+
+
+/**
+ * Get a reference to the wrapped source.
+ * @return {ol.source.Vector} Source.
+ * @api
+ */
+ol.source.Cluster.prototype.getSource = function() {
+ return this.source_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.Cluster.prototype.loadFeatures = function(extent, resolution,
+ projection) {
+ this.source_.loadFeatures(extent, resolution, projection);
+ if (resolution !== this.resolution_) {
+ this.clear();
+ this.resolution_ = resolution;
+ this.cluster_();
+ this.addFeatures(this.features_);
+ }
+};
+
+
+/**
+ * handle the source changing
+ * @private
+ */
+ol.source.Cluster.prototype.onSourceChange_ = function() {
+ this.clear();
+ this.cluster_();
+ this.addFeatures(this.features_);
+ this.changed();
+};
+
+
+/**
+ * @private
+ */
+ol.source.Cluster.prototype.cluster_ = function() {
+ if (this.resolution_ === undefined) {
+ return;
+ }
+ this.features_.length = 0;
+ var extent = ol.extent.createEmpty();
+ var mapDistance = this.distance_ * this.resolution_;
+ var features = this.source_.getFeatures();
+
+ /**
+ * @type {!Object.<string, boolean>}
+ */
+ var clustered = {};
+
+ for (var i = 0, ii = features.length; i < ii; i++) {
+ var feature = features[i];
+ if (!(goog.getUid(feature).toString() in clustered)) {
+ var geometry = this.geometryFunction_(feature);
+ if (geometry) {
+ var coordinates = geometry.getCoordinates();
+ ol.extent.createOrUpdateFromCoordinate(coordinates, extent);
+ ol.extent.buffer(extent, mapDistance, extent);
+
+ var neighbors = this.source_.getFeaturesInExtent(extent);
+ goog.asserts.assert(neighbors.length >= 1, 'at least one neighbor found');
+ neighbors = neighbors.filter(function(neighbor) {
+ var uid = goog.getUid(neighbor).toString();
+ if (!(uid in clustered)) {
+ clustered[uid] = true;
+ return true;
+ } else {
+ return false;
+ }
+ });
+ this.features_.push(this.createCluster_(neighbors));
+ }
+ }
+ }
+ goog.asserts.assert(
+ Object.keys(clustered).length == this.source_.getFeatures().length,
+ 'number of clustered equals number of features in the source');
+};
+
+
+/**
+ * @param {Array.<ol.Feature>} features Features
+ * @return {ol.Feature} The cluster feature.
+ * @private
+ */
+ol.source.Cluster.prototype.createCluster_ = function(features) {
+ var centroid = [0, 0];
+ for (var i = features.length - 1; i >= 0; --i) {
+ var geometry = this.geometryFunction_(features[i]);
+ if (geometry) {
+ ol.coordinate.add(centroid, geometry.getCoordinates());
+ } else {
+ features.splice(i, 1);
+ }
+ }
+ ol.coordinate.scale(centroid, 1 / features.length);
+
+ var cluster = new ol.Feature(new ol.geom.Point(centroid));
+ cluster.set('features', features);
+ return cluster;
+};
+
+goog.provide('ol.uri');
+
+
+/**
+ * Appends query parameters to a URI.
+ *
+ * @param {string} uri The original URI, which may already have query data.
+ * @param {!Object} params An object where keys are URI-encoded parameter keys,
+ * and the values are arbitrary types or arrays.
+ * @return {string} The new URI.
+ */
+ol.uri.appendParams = function(uri, params) {
+ var qs = Object.keys(params).map(function(k) {
+ return k + '=' + encodeURIComponent(params[k]);
+ }).join('&');
+ // remove any trailing ? or &
+ uri = uri.replace(/[?&]$/, '');
+ // append ? or & depending on whether uri has existing parameters
+ uri = uri.indexOf('?') === -1 ? uri + '?' : uri + '&';
+ return uri + qs;
+};
+
+goog.provide('ol.source.ImageArcGISRest');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.Image');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.source.Image');
+goog.require('ol.uri');
+
+
+/**
+ * @classdesc
+ * Source for data from ArcGIS Rest services providing single, untiled images.
+ * Useful when underlying map service has labels.
+ *
+ * If underlying map service is not using labels,
+ * take advantage of ol image caching and use
+ * {@link ol.source.TileArcGISRest} data source.
+ *
+ * @constructor
+ * @fires ol.source.ImageEvent
+ * @extends {ol.source.Image}
+ * @param {olx.source.ImageArcGISRestOptions=} opt_options Image ArcGIS Rest Options.
+ * @api
+ */
+ol.source.ImageArcGISRest = function(opt_options) {
+
+ var options = opt_options || {};
+
+ ol.source.Image.call(this, {
+ attributions: options.attributions,
+ logo: options.logo,
+ projection: options.projection,
+ resolutions: options.resolutions
+ });
+
+ /**
+ * @private
+ * @type {?string}
+ */
+ this.crossOrigin_ =
+ options.crossOrigin !== undefined ? options.crossOrigin : null;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.url_ = options.url;
+
+ /**
+ * @private
+ * @type {ol.ImageLoadFunctionType}
+ */
+ this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?
+ options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
+
+
+ /**
+ * @private
+ * @type {!Object}
+ */
+ this.params_ = options.params || {};
+
+ /**
+ * @private
+ * @type {ol.Image}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.imageSize_ = [0, 0];
+
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
+
+};
+ol.inherits(ol.source.ImageArcGISRest, ol.source.Image);
+
+
+/**
+ * Get the user-provided params, i.e. those passed to the constructor through
+ * the "params" option, and possibly updated using the updateParams method.
+ * @return {Object} Params.
+ * @api stable
+ */
+ol.source.ImageArcGISRest.prototype.getParams = function() {
+ return this.params_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageArcGISRest.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
+
+ if (this.url_ === undefined) {
+ return null;
+ }
+
+ resolution = this.findNearestResolution(resolution);
+
+ var image = this.image_;
+ if (image &&
+ this.renderedRevision_ == this.getRevision() &&
+ image.getResolution() == resolution &&
+ image.getPixelRatio() == pixelRatio &&
+ ol.extent.containsExtent(image.getExtent(), extent)) {
+ return image;
+ }
+
+ var params = {
+ 'F': 'image',
+ 'FORMAT': 'PNG32',
+ 'TRANSPARENT': true
+ };
+ ol.object.assign(params, this.params_);
+
+ extent = extent.slice();
+ var centerX = (extent[0] + extent[2]) / 2;
+ var centerY = (extent[1] + extent[3]) / 2;
+ if (this.ratio_ != 1) {
+ var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2;
+ var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2;
+ extent[0] = centerX - halfWidth;
+ extent[1] = centerY - halfHeight;
+ extent[2] = centerX + halfWidth;
+ extent[3] = centerY + halfHeight;
+ }
+
+ var imageResolution = resolution / pixelRatio;
+
+ // Compute an integer width and height.
+ var width = Math.ceil(ol.extent.getWidth(extent) / imageResolution);
+ var height = Math.ceil(ol.extent.getHeight(extent) / imageResolution);
+
+ // Modify the extent to match the integer width and height.
+ extent[0] = centerX - imageResolution * width / 2;
+ extent[2] = centerX + imageResolution * width / 2;
+ extent[1] = centerY - imageResolution * height / 2;
+ extent[3] = centerY + imageResolution * height / 2;
+
+ this.imageSize_[0] = width;
+ this.imageSize_[1] = height;
+
+ var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio,
+ projection, params);
+
+ this.image_ = new ol.Image(extent, resolution, pixelRatio,
+ this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);
+
+ this.renderedRevision_ = this.getRevision();
+
+ ol.events.listen(this.image_, ol.events.EventType.CHANGE,
+ this.handleImageChange, this);
+
+ return this.image_;
+
+};
+
+
+/**
+ * Return the image load function of the source.
+ * @return {ol.ImageLoadFunctionType} The image load function.
+ * @api
+ */
+ol.source.ImageArcGISRest.prototype.getImageLoadFunction = function() {
+ return this.imageLoadFunction_;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {Object} params Params.
+ * @return {string} Request URL.
+ * @private
+ */
+ol.source.ImageArcGISRest.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {
+
+ goog.asserts.assert(this.url_ !== undefined, 'url is defined');
+
+ // ArcGIS Server only wants the numeric portion of the projection ID.
+ var srid = projection.getCode().split(':').pop();
+
+ params['SIZE'] = size[0] + ',' + size[1];
+ params['BBOX'] = extent.join(',');
+ params['BBOXSR'] = srid;
+ params['IMAGESR'] = srid;
+ params['DPI'] = 90 * pixelRatio;
+
+ var url = this.url_;
+
+ var modifiedUrl = url
+ .replace(/MapServer\/?$/, 'MapServer/export')
+ .replace(/ImageServer\/?$/, 'ImageServer/exportImage');
+ if (modifiedUrl == url) {
+ goog.asserts.fail('Unknown Rest Service', url);
+ }
+ return ol.uri.appendParams(modifiedUrl, params);
+};
+
+
+/**
+ * Return the URL used for this ArcGIS source.
+ * @return {string|undefined} URL.
+ * @api stable
+ */
+ol.source.ImageArcGISRest.prototype.getUrl = function() {
+ return this.url_;
+};
+
+
+/**
+ * Set the image load function of the source.
+ * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
+ * @api
+ */
+ol.source.ImageArcGISRest.prototype.setImageLoadFunction = function(imageLoadFunction) {
+ this.image_ = null;
+ this.imageLoadFunction_ = imageLoadFunction;
+ this.changed();
+};
+
+
+/**
+ * Set the URL to use for requests.
+ * @param {string|undefined} url URL.
+ * @api stable
+ */
+ol.source.ImageArcGISRest.prototype.setUrl = function(url) {
+ if (url != this.url_) {
+ this.url_ = url;
+ this.image_ = null;
+ this.changed();
+ }
+};
+
+
+/**
+ * Update the user-provided params.
+ * @param {Object} params Params.
+ * @api stable
+ */
+ol.source.ImageArcGISRest.prototype.updateParams = function(params) {
+ ol.object.assign(this.params_, params);
+ this.image_ = null;
+ this.changed();
+};
+
+goog.provide('ol.source.ImageMapGuide');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.Image');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.source.Image');
+goog.require('ol.uri');
+
+
+/**
+ * @classdesc
+ * Source for images from Mapguide servers
+ *
+ * @constructor
+ * @fires ol.source.ImageEvent
+ * @extends {ol.source.Image}
+ * @param {olx.source.ImageMapGuideOptions} options Options.
+ * @api stable
+ */
+ol.source.ImageMapGuide = function(options) {
+
+ ol.source.Image.call(this, {
+ projection: options.projection,
+ resolutions: options.resolutions
+ });
+
+ /**
+ * @private
+ * @type {?string}
+ */
+ this.crossOrigin_ =
+ options.crossOrigin !== undefined ? options.crossOrigin : null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.displayDpi_ = options.displayDpi !== undefined ?
+ options.displayDpi : 96;
+
+ /**
+ * @private
+ * @type {!Object}
+ */
+ this.params_ = options.params || {};
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.url_ = options.url;
+
+ /**
+ * @private
+ * @type {ol.ImageLoadFunctionType}
+ */
+ this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?
+ options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.metersPerUnit_ = options.metersPerUnit !== undefined ?
+ options.metersPerUnit : 1;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.ratio_ = options.ratio !== undefined ? options.ratio : 1;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.useOverlay_ = options.useOverlay !== undefined ?
+ options.useOverlay : false;
+
+ /**
+ * @private
+ * @type {ol.Image}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = 0;
+
+};
+ol.inherits(ol.source.ImageMapGuide, ol.source.Image);
+
+
+/**
+ * Get the user-provided params, i.e. those passed to the constructor through
+ * the "params" option, and possibly updated using the updateParams method.
+ * @return {Object} Params.
+ * @api stable
+ */
+ol.source.ImageMapGuide.prototype.getParams = function() {
+ return this.params_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageMapGuide.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
+ resolution = this.findNearestResolution(resolution);
+ pixelRatio = this.hidpi_ ? pixelRatio : 1;
+
+ var image = this.image_;
+ if (image &&
+ this.renderedRevision_ == this.getRevision() &&
+ image.getResolution() == resolution &&
+ image.getPixelRatio() == pixelRatio &&
+ ol.extent.containsExtent(image.getExtent(), extent)) {
+ return image;
+ }
+
+ if (this.ratio_ != 1) {
+ extent = extent.slice();
+ ol.extent.scaleFromCenter(extent, this.ratio_);
+ }
+ var width = ol.extent.getWidth(extent) / resolution;
+ var height = ol.extent.getHeight(extent) / resolution;
+ var size = [width * pixelRatio, height * pixelRatio];
+
+ if (this.url_ !== undefined) {
+ var imageUrl = this.getUrl(this.url_, this.params_, extent, size,
+ projection);
+ image = new ol.Image(extent, resolution, pixelRatio,
+ this.getAttributions(), imageUrl, this.crossOrigin_,
+ this.imageLoadFunction_);
+ ol.events.listen(image, ol.events.EventType.CHANGE,
+ this.handleImageChange, this);
+ } else {
+ image = null;
+ }
+ this.image_ = image;
+ this.renderedRevision_ = this.getRevision();
+
+ return image;
+};
+
+
+/**
+ * Return the image load function of the source.
+ * @return {ol.ImageLoadFunctionType} The image load function.
+ * @api
+ */
+ol.source.ImageMapGuide.prototype.getImageLoadFunction = function() {
+ return this.imageLoadFunction_;
+};
+
+
+/**
+ * @param {ol.Extent} extent The map extents.
+ * @param {ol.Size} size The viewport size.
+ * @param {number} metersPerUnit The meters-per-unit value.
+ * @param {number} dpi The display resolution.
+ * @return {number} The computed map scale.
+ */
+ol.source.ImageMapGuide.getScale = function(extent, size, metersPerUnit, dpi) {
+ var mcsW = ol.extent.getWidth(extent);
+ var mcsH = ol.extent.getHeight(extent);
+ var devW = size[0];
+ var devH = size[1];
+ var mpp = 0.0254 / dpi;
+ if (devH * mcsW > devW * mcsH) {
+ return mcsW * metersPerUnit / (devW * mpp); // width limited
+ } else {
+ return mcsH * metersPerUnit / (devH * mpp); // height limited
+ }
+};
+
+
+/**
+ * Update the user-provided params.
+ * @param {Object} params Params.
+ * @api stable
+ */
+ol.source.ImageMapGuide.prototype.updateParams = function(params) {
+ ol.object.assign(this.params_, params);
+ this.changed();
+};
+
+
+/**
+ * @param {string} baseUrl The mapagent url.
+ * @param {Object.<string, string|number>} params Request parameters.
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Size} size Size.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string} The mapagent map image request URL.
+ */
+ol.source.ImageMapGuide.prototype.getUrl = function(baseUrl, params, extent, size, projection) {
+ var scale = ol.source.ImageMapGuide.getScale(extent, size,
+ this.metersPerUnit_, this.displayDpi_);
+ var center = ol.extent.getCenter(extent);
+ var baseParams = {
+ 'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE',
+ 'VERSION': '2.0.0',
+ 'LOCALE': 'en',
+ 'CLIENTAGENT': 'ol.source.ImageMapGuide source',
+ 'CLIP': '1',
+ 'SETDISPLAYDPI': this.displayDpi_,
+ 'SETDISPLAYWIDTH': Math.round(size[0]),
+ 'SETDISPLAYHEIGHT': Math.round(size[1]),
+ 'SETVIEWSCALE': scale,
+ 'SETVIEWCENTERX': center[0],
+ 'SETVIEWCENTERY': center[1]
+ };
+ ol.object.assign(baseParams, params);
+ return ol.uri.appendParams(baseUrl, baseParams);
+};
+
+
+/**
+ * Set the image load function of the MapGuide source.
+ * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
+ * @api
+ */
+ol.source.ImageMapGuide.prototype.setImageLoadFunction = function(
+ imageLoadFunction) {
+ this.image_ = null;
+ this.imageLoadFunction_ = imageLoadFunction;
+ this.changed();
+};
+
+goog.provide('ol.source.ImageStatic');
+
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.Image');
+goog.require('ol.ImageState');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.proj');
+goog.require('ol.source.Image');
+
+
+/**
+ * @classdesc
+ * A layer source for displaying a single, static image.
+ *
+ * @constructor
+ * @extends {ol.source.Image}
+ * @param {olx.source.ImageStaticOptions} options Options.
+ * @api stable
+ */
+ol.source.ImageStatic = function(options) {
+ var imageExtent = options.imageExtent;
+
+ var crossOrigin = options.crossOrigin !== undefined ?
+ options.crossOrigin : null;
+
+ var /** @type {ol.ImageLoadFunctionType} */ imageLoadFunction =
+ options.imageLoadFunction !== undefined ?
+ options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
+
+ ol.source.Image.call(this, {
+ attributions: options.attributions,
+ logo: options.logo,
+ projection: ol.proj.get(options.projection)
+ });
+
+ /**
+ * @private
+ * @type {ol.Image}
+ */
+ this.image_ = new ol.Image(imageExtent, undefined, 1, this.getAttributions(),
+ options.url, crossOrigin, imageLoadFunction);
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.imageSize_ = options.imageSize ? options.imageSize : null;
+
+ ol.events.listen(this.image_, ol.events.EventType.CHANGE,
+ this.handleImageChange, this);
+
+};
+ol.inherits(ol.source.ImageStatic, ol.source.Image);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageStatic.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
+ if (ol.extent.intersects(extent, this.image_.getExtent())) {
+ return this.image_;
+ }
+ return null;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageStatic.prototype.handleImageChange = function(evt) {
+ if (this.image_.getState() == ol.ImageState.LOADED) {
+ var imageExtent = this.image_.getExtent();
+ var image = this.image_.getImage();
+ var imageWidth, imageHeight;
+ if (this.imageSize_) {
+ imageWidth = this.imageSize_[0];
+ imageHeight = this.imageSize_[1];
+ } else {
+ // TODO: remove the type cast when a closure-compiler > 20160315 is used.
+ // see: https://github.com/google/closure-compiler/pull/1664
+ imageWidth = /** @type {number} */ (image.width);
+ imageHeight = /** @type {number} */ (image.height);
+ }
+ var resolution = ol.extent.getHeight(imageExtent) / imageHeight;
+ var targetWidth = Math.ceil(ol.extent.getWidth(imageExtent) / resolution);
+ if (targetWidth != imageWidth) {
+ var context = ol.dom.createCanvasContext2D(targetWidth, imageHeight);
+ var canvas = context.canvas;
+ context.drawImage(image, 0, 0, imageWidth, imageHeight,
+ 0, 0, canvas.width, canvas.height);
+ this.image_.setImage(canvas);
+ }
+ }
+ ol.source.Image.prototype.handleImageChange.call(this, evt);
+};
+
+goog.provide('ol.source.wms');
+goog.provide('ol.source.wms.ServerType');
+
+
+/**
+ * Available server types: `'carmentaserver'`, `'geoserver'`, `'mapserver'`,
+ * `'qgis'`. These are servers that have vendor parameters beyond the WMS
+ * specification that OpenLayers can make use of.
+ * @enum {string}
+ */
+ol.source.wms.ServerType = {
+ CARMENTA_SERVER: 'carmentaserver',
+ GEOSERVER: 'geoserver',
+ MAPSERVER: 'mapserver',
+ QGIS: 'qgis'
+};
+
+// FIXME cannot be shared between maps with different projections
+
+goog.provide('ol.source.ImageWMS');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.Image');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.source.Image');
+goog.require('ol.source.wms');
+goog.require('ol.source.wms.ServerType');
+goog.require('ol.string');
+goog.require('ol.uri');
+
+
+/**
+ * @classdesc
+ * Source for WMS servers providing single, untiled images.
+ *
+ * @constructor
+ * @fires ol.source.ImageEvent
+ * @extends {ol.source.Image}
+ * @param {olx.source.ImageWMSOptions=} opt_options Options.
+ * @api stable
+ */
+ol.source.ImageWMS = function(opt_options) {
+
+ var options = opt_options || {};
+
+ ol.source.Image.call(this, {
+ attributions: options.attributions,
+ logo: options.logo,
+ projection: options.projection,
+ resolutions: options.resolutions
+ });
+
+ /**
+ * @private
+ * @type {?string}
+ */
+ this.crossOrigin_ =
+ options.crossOrigin !== undefined ? options.crossOrigin : null;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.url_ = options.url;
+
+ /**
+ * @private
+ * @type {ol.ImageLoadFunctionType}
+ */
+ this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?
+ options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
+
+ /**
+ * @private
+ * @type {!Object}
+ */
+ this.params_ = options.params || {};
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.v13_ = true;
+ this.updateV13_();
+
+ /**
+ * @private
+ * @type {ol.source.wms.ServerType|undefined}
+ */
+ this.serverType_ =
+ /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
+
+ /**
+ * @private
+ * @type {ol.Image}
+ */
+ this.image_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.imageSize_ = [0, 0];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.renderedRevision_ = 0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
+
+};
+ol.inherits(ol.source.ImageWMS, ol.source.Image);
+
+
+/**
+ * @const
+ * @type {ol.Size}
+ * @private
+ */
+ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101];
+
+
+/**
+ * Return the GetFeatureInfo URL for the passed coordinate, resolution, and
+ * projection. Return `undefined` if the GetFeatureInfo URL cannot be
+ * constructed.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} resolution Resolution.
+ * @param {ol.ProjectionLike} projection Projection.
+ * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
+ * be provided. If `QUERY_LAYERS` is not provided then the layers specified
+ * in the `LAYERS` parameter will be used. `VERSION` should not be
+ * specified here.
+ * @return {string|undefined} GetFeatureInfo URL.
+ * @api stable
+ */
+ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
+
+ goog.asserts.assert(!('VERSION' in params),
+ 'key VERSION is not allowed in params');
+
+ if (this.url_ === undefined) {
+ return undefined;
+ }
+
+ var extent = ol.extent.getForViewAndSize(
+ coordinate, resolution, 0,
+ ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_);
+
+ var baseParams = {
+ 'SERVICE': 'WMS',
+ 'VERSION': ol.DEFAULT_WMS_VERSION,
+ 'REQUEST': 'GetFeatureInfo',
+ 'FORMAT': 'image/png',
+ 'TRANSPARENT': true,
+ 'QUERY_LAYERS': this.params_['LAYERS']
+ };
+ ol.object.assign(baseParams, this.params_, params);
+
+ var x = Math.floor((coordinate[0] - extent[0]) / resolution);
+ var y = Math.floor((extent[3] - coordinate[1]) / resolution);
+ baseParams[this.v13_ ? 'I' : 'X'] = x;
+ baseParams[this.v13_ ? 'J' : 'Y'] = y;
+
+ return this.getRequestUrl_(
+ extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_,
+ 1, ol.proj.get(projection), baseParams);
+};
+
+
+/**
+ * Get the user-provided params, i.e. those passed to the constructor through
+ * the "params" option, and possibly updated using the updateParams method.
+ * @return {Object} Params.
+ * @api stable
+ */
+ol.source.ImageWMS.prototype.getParams = function() {
+ return this.params_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageWMS.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
+
+ if (this.url_ === undefined) {
+ return null;
+ }
+
+ resolution = this.findNearestResolution(resolution);
+
+ if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
+ pixelRatio = 1;
+ }
+
+ extent = extent.slice();
+ var centerX = (extent[0] + extent[2]) / 2;
+ var centerY = (extent[1] + extent[3]) / 2;
+
+ var imageResolution = resolution / pixelRatio;
+ var imageWidth = ol.extent.getWidth(extent) / imageResolution;
+ var imageHeight = ol.extent.getHeight(extent) / imageResolution;
+
+ var image = this.image_;
+ if (image &&
+ this.renderedRevision_ == this.getRevision() &&
+ image.getResolution() == resolution &&
+ image.getPixelRatio() == pixelRatio &&
+ ol.extent.containsExtent(image.getExtent(), extent)) {
+ return image;
+ }
+
+ if (this.ratio_ != 1) {
+ var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2;
+ var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2;
+ extent[0] = centerX - halfWidth;
+ extent[1] = centerY - halfHeight;
+ extent[2] = centerX + halfWidth;
+ extent[3] = centerY + halfHeight;
+ }
+
+ var params = {
+ 'SERVICE': 'WMS',
+ 'VERSION': ol.DEFAULT_WMS_VERSION,
+ 'REQUEST': 'GetMap',
+ 'FORMAT': 'image/png',
+ 'TRANSPARENT': true
+ };
+ ol.object.assign(params, this.params_);
+
+ this.imageSize_[0] = Math.ceil(imageWidth * this.ratio_);
+ this.imageSize_[1] = Math.ceil(imageHeight * this.ratio_);
+
+ var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio,
+ projection, params);
+
+ this.image_ = new ol.Image(extent, resolution, pixelRatio,
+ this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);
+
+ this.renderedRevision_ = this.getRevision();
+
+ ol.events.listen(this.image_, ol.events.EventType.CHANGE,
+ this.handleImageChange, this);
+
+ return this.image_;
+
+};
+
+
+/**
+ * Return the image load function of the source.
+ * @return {ol.ImageLoadFunctionType} The image load function.
+ * @api
+ */
+ol.source.ImageWMS.prototype.getImageLoadFunction = function() {
+ return this.imageLoadFunction_;
+};
+
+
+/**
+ * @param {ol.Extent} extent Extent.
+ * @param {ol.Size} size Size.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {Object} params Params.
+ * @return {string} Request URL.
+ * @private
+ */
+ol.source.ImageWMS.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {
+
+ goog.asserts.assert(this.url_ !== undefined, 'url is defined');
+
+ params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
+
+ if (!('STYLES' in this.params_)) {
+ params['STYLES'] = '';
+ }
+
+ if (pixelRatio != 1) {
+ switch (this.serverType_) {
+ case ol.source.wms.ServerType.GEOSERVER:
+ var dpi = (90 * pixelRatio + 0.5) | 0;
+ if ('FORMAT_OPTIONS' in params) {
+ params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
+ } else {
+ params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
+ }
+ break;
+ case ol.source.wms.ServerType.MAPSERVER:
+ params['MAP_RESOLUTION'] = 90 * pixelRatio;
+ break;
+ case ol.source.wms.ServerType.CARMENTA_SERVER:
+ case ol.source.wms.ServerType.QGIS:
+ params['DPI'] = 90 * pixelRatio;
+ break;
+ default:
+ goog.asserts.fail('unknown serverType configured');
+ break;
+ }
+ }
+
+ params['WIDTH'] = size[0];
+ params['HEIGHT'] = size[1];
+
+ var axisOrientation = projection.getAxisOrientation();
+ var bbox;
+ if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
+ bbox = [extent[1], extent[0], extent[3], extent[2]];
+ } else {
+ bbox = extent;
+ }
+ params['BBOX'] = bbox.join(',');
+
+ return ol.uri.appendParams(this.url_, params);
+};
+
+
+/**
+ * Return the URL used for this WMS source.
+ * @return {string|undefined} URL.
+ * @api stable
+ */
+ol.source.ImageWMS.prototype.getUrl = function() {
+ return this.url_;
+};
+
+
+/**
+ * Set the image load function of the source.
+ * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
+ * @api
+ */
+ol.source.ImageWMS.prototype.setImageLoadFunction = function(
+ imageLoadFunction) {
+ this.image_ = null;
+ this.imageLoadFunction_ = imageLoadFunction;
+ this.changed();
+};
+
+
+/**
+ * Set the URL to use for requests.
+ * @param {string|undefined} url URL.
+ * @api stable
+ */
+ol.source.ImageWMS.prototype.setUrl = function(url) {
+ if (url != this.url_) {
+ this.url_ = url;
+ this.image_ = null;
+ this.changed();
+ }
+};
+
+
+/**
+ * Update the user-provided params.
+ * @param {Object} params Params.
+ * @api stable
+ */
+ol.source.ImageWMS.prototype.updateParams = function(params) {
+ ol.object.assign(this.params_, params);
+ this.updateV13_();
+ this.image_ = null;
+ this.changed();
+};
+
+
+/**
+ * @private
+ */
+ol.source.ImageWMS.prototype.updateV13_ = function() {
+ var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;
+ this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;
+};
+
+goog.provide('ol.source.OSM');
+
+goog.require('ol.Attribution');
+goog.require('ol.source.XYZ');
+
+
+/**
+ * @classdesc
+ * Layer source for the OpenStreetMap tile server.
+ *
+ * @constructor
+ * @extends {ol.source.XYZ}
+ * @param {olx.source.OSMOptions=} opt_options Open Street Map options.
+ * @api stable
+ */
+ol.source.OSM = function(opt_options) {
+
+ var options = opt_options || {};
+
+ var attributions;
+ if (options.attributions !== undefined) {
+ attributions = options.attributions;
+ } else {
+ attributions = [ol.source.OSM.ATTRIBUTION];
+ }
+
+ var crossOrigin = options.crossOrigin !== undefined ?
+ options.crossOrigin : 'anonymous';
+
+ var url = options.url !== undefined ?
+ options.url : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png';
+
+ ol.source.XYZ.call(this, {
+ attributions: attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: crossOrigin,
+ opaque: options.opaque !== undefined ? options.opaque : true,
+ maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileLoadFunction: options.tileLoadFunction,
+ url: url,
+ wrapX: options.wrapX
+ });
+
+};
+ol.inherits(ol.source.OSM, ol.source.XYZ);
+
+
+/**
+ * The attribution containing a link to the OpenStreetMap Copyright and License
+ * page.
+ * @const
+ * @type {ol.Attribution}
+ * @api
+ */
+ol.source.OSM.ATTRIBUTION = new ol.Attribution({
+ html: '&copy; ' +
+ '<a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' +
+ 'contributors.'
+});
+
+goog.provide('ol.ext.pixelworks');
+/** @typedef {function(*)} */
+ol.ext.pixelworks;
+(function() {
+var exports = {};
+var module = {exports: exports};
+var define;
+/**
+ * @fileoverview
+ * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, uselessCode, visibility}
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixelworks = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+var Processor = _dereq_('./processor');
+
+exports.Processor = Processor;
+
+},{"./processor":2}],2:[function(_dereq_,module,exports){
+var newImageData = _dereq_('./util').newImageData;
+
+/**
+ * Create a function for running operations. This function is serialized for
+ * use in a worker.
+ * @param {function(Array, Object):*} operation The operation.
+ * @return {function(Object):ArrayBuffer} A function that takes an object with
+ * buffers, meta, imageOps, width, and height properties and returns an array
+ * buffer.
+ */
+function createMinion(operation) {
+ var workerHasImageData = true;
+ try {
+ new ImageData(10, 10);
+ } catch (_) {
+ workerHasImageData = false;
+ }
+
+ function newWorkerImageData(data, width, height) {
+ if (workerHasImageData) {
+ return new ImageData(data, width, height);
+ } else {
+ return {data: data, width: width, height: height};
+ }
+ }
+
+ return function(data) {
+ // bracket notation for minification support
+ var buffers = data['buffers'];
+ var meta = data['meta'];
+ var imageOps = data['imageOps'];
+ var width = data['width'];
+ var height = data['height'];
+
+ var numBuffers = buffers.length;
+ var numBytes = buffers[0].byteLength;
+ var output, b;
+
+ if (imageOps) {
+ var images = new Array(numBuffers);
+ for (b = 0; b < numBuffers; ++b) {
+ images[b] = newWorkerImageData(
+ new Uint8ClampedArray(buffers[b]), width, height);
+ }
+ output = operation(images, meta).data;
+ } else {
+ output = new Uint8ClampedArray(numBytes);
+ var arrays = new Array(numBuffers);
+ var pixels = new Array(numBuffers);
+ for (b = 0; b < numBuffers; ++b) {
+ arrays[b] = new Uint8ClampedArray(buffers[b]);
+ pixels[b] = [0, 0, 0, 0];
+ }
+ for (var i = 0; i < numBytes; i += 4) {
+ for (var j = 0; j < numBuffers; ++j) {
+ var array = arrays[j];
+ pixels[j][0] = array[i];
+ pixels[j][1] = array[i + 1];
+ pixels[j][2] = array[i + 2];
+ pixels[j][3] = array[i + 3];
+ }
+ var pixel = operation(pixels, meta);
+ output[i] = pixel[0];
+ output[i + 1] = pixel[1];
+ output[i + 2] = pixel[2];
+ output[i + 3] = pixel[3];
+ }
+ }
+ return output.buffer;
+ };
+}
+
+/**
+ * Create a worker for running operations.
+ * @param {Object} config Configuration.
+ * @param {function(MessageEvent)} onMessage Called with a message event.
+ * @return {Worker} The worker.
+ */
+function createWorker(config, onMessage) {
+ var lib = Object.keys(config.lib || {}).map(function(name) {
+ return 'var ' + name + ' = ' + config.lib[name].toString() + ';';
+ });
+
+ var lines = lib.concat([
+ 'var __minion__ = (' + createMinion.toString() + ')(', config.operation.toString(), ');',
+ 'self.addEventListener("message", function(event) {',
+ ' var buffer = __minion__(event.data);',
+ ' self.postMessage({buffer: buffer, meta: event.data.meta}, [buffer]);',
+ '});'
+ ]);
+
+ var blob = new Blob(lines, {type: 'text/javascript'});
+ var source = URL.createObjectURL(blob);
+ var worker = new Worker(source);
+ worker.addEventListener('message', onMessage);
+ return worker;
+}
+
+/**
+ * Create a faux worker for running operations.
+ * @param {Object} config Configuration.
+ * @param {function(MessageEvent)} onMessage Called with a message event.
+ * @return {Object} The faux worker.
+ */
+function createFauxWorker(config, onMessage) {
+ var minion = createMinion(config.operation);
+ return {
+ postMessage: function(data) {
+ setTimeout(function() {
+ onMessage({'data': {'buffer': minion(data), 'meta': data['meta']}});
+ }, 0);
+ }
+ };
+}
+
+/**
+ * A processor runs pixel or image operations in workers.
+ * @param {Object} config Configuration.
+ */
+function Processor(config) {
+ this._imageOps = !!config.imageOps;
+ var threads;
+ if (config.threads === 0) {
+ threads = 0;
+ } else if (this._imageOps) {
+ threads = 1;
+ } else {
+ threads = config.threads || 1;
+ }
+ var workers = [];
+ if (threads) {
+ for (var i = 0; i < threads; ++i) {
+ workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i));
+ }
+ } else {
+ workers[0] = createFauxWorker(config, this._onWorkerMessage.bind(this, 0));
+ }
+ this._workers = workers;
+ this._queue = [];
+ this._maxQueueLength = config.queue || Infinity;
+ this._running = 0;
+ this._dataLookup = {};
+ this._job = null;
+}
+
+/**
+ * Run operation on input data.
+ * @param {Array.<Array|ImageData>} inputs Array of pixels or image data
+ * (depending on the operation type).
+ * @param {Object} meta A user data object. This is passed to all operations
+ * and must be serializable.
+ * @param {function(Error, ImageData, Object)} callback Called when work
+ * completes. The first argument is any error. The second is the ImageData
+ * generated by operations. The third is the user data object.
+ */
+Processor.prototype.process = function(inputs, meta, callback) {
+ this._enqueue({
+ inputs: inputs,
+ meta: meta,
+ callback: callback
+ });
+ this._dispatch();
+};
+
+/**
+ * Stop responding to any completed work and destroy the processor.
+ */
+Processor.prototype.destroy = function() {
+ for (var key in this) {
+ this[key] = null;
+ }
+ this._destroyed = true;
+};
+
+/**
+ * Add a job to the queue.
+ * @param {Object} job The job.
+ */
+Processor.prototype._enqueue = function(job) {
+ this._queue.push(job);
+ while (this._queue.length > this._maxQueueLength) {
+ this._queue.shift().callback(null, null);
+ }
+};
+
+/**
+ * Dispatch a job.
+ */
+Processor.prototype._dispatch = function() {
+ if (this._running === 0 && this._queue.length > 0) {
+ var job = this._job = this._queue.shift();
+ var width = job.inputs[0].width;
+ var height = job.inputs[0].height;
+ var buffers = job.inputs.map(function(input) {
+ return input.data.buffer;
+ });
+ var threads = this._workers.length;
+ this._running = threads;
+ if (threads === 1) {
+ this._workers[0].postMessage({
+ 'buffers': buffers,
+ 'meta': job.meta,
+ 'imageOps': this._imageOps,
+ 'width': width,
+ 'height': height
+ }, buffers);
+ } else {
+ var length = job.inputs[0].data.length;
+ var segmentLength = 4 * Math.ceil(length / 4 / threads);
+ for (var i = 0; i < threads; ++i) {
+ var offset = i * segmentLength;
+ var slices = [];
+ for (var j = 0, jj = buffers.length; j < jj; ++j) {
+ slices.push(buffers[i].slice(offset, offset + segmentLength));
+ }
+ this._workers[i].postMessage({
+ 'buffers': slices,
+ 'meta': job.meta,
+ 'imageOps': this._imageOps,
+ 'width': width,
+ 'height': height
+ }, slices);
+ }
+ }
+ }
+};
+
+/**
+ * Handle messages from the worker.
+ * @param {number} index The worker index.
+ * @param {MessageEvent} event The message event.
+ */
+Processor.prototype._onWorkerMessage = function(index, event) {
+ if (this._destroyed) {
+ return;
+ }
+ this._dataLookup[index] = event.data;
+ --this._running;
+ if (this._running === 0) {
+ this._resolveJob();
+ }
+};
+
+/**
+ * Resolve a job. If there are no more worker threads, the processor callback
+ * will be called.
+ */
+Processor.prototype._resolveJob = function() {
+ var job = this._job;
+ var threads = this._workers.length;
+ var data, meta;
+ if (threads === 1) {
+ data = new Uint8ClampedArray(this._dataLookup[0]['buffer']);
+ meta = this._dataLookup[0]['meta'];
+ } else {
+ var length = job.inputs[0].data.length;
+ data = new Uint8ClampedArray(length);
+ meta = new Array(length);
+ var segmentLength = 4 * Math.ceil(length / 4 / threads);
+ for (var i = 0; i < threads; ++i) {
+ var buffer = this._dataLookup[i]['buffer'];
+ var offset = i * segmentLength;
+ data.set(new Uint8ClampedArray(buffer), offset);
+ meta[i] = this._dataLookup[i]['meta'];
+ }
+ }
+ this._job = null;
+ this._dataLookup = {};
+ job.callback(null,
+ newImageData(data, job.inputs[0].width, job.inputs[0].height), meta);
+ this._dispatch();
+};
+
+module.exports = Processor;
+
+},{"./util":3}],3:[function(_dereq_,module,exports){
+var hasImageData = true;
+try {
+ new ImageData(10, 10);
+} catch (_) {
+ hasImageData = false;
+}
+
+var context = document.createElement('canvas').getContext('2d');
+
+function newImageData(data, width, height) {
+ if (hasImageData) {
+ return new ImageData(data, width, height);
+ } else {
+ var imageData = context.createImageData(width, height);
+ imageData.data.set(data);
+ return imageData;
+ }
+}
+
+exports.newImageData = newImageData;
+
+},{}]},{},[1])(1)
+});
+ol.ext.pixelworks = module.exports;
+})();
+
+goog.provide('ol.RasterOperationType');
+goog.provide('ol.source.Raster');
+goog.provide('ol.source.RasterEvent');
+goog.provide('ol.source.RasterEventType');
+
+goog.require('goog.asserts');
+goog.require('goog.vec.Mat4');
+goog.require('ol.ImageCanvas');
+goog.require('ol.TileQueue');
+goog.require('ol.dom');
+goog.require('ol.events');
+goog.require('ol.events.Event');
+goog.require('ol.events.EventType');
+goog.require('ol.ext.pixelworks');
+goog.require('ol.extent');
+goog.require('ol.layer.Image');
+goog.require('ol.layer.Tile');
+goog.require('ol.object');
+goog.require('ol.renderer.canvas.ImageLayer');
+goog.require('ol.renderer.canvas.TileLayer');
+goog.require('ol.source.Image');
+goog.require('ol.source.State');
+goog.require('ol.source.Tile');
+
+
+/**
+ * Raster operation type. Supported values are `'pixel'` and `'image'`.
+ * @enum {string}
+ */
+ol.RasterOperationType = {
+ PIXEL: 'pixel',
+ IMAGE: 'image'
+};
+
+
+/**
+ * @classdesc
+ * A source that transforms data from any number of input sources using an array
+ * of {@link ol.RasterOperation} functions to transform input pixel values into
+ * output pixel values.
+ *
+ * @constructor
+ * @extends {ol.source.Image}
+ * @fires ol.source.RasterEvent
+ * @param {olx.source.RasterOptions} options Options.
+ * @api
+ */
+ol.source.Raster = function(options) {
+
+ /**
+ * @private
+ * @type {*}
+ */
+ this.worker_ = null;
+
+ /**
+ * @private
+ * @type {ol.RasterOperationType}
+ */
+ this.operationType_ = options.operationType !== undefined ?
+ options.operationType : ol.RasterOperationType.PIXEL;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.threads_ = options.threads !== undefined ? options.threads : 1;
+
+ /**
+ * @private
+ * @type {Array.<ol.renderer.canvas.Layer>}
+ */
+ this.renderers_ = ol.source.Raster.createRenderers_(options.sources);
+
+ for (var r = 0, rr = this.renderers_.length; r < rr; ++r) {
+ ol.events.listen(this.renderers_[r], ol.events.EventType.CHANGE,
+ this.changed, this);
+ }
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.canvasContext_ = ol.dom.createCanvasContext2D();
+
+ /**
+ * @private
+ * @type {ol.TileQueue}
+ */
+ this.tileQueue_ = new ol.TileQueue(
+ function() {
+ return 1;
+ },
+ this.changed.bind(this));
+
+ var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_);
+ var layerStates = {};
+ for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) {
+ layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];
+ }
+
+ /**
+ * The most recently rendered state.
+ * @type {?ol.SourceRasterRenderedState}
+ * @private
+ */
+ this.renderedState_ = null;
+
+ /**
+ * The most recently rendered image canvas.
+ * @type {ol.ImageCanvas}
+ * @private
+ */
+ this.renderedImageCanvas_ = null;
+
+ /**
+ * @private
+ * @type {olx.FrameState}
+ */
+ this.frameState_ = {
+ animate: false,
+ attributions: {},
+ coordinateToPixelMatrix: goog.vec.Mat4.createNumber(),
+ extent: null,
+ focus: null,
+ index: 0,
+ layerStates: layerStates,
+ layerStatesArray: layerStatesArray,
+ logos: {},
+ pixelRatio: 1,
+ pixelToCoordinateMatrix: goog.vec.Mat4.createNumber(),
+ postRenderFunctions: [],
+ size: [0, 0],
+ skippedFeatureUids: {},
+ tileQueue: this.tileQueue_,
+ time: Date.now(),
+ usedTiles: {},
+ viewState: /** @type {olx.ViewState} */ ({
+ rotation: 0
+ }),
+ viewHints: [],
+ wantedTiles: {}
+ };
+
+ ol.source.Image.call(this, {});
+
+ if (options.operation !== undefined) {
+ this.setOperation(options.operation, options.lib);
+ }
+
+};
+ol.inherits(ol.source.Raster, ol.source.Image);
+
+
+/**
+ * Set the operation.
+ * @param {ol.RasterOperation} operation New operation.
+ * @param {Object=} opt_lib Functions that will be available to operations run
+ * in a worker.
+ * @api
+ */
+ol.source.Raster.prototype.setOperation = function(operation, opt_lib) {
+ this.worker_ = new ol.ext.pixelworks.Processor({
+ operation: operation,
+ imageOps: this.operationType_ === ol.RasterOperationType.IMAGE,
+ queue: 1,
+ lib: opt_lib,
+ threads: this.threads_
+ });
+ this.changed();
+};
+
+
+/**
+ * Update the stored frame state.
+ * @param {ol.Extent} extent The view extent (in map units).
+ * @param {number} resolution The view resolution.
+ * @param {ol.proj.Projection} projection The view projection.
+ * @return {olx.FrameState} The updated frame state.
+ * @private
+ */
+ol.source.Raster.prototype.updateFrameState_ = function(extent, resolution, projection) {
+
+ var frameState = /** @type {olx.FrameState} */ (
+ ol.object.assign({}, this.frameState_));
+
+ frameState.viewState = /** @type {olx.ViewState} */ (
+ ol.object.assign({}, frameState.viewState));
+
+ var center = ol.extent.getCenter(extent);
+ var width = Math.round(ol.extent.getWidth(extent) / resolution);
+ var height = Math.round(ol.extent.getHeight(extent) / resolution);
+
+ frameState.extent = extent;
+ frameState.focus = ol.extent.getCenter(extent);
+ frameState.size[0] = width;
+ frameState.size[1] = height;
+
+ var viewState = frameState.viewState;
+ viewState.center = center;
+ viewState.projection = projection;
+ viewState.resolution = resolution;
+ return frameState;
+};
+
+
+/**
+ * Determine if the most recently rendered image canvas is dirty.
+ * @param {ol.Extent} extent The requested extent.
+ * @param {number} resolution The requested resolution.
+ * @return {boolean} The image is dirty.
+ * @private
+ */
+ol.source.Raster.prototype.isDirty_ = function(extent, resolution) {
+ var state = this.renderedState_;
+ return !state ||
+ this.getRevision() !== state.revision ||
+ resolution !== state.resolution ||
+ !ol.extent.equals(extent, state.extent);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.Raster.prototype.getImage = function(extent, resolution, pixelRatio, projection) {
+
+ if (!this.allSourcesReady_()) {
+ return null;
+ }
+
+ var currentExtent = extent.slice();
+ if (!this.isDirty_(currentExtent, resolution)) {
+ return this.renderedImageCanvas_;
+ }
+
+ var context = this.canvasContext_;
+ var canvas = context.canvas;
+
+ var width = Math.round(ol.extent.getWidth(currentExtent) / resolution);
+ var height = Math.round(ol.extent.getHeight(currentExtent) / resolution);
+
+ if (width !== canvas.width ||
+ height !== canvas.height) {
+ canvas.width = width;
+ canvas.height = height;
+ }
+
+ var frameState = this.updateFrameState_(currentExtent, resolution, projection);
+
+ var imageCanvas = new ol.ImageCanvas(
+ currentExtent, resolution, 1, this.getAttributions(), canvas,
+ this.composeFrame_.bind(this, frameState));
+
+ this.renderedImageCanvas_ = imageCanvas;
+
+ this.renderedState_ = {
+ extent: currentExtent,
+ resolution: resolution,
+ revision: this.getRevision()
+ };
+
+ return imageCanvas;
+};
+
+
+/**
+ * Determine if all sources are ready.
+ * @return {boolean} All sources are ready.
+ * @private
+ */
+ol.source.Raster.prototype.allSourcesReady_ = function() {
+ var ready = true;
+ var source;
+ for (var i = 0, ii = this.renderers_.length; i < ii; ++i) {
+ source = this.renderers_[i].getLayer().getSource();
+ if (source.getState() !== ol.source.State.READY) {
+ ready = false;
+ break;
+ }
+ }
+ return ready;
+};
+
+
+/**
+ * Compose the frame. This renders data from all sources, runs pixel-wise
+ * operations, and renders the result to the stored canvas context.
+ * @param {olx.FrameState} frameState The frame state.
+ * @param {function(Error)} callback Called when composition is complete.
+ * @private
+ */
+ol.source.Raster.prototype.composeFrame_ = function(frameState, callback) {
+ var len = this.renderers_.length;
+ var imageDatas = new Array(len);
+ for (var i = 0; i < len; ++i) {
+ var imageData = ol.source.Raster.getImageData_(
+ this.renderers_[i], frameState, frameState.layerStatesArray[i]);
+ if (imageData) {
+ imageDatas[i] = imageData;
+ } else {
+ // image not yet ready
+ return;
+ }
+ }
+
+ var data = {};
+ this.dispatchEvent(new ol.source.RasterEvent(
+ ol.source.RasterEventType.BEFOREOPERATIONS, frameState, data));
+
+ this.worker_.process(imageDatas, data,
+ this.onWorkerComplete_.bind(this, frameState, callback));
+
+ frameState.tileQueue.loadMoreTiles(16, 16);
+};
+
+
+/**
+ * Called when pixel processing is complete.
+ * @param {olx.FrameState} frameState The frame state.
+ * @param {function(Error)} callback Called when rendering is complete.
+ * @param {Error} err Any error during processing.
+ * @param {ImageData} output The output image data.
+ * @param {Object} data The user data.
+ * @private
+ */
+ol.source.Raster.prototype.onWorkerComplete_ = function(frameState, callback, err, output, data) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (!output) {
+ // job aborted
+ return;
+ }
+
+ this.dispatchEvent(new ol.source.RasterEvent(
+ ol.source.RasterEventType.AFTEROPERATIONS, frameState, data));
+
+ var resolution = frameState.viewState.resolution / frameState.pixelRatio;
+ if (!this.isDirty_(frameState.extent, resolution)) {
+ this.canvasContext_.putImageData(output, 0, 0);
+ }
+
+ callback(null);
+};
+
+
+/**
+ * Get image data from a renderer.
+ * @param {ol.renderer.canvas.Layer} renderer Layer renderer.
+ * @param {olx.FrameState} frameState The frame state.
+ * @param {ol.LayerState} layerState The layer state.
+ * @return {ImageData} The image data.
+ * @private
+ */
+ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) {
+ if (!renderer.prepareFrame(frameState, layerState)) {
+ return null;
+ }
+ var width = frameState.size[0];
+ var height = frameState.size[1];
+ if (!ol.source.Raster.context_) {
+ ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
+ } else {
+ var canvas = ol.source.Raster.context_.canvas;
+ if (canvas.width !== width || canvas.height !== height) {
+ ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
+ } else {
+ ol.source.Raster.context_.clearRect(0, 0, width, height);
+ }
+ }
+ renderer.composeFrame(frameState, layerState, ol.source.Raster.context_);
+ return ol.source.Raster.context_.getImageData(0, 0, width, height);
+};
+
+
+/**
+ * A reusable canvas context.
+ * @type {CanvasRenderingContext2D}
+ * @private
+ */
+ol.source.Raster.context_ = null;
+
+
+/**
+ * Get a list of layer states from a list of renderers.
+ * @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers.
+ * @return {Array.<ol.LayerState>} The layer states.
+ * @private
+ */
+ol.source.Raster.getLayerStatesArray_ = function(renderers) {
+ return renderers.map(function(renderer) {
+ return renderer.getLayer().getLayerState();
+ });
+};
+
+
+/**
+ * Create renderers for all sources.
+ * @param {Array.<ol.source.Source>} sources The sources.
+ * @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers.
+ * @private
+ */
+ol.source.Raster.createRenderers_ = function(sources) {
+ var len = sources.length;
+ var renderers = new Array(len);
+ for (var i = 0; i < len; ++i) {
+ renderers[i] = ol.source.Raster.createRenderer_(sources[i]);
+ }
+ return renderers;
+};
+
+
+/**
+ * Create a renderer for the provided source.
+ * @param {ol.source.Source} source The source.
+ * @return {ol.renderer.canvas.Layer} The renderer.
+ * @private
+ */
+ol.source.Raster.createRenderer_ = function(source) {
+ var renderer = null;
+ if (source instanceof ol.source.Tile) {
+ renderer = ol.source.Raster.createTileRenderer_(source);
+ } else if (source instanceof ol.source.Image) {
+ renderer = ol.source.Raster.createImageRenderer_(source);
+ } else {
+ goog.asserts.fail('Unsupported source type: ' + source);
+ }
+ return renderer;
+};
+
+
+/**
+ * Create an image renderer for the provided source.
+ * @param {ol.source.Image} source The source.
+ * @return {ol.renderer.canvas.Layer} The renderer.
+ * @private
+ */
+ol.source.Raster.createImageRenderer_ = function(source) {
+ var layer = new ol.layer.Image({source: source});
+ return new ol.renderer.canvas.ImageLayer(layer);
+};
+
+
+/**
+ * Create a tile renderer for the provided source.
+ * @param {ol.source.Tile} source The source.
+ * @return {ol.renderer.canvas.Layer} The renderer.
+ * @private
+ */
+ol.source.Raster.createTileRenderer_ = function(source) {
+ var layer = new ol.layer.Tile({source: source});
+ return new ol.renderer.canvas.TileLayer(layer);
+};
+
+
+/**
+ * @classdesc
+ * Events emitted by {@link ol.source.Raster} instances are instances of this
+ * type.
+ *
+ * @constructor
+ * @extends {ol.events.Event}
+ * @implements {oli.source.RasterEvent}
+ * @param {string} type Type.
+ * @param {olx.FrameState} frameState The frame state.
+ * @param {Object} data An object made available to operations.
+ */
+ol.source.RasterEvent = function(type, frameState, data) {
+ ol.events.Event.call(this, type);
+
+ /**
+ * The raster extent.
+ * @type {ol.Extent}
+ * @api
+ */
+ this.extent = frameState.extent;
+
+ /**
+ * The pixel resolution (map units per pixel).
+ * @type {number}
+ * @api
+ */
+ this.resolution = frameState.viewState.resolution / frameState.pixelRatio;
+
+ /**
+ * An object made available to all operations. This can be used by operations
+ * as a storage object (e.g. for calculating statistics).
+ * @type {Object}
+ * @api
+ */
+ this.data = data;
+
+};
+ol.inherits(ol.source.RasterEvent, ol.events.Event);
+
+
+/**
+ * @enum {string}
+ */
+ol.source.RasterEventType = {
+ /**
+ * Triggered before operations are run.
+ * @event ol.source.RasterEvent#beforeoperations
+ * @api
+ */
+ BEFOREOPERATIONS: 'beforeoperations',
+
+ /**
+ * Triggered after operations are run.
+ * @event ol.source.RasterEvent#afteroperations
+ * @api
+ */
+ AFTEROPERATIONS: 'afteroperations'
+};
+
+goog.provide('ol.source.Stamen');
+
+goog.require('goog.asserts');
+goog.require('ol.Attribution');
+goog.require('ol.source.OSM');
+goog.require('ol.source.XYZ');
+
+
+/**
+ * @type {Object.<string, {extension: string, opaque: boolean}>}
+ */
+ol.source.StamenLayerConfig = {
+ 'terrain': {
+ extension: 'jpg',
+ opaque: true
+ },
+ 'terrain-background': {
+ extension: 'jpg',
+ opaque: true
+ },
+ 'terrain-labels': {
+ extension: 'png',
+ opaque: false
+ },
+ 'terrain-lines': {
+ extension: 'png',
+ opaque: false
+ },
+ 'toner-background': {
+ extension: 'png',
+ opaque: true
+ },
+ 'toner': {
+ extension: 'png',
+ opaque: true
+ },
+ 'toner-hybrid': {
+ extension: 'png',
+ opaque: false
+ },
+ 'toner-labels': {
+ extension: 'png',
+ opaque: false
+ },
+ 'toner-lines': {
+ extension: 'png',
+ opaque: false
+ },
+ 'toner-lite': {
+ extension: 'png',
+ opaque: true
+ },
+ 'watercolor': {
+ extension: 'jpg',
+ opaque: true
+ }
+};
+
+
+/**
+ * @type {Object.<string, {minZoom: number, maxZoom: number}>}
+ */
+ol.source.StamenProviderConfig = {
+ 'terrain': {
+ minZoom: 4,
+ maxZoom: 18
+ },
+ 'toner': {
+ minZoom: 0,
+ maxZoom: 20
+ },
+ 'watercolor': {
+ minZoom: 1,
+ maxZoom: 16
+ }
+};
+
+
+/**
+ * @classdesc
+ * Layer source for the Stamen tile server.
+ *
+ * @constructor
+ * @extends {ol.source.XYZ}
+ * @param {olx.source.StamenOptions} options Stamen options.
+ * @api stable
+ */
+ol.source.Stamen = function(options) {
+
+ var i = options.layer.indexOf('-');
+ var provider = i == -1 ? options.layer : options.layer.slice(0, i);
+ goog.asserts.assert(provider in ol.source.StamenProviderConfig,
+ 'known provider configured');
+ var providerConfig = ol.source.StamenProviderConfig[provider];
+
+ goog.asserts.assert(options.layer in ol.source.StamenLayerConfig,
+ 'known layer configured');
+ var layerConfig = ol.source.StamenLayerConfig[options.layer];
+
+ var url = options.url !== undefined ? options.url :
+ 'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer +
+ '/{z}/{x}/{y}.' + layerConfig.extension;
+
+ ol.source.XYZ.call(this, {
+ attributions: ol.source.Stamen.ATTRIBUTIONS,
+ cacheSize: options.cacheSize,
+ crossOrigin: 'anonymous',
+ maxZoom: options.maxZoom != undefined ? options.maxZoom : providerConfig.maxZoom,
+ minZoom: options.minZoom != undefined ? options.minZoom : providerConfig.minZoom,
+ opaque: layerConfig.opaque,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileLoadFunction: options.tileLoadFunction,
+ url: url
+ });
+
+};
+ol.inherits(ol.source.Stamen, ol.source.XYZ);
+
+
+/**
+ * @const
+ * @type {Array.<ol.Attribution>}
+ */
+ol.source.Stamen.ATTRIBUTIONS = [
+ new ol.Attribution({
+ html: 'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, ' +
+ 'under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY' +
+ ' 3.0</a>.'
+ }),
+ ol.source.OSM.ATTRIBUTION
+];
+
+goog.provide('ol.source.TileArcGISRest');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.math');
+goog.require('ol.proj');
+goog.require('ol.size');
+goog.require('ol.source.TileImage');
+goog.require('ol.tilecoord');
+goog.require('ol.uri');
+
+
+/**
+ * @classdesc
+ * Layer source for tile data from ArcGIS Rest services. Map and Image
+ * Services are supported.
+ *
+ * For cached ArcGIS services, better performance is available using the
+ * {@link ol.source.XYZ} data source.
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.TileArcGISRestOptions=} opt_options Tile ArcGIS Rest
+ * options.
+ * @api
+ */
+ol.source.TileArcGISRest = function(opt_options) {
+
+ var options = opt_options || {};
+
+ ol.source.TileImage.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ logo: options.logo,
+ projection: options.projection,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileGrid: options.tileGrid,
+ tileLoadFunction: options.tileLoadFunction,
+ url: options.url,
+ urls: options.urls,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+ /**
+ * @private
+ * @type {!Object}
+ */
+ this.params_ = options.params || {};
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.tmpExtent_ = ol.extent.createEmpty();
+
+};
+ol.inherits(ol.source.TileArcGISRest, ol.source.TileImage);
+
+
+/**
+ * Get the user-provided params, i.e. those passed to the constructor through
+ * the "params" option, and possibly updated using the updateParams method.
+ * @return {Object} Params.
+ * @api
+ */
+ol.source.TileArcGISRest.prototype.getParams = function() {
+ return this.params_;
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.Size} tileSize Tile size.
+ * @param {ol.Extent} tileExtent Tile extent.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {Object} params Params.
+ * @return {string|undefined} Request URL.
+ * @private
+ */
+ol.source.TileArcGISRest.prototype.getRequestUrl_ = function(tileCoord, tileSize, tileExtent,
+ pixelRatio, projection, params) {
+
+ var urls = this.urls;
+ if (!urls) {
+ return undefined;
+ }
+
+ // ArcGIS Server only wants the numeric portion of the projection ID.
+ var srid = projection.getCode().split(':').pop();
+
+ params['SIZE'] = tileSize[0] + ',' + tileSize[1];
+ params['BBOX'] = tileExtent.join(',');
+ params['BBOXSR'] = srid;
+ params['IMAGESR'] = srid;
+ params['DPI'] = Math.round(
+ params['DPI'] ? params['DPI'] * pixelRatio : 90 * pixelRatio
+ );
+
+ var url;
+ if (urls.length == 1) {
+ url = urls[0];
+ } else {
+ var index = ol.math.modulo(ol.tilecoord.hash(tileCoord), urls.length);
+ url = urls[index];
+ }
+
+ var modifiedUrl = url
+ .replace(/MapServer\/?$/, 'MapServer/export')
+ .replace(/ImageServer\/?$/, 'ImageServer/exportImage');
+ if (modifiedUrl == url) {
+ goog.asserts.fail('Unknown Rest Service', url);
+ }
+ return ol.uri.appendParams(modifiedUrl, params);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileArcGISRest.prototype.getTilePixelRatio = function(pixelRatio) {
+ return pixelRatio;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileArcGISRest.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {
+
+ var tileGrid = this.getTileGrid();
+ if (!tileGrid) {
+ tileGrid = this.getTileGridForProjection(projection);
+ }
+
+ if (tileGrid.getResolutions().length <= tileCoord[0]) {
+ return undefined;
+ }
+
+ var tileExtent = tileGrid.getTileCoordExtent(
+ tileCoord, this.tmpExtent_);
+ var tileSize = ol.size.toSize(
+ tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
+
+ if (pixelRatio != 1) {
+ tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);
+ }
+
+ // Apply default params and override with user specified values.
+ var baseParams = {
+ 'F': 'image',
+ 'FORMAT': 'PNG32',
+ 'TRANSPARENT': true
+ };
+ ol.object.assign(baseParams, this.params_);
+
+ return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
+ pixelRatio, projection, baseParams);
+};
+
+
+/**
+ * Update the user-provided params.
+ * @param {Object} params Params.
+ * @api stable
+ */
+ol.source.TileArcGISRest.prototype.updateParams = function(params) {
+ ol.object.assign(this.params_, params);
+ this.changed();
+};
+
+goog.provide('ol.source.TileDebug');
+
+goog.require('ol.Tile');
+goog.require('ol.TileState');
+goog.require('ol.dom');
+goog.require('ol.size');
+goog.require('ol.source.Tile');
+
+
+/**
+ * @constructor
+ * @extends {ol.Tile}
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.Size} tileSize Tile size.
+ * @param {string} text Text.
+ * @private
+ */
+ol.DebugTile_ = function(tileCoord, tileSize, text) {
+
+ ol.Tile.call(this, tileCoord, ol.TileState.LOADED);
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.tileSize_ = tileSize;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.text_ = text;
+
+ /**
+ * @private
+ * @type {Object.<number, HTMLCanvasElement>}
+ */
+ this.canvasByContext_ = {};
+
+};
+ol.inherits(ol.DebugTile_, ol.Tile);
+
+
+/**
+ * Get the image element for this tile.
+ * @param {Object=} opt_context Optional context. Only used by the DOM
+ * renderer.
+ * @return {HTMLCanvasElement} Image.
+ */
+ol.DebugTile_.prototype.getImage = function(opt_context) {
+ var key = opt_context !== undefined ? goog.getUid(opt_context) : -1;
+ if (key in this.canvasByContext_) {
+ return this.canvasByContext_[key];
+ } else {
+
+ var tileSize = this.tileSize_;
+ var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]);
+
+ context.strokeStyle = 'black';
+ context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5);
+
+ context.fillStyle = 'black';
+ context.textAlign = 'center';
+ context.textBaseline = 'middle';
+ context.font = '24px sans-serif';
+ context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2);
+
+ this.canvasByContext_[key] = context.canvas;
+ return context.canvas;
+
+ }
+};
+
+
+/**
+ * @classdesc
+ * A pseudo tile source, which does not fetch tiles from a server, but renders
+ * a grid outline for the tile grid/projection along with the coordinates for
+ * each tile. See examples/canvas-tiles for an example.
+ *
+ * Uses Canvas context2d, so requires Canvas support.
+ *
+ * @constructor
+ * @extends {ol.source.Tile}
+ * @param {olx.source.TileDebugOptions} options Debug tile options.
+ * @api
+ */
+ol.source.TileDebug = function(options) {
+
+ ol.source.Tile.call(this, {
+ opaque: false,
+ projection: options.projection,
+ tileGrid: options.tileGrid,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+};
+ol.inherits(ol.source.TileDebug, ol.source.Tile);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileDebug.prototype.getTile = function(z, x, y) {
+ var tileCoordKey = this.getKeyZXY(z, x, y);
+ if (this.tileCache.containsKey(tileCoordKey)) {
+ return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey));
+ } else {
+ var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
+ var tileCoord = [z, x, y];
+ var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord);
+ var text = !textTileCoord ? '' :
+ this.getTileCoordForTileUrlFunction(textTileCoord).toString();
+ var tile = new ol.DebugTile_(tileCoord, tileSize, text);
+ this.tileCache.set(tileCoordKey, tile);
+ return tile;
+ }
+};
+
+// FIXME check order of async callbacks
+
+/**
+ * @see http://mapbox.com/developers/api/
+ */
+
+goog.provide('ol.source.TileJSON');
+goog.provide('ol.tilejson');
+
+goog.require('goog.asserts');
+goog.require('ol.Attribution');
+goog.require('ol.TileRange');
+goog.require('ol.TileUrlFunction');
+goog.require('ol.extent');
+goog.require('ol.net');
+goog.require('ol.proj');
+goog.require('ol.source.State');
+goog.require('ol.source.TileImage');
+
+
+/**
+ * @classdesc
+ * Layer source for tile data in TileJSON format.
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.TileJSONOptions} options TileJSON options.
+ * @api stable
+ */
+ol.source.TileJSON = function(options) {
+
+ /**
+ * @type {TileJSON}
+ * @private
+ */
+ this.tileJSON_ = null;
+
+ ol.source.TileImage.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ projection: ol.proj.get('EPSG:3857'),
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ state: ol.source.State.LOADING,
+ tileLoadFunction: options.tileLoadFunction,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+ if (options.jsonp) {
+ ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),
+ this.handleTileJSONError.bind(this));
+ } else {
+ var client = new XMLHttpRequest();
+ client.addEventListener('load', this.onXHRLoad_.bind(this));
+ client.addEventListener('error', this.onXHRError_.bind(this));
+ client.open('GET', options.url);
+ client.send();
+ }
+
+};
+ol.inherits(ol.source.TileJSON, ol.source.TileImage);
+
+
+/**
+ * @private
+ * @param {Event} event The load event.
+ */
+ol.source.TileJSON.prototype.onXHRLoad_ = function(event) {
+ var client = /** @type {XMLHttpRequest} */ (event.target);
+ if (client.status >= 200 && client.status < 300) {
+ var response;
+ try {
+ response = /** @type {TileJSON} */(JSON.parse(client.responseText));
+ } catch (err) {
+ this.handleTileJSONError();
+ return;
+ }
+ this.handleTileJSONResponse(response);
+ } else {
+ this.handleTileJSONError();
+ }
+};
+
+
+/**
+ * @private
+ * @param {Event} event The error event.
+ */
+ol.source.TileJSON.prototype.onXHRError_ = function(event) {
+ this.handleTileJSONError();
+};
+
+
+/**
+ * @return {TileJSON} The tilejson object.
+ * @api
+ */
+ol.source.TileJSON.prototype.getTileJSON = function() {
+ return this.tileJSON_;
+};
+
+
+/**
+ * @protected
+ * @param {TileJSON} tileJSON Tile JSON.
+ */
+ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
+
+ var epsg4326Projection = ol.proj.get('EPSG:4326');
+
+ var sourceProjection = this.getProjection();
+ var extent;
+ if (tileJSON.bounds !== undefined) {
+ var transform = ol.proj.getTransformFromProjections(
+ epsg4326Projection, sourceProjection);
+ extent = ol.extent.applyTransform(tileJSON.bounds, transform);
+ }
+
+ if (tileJSON.scheme !== undefined) {
+ goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"');
+ }
+ var minZoom = tileJSON.minzoom || 0;
+ var maxZoom = tileJSON.maxzoom || 22;
+ var tileGrid = ol.tilegrid.createXYZ({
+ extent: ol.tilegrid.extentFromProjection(sourceProjection),
+ maxZoom: maxZoom,
+ minZoom: minZoom
+ });
+ this.tileGrid = tileGrid;
+
+ this.tileUrlFunction =
+ ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid);
+
+ if (tileJSON.attribution !== undefined && !this.getAttributions()) {
+ var attributionExtent = extent !== undefined ?
+ extent : epsg4326Projection.getExtent();
+ /** @type {Object.<string, Array.<ol.TileRange>>} */
+ var tileRanges = {};
+ var z, zKey;
+ for (z = minZoom; z <= maxZoom; ++z) {
+ zKey = z.toString();
+ tileRanges[zKey] =
+ [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];
+ }
+ this.setAttributions([
+ new ol.Attribution({
+ html: tileJSON.attribution,
+ tileRanges: tileRanges
+ })
+ ]);
+ }
+ this.tileJSON_ = tileJSON;
+ this.setState(ol.source.State.READY);
+
+};
+
+
+/**
+ * @protected
+ */
+ol.source.TileJSON.prototype.handleTileJSONError = function() {
+ this.setState(ol.source.State.ERROR);
+};
+
+goog.provide('ol.source.TileUTFGrid');
+
+goog.require('goog.asserts');
+goog.require('goog.async.nextTick');
+goog.require('ol.Attribution');
+goog.require('ol.Tile');
+goog.require('ol.TileState');
+goog.require('ol.TileUrlFunction');
+goog.require('ol.events');
+goog.require('ol.events.EventType');
+goog.require('ol.extent');
+goog.require('ol.net');
+goog.require('ol.proj');
+goog.require('ol.source.State');
+goog.require('ol.source.Tile');
+
+
+/**
+ * @classdesc
+ * Layer source for UTFGrid interaction data loaded from TileJSON format.
+ *
+ * @constructor
+ * @extends {ol.source.Tile}
+ * @param {olx.source.TileUTFGridOptions} options Source options.
+ * @api
+ */
+ol.source.TileUTFGrid = function(options) {
+ ol.source.Tile.call(this, {
+ projection: ol.proj.get('EPSG:3857'),
+ state: ol.source.State.LOADING
+ });
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.preemptive_ = options.preemptive !== undefined ?
+ options.preemptive : true;
+
+ /**
+ * @private
+ * @type {!ol.TileUrlFunctionType}
+ */
+ this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction;
+
+ /**
+ * @private
+ * @type {string|undefined}
+ */
+ this.template_ = undefined;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.jsonp_ = options.jsonp || false;
+
+ if (options.url) {
+ if (this.jsonp_) {
+ ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),
+ this.handleTileJSONError.bind(this));
+ } else {
+ var client = new XMLHttpRequest();
+ client.addEventListener('load', this.onXHRLoad_.bind(this));
+ client.addEventListener('error', this.onXHRError_.bind(this));
+ client.open('GET', options.url);
+ client.send();
+ }
+ } else if (options.tileJSON) {
+ this.handleTileJSONResponse(options.tileJSON);
+ } else {
+ goog.asserts.fail('Either url or tileJSON options must be provided');
+ }
+};
+ol.inherits(ol.source.TileUTFGrid, ol.source.Tile);
+
+
+/**
+ * @private
+ * @param {Event} event The load event.
+ */
+ol.source.TileUTFGrid.prototype.onXHRLoad_ = function(event) {
+ var client = /** @type {XMLHttpRequest} */ (event.target);
+ if (client.status >= 200 && client.status < 300) {
+ var response;
+ try {
+ response = /** @type {TileJSON} */(JSON.parse(client.responseText));
+ } catch (err) {
+ this.handleTileJSONError();
+ return;
+ }
+ this.handleTileJSONResponse(response);
+ } else {
+ this.handleTileJSONError();
+ }
+};
+
+
+/**
+ * @private
+ * @param {Event} event The error event.
+ */
+ol.source.TileUTFGrid.prototype.onXHRError_ = function(event) {
+ this.handleTileJSONError();
+};
+
+
+/**
+ * Return the template from TileJSON.
+ * @return {string|undefined} The template from TileJSON.
+ * @api
+ */
+ol.source.TileUTFGrid.prototype.getTemplate = function() {
+ return this.template_;
+};
+
+
+/**
+ * Calls the callback (synchronously by default) with the available data
+ * for given coordinate and resolution (or `null` if not yet loaded or
+ * in case of an error).
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} resolution Resolution.
+ * @param {function(this: T, *)} callback Callback.
+ * @param {T=} opt_this The object to use as `this` in the callback.
+ * @param {boolean=} opt_request If `true` the callback is always async.
+ * The tile data is requested if not yet loaded.
+ * @template T
+ * @api
+ */
+ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function(
+ coordinate, resolution, callback, opt_this, opt_request) {
+ if (this.tileGrid) {
+ var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution(
+ coordinate, resolution);
+ var tile = /** @type {!ol.source.TileUTFGridTile_} */(this.getTile(
+ tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection()));
+ tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request);
+ } else {
+ if (opt_request === true) {
+ goog.async.nextTick(function() {
+ callback.call(opt_this, null);
+ });
+ } else {
+ callback.call(opt_this, null);
+ }
+ }
+};
+
+
+/**
+ * @protected
+ */
+ol.source.TileUTFGrid.prototype.handleTileJSONError = function() {
+ this.setState(ol.source.State.ERROR);
+};
+
+
+/**
+ * TODO: very similar to ol.source.TileJSON#handleTileJSONResponse
+ * @protected
+ * @param {TileJSON} tileJSON Tile JSON.
+ */
+ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
+
+ var epsg4326Projection = ol.proj.get('EPSG:4326');
+
+ var sourceProjection = this.getProjection();
+ var extent;
+ if (tileJSON.bounds !== undefined) {
+ var transform = ol.proj.getTransformFromProjections(
+ epsg4326Projection, sourceProjection);
+ extent = ol.extent.applyTransform(tileJSON.bounds, transform);
+ }
+
+ if (tileJSON.scheme !== undefined) {
+ goog.asserts.assert(tileJSON.scheme == 'xyz', 'tileJSON-scheme is "xyz"');
+ }
+ var minZoom = tileJSON.minzoom || 0;
+ var maxZoom = tileJSON.maxzoom || 22;
+ var tileGrid = ol.tilegrid.createXYZ({
+ extent: ol.tilegrid.extentFromProjection(sourceProjection),
+ maxZoom: maxZoom,
+ minZoom: minZoom
+ });
+ this.tileGrid = tileGrid;
+
+ this.template_ = tileJSON.template;
+
+ var grids = tileJSON.grids;
+ if (!grids) {
+ this.setState(ol.source.State.ERROR);
+ return;
+ }
+
+ this.tileUrlFunction_ =
+ ol.TileUrlFunction.createFromTemplates(grids, tileGrid);
+
+ if (tileJSON.attribution !== undefined) {
+ var attributionExtent = extent !== undefined ?
+ extent : epsg4326Projection.getExtent();
+ /** @type {Object.<string, Array.<ol.TileRange>>} */
+ var tileRanges = {};
+ var z, zKey;
+ for (z = minZoom; z <= maxZoom; ++z) {
+ zKey = z.toString();
+ tileRanges[zKey] =
+ [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];
+ }
+ this.setAttributions([
+ new ol.Attribution({
+ html: tileJSON.attribution,
+ tileRanges: tileRanges
+ })
+ ]);
+ }
+
+ this.setState(ol.source.State.READY);
+
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileUTFGrid.prototype.getTile = function(z, x, y, pixelRatio, projection) {
+ var tileCoordKey = this.getKeyZXY(z, x, y);
+ if (this.tileCache.containsKey(tileCoordKey)) {
+ return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
+ } else {
+ goog.asserts.assert(projection, 'argument projection is truthy');
+ var tileCoord = [z, x, y];
+ var urlTileCoord =
+ this.getTileCoordForTileUrlFunction(tileCoord, projection);
+ var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection);
+ var tile = new ol.source.TileUTFGridTile_(
+ tileCoord,
+ tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
+ tileUrl !== undefined ? tileUrl : '',
+ this.tileGrid.getTileCoordExtent(tileCoord),
+ this.preemptive_,
+ this.jsonp_);
+ this.tileCache.set(tileCoordKey, tile);
+ return tile;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) {
+ var tileCoordKey = this.getKeyZXY(z, x, y);
+ if (this.tileCache.containsKey(tileCoordKey)) {
+ this.tileCache.get(tileCoordKey);
+ }
+};
+
+
+/**
+ * @constructor
+ * @extends {ol.Tile}
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.TileState} state State.
+ * @param {string} src Image source URI.
+ * @param {ol.Extent} extent Extent of the tile.
+ * @param {boolean} preemptive Load the tile when visible (before it's needed).
+ * @param {boolean} jsonp Load the tile as a script.
+ * @private
+ */
+ol.source.TileUTFGridTile_ = function(tileCoord, state, src, extent, preemptive, jsonp) {
+
+ ol.Tile.call(this, tileCoord, state);
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.src_ = src;
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.extent_ = extent;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.preemptive_ = preemptive;
+
+ /**
+ * @private
+ * @type {Array.<string>}
+ */
+ this.grid_ = null;
+
+ /**
+ * @private
+ * @type {Array.<string>}
+ */
+ this.keys_ = null;
+
+ /**
+ * @private
+ * @type {Object.<string, Object>|undefined}
+ */
+ this.data_ = null;
+
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.jsonp_ = jsonp;
+
+};
+ol.inherits(ol.source.TileUTFGridTile_, ol.Tile);
+
+
+/**
+ * Get the image element for this tile.
+ * @param {Object=} opt_context Optional context. Only used for the DOM
+ * renderer.
+ * @return {Image} Image.
+ */
+ol.source.TileUTFGridTile_.prototype.getImage = function(opt_context) {
+ return null;
+};
+
+
+/**
+ * Synchronously returns data at given coordinate (if available).
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @return {*} The data.
+ */
+ol.source.TileUTFGridTile_.prototype.getData = function(coordinate) {
+ if (!this.grid_ || !this.keys_) {
+ return null;
+ }
+ var xRelative = (coordinate[0] - this.extent_[0]) /
+ (this.extent_[2] - this.extent_[0]);
+ var yRelative = (coordinate[1] - this.extent_[1]) /
+ (this.extent_[3] - this.extent_[1]);
+
+ var row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)];
+
+ if (typeof row !== 'string') {
+ return null;
+ }
+
+ var code = row.charCodeAt(Math.floor(xRelative * row.length));
+ if (code >= 93) {
+ code--;
+ }
+ if (code >= 35) {
+ code--;
+ }
+ code -= 32;
+
+ var data = null;
+ if (code in this.keys_) {
+ var id = this.keys_[code];
+ if (this.data_ && id in this.data_) {
+ data = this.data_[id];
+ } else {
+ data = id;
+ }
+ }
+ return data;
+};
+
+
+/**
+ * Calls the callback (synchronously by default) with the available data
+ * for given coordinate (or `null` if not yet loaded).
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {function(this: T, *)} callback Callback.
+ * @param {T=} opt_this The object to use as `this` in the callback.
+ * @param {boolean=} opt_request If `true` the callback is always async.
+ * The tile data is requested if not yet loaded.
+ * @template T
+ */
+ol.source.TileUTFGridTile_.prototype.forDataAtCoordinate = function(coordinate, callback, opt_this, opt_request) {
+ if (this.state == ol.TileState.IDLE && opt_request === true) {
+ ol.events.listenOnce(this, ol.events.EventType.CHANGE, function(e) {
+ callback.call(opt_this, this.getData(coordinate));
+ }, this);
+ this.loadInternal_();
+ } else {
+ if (opt_request === true) {
+ goog.async.nextTick(function() {
+ callback.call(opt_this, this.getData(coordinate));
+ }, this);
+ } else {
+ callback.call(opt_this, this.getData(coordinate));
+ }
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileUTFGridTile_.prototype.getKey = function() {
+ return this.src_;
+};
+
+
+/**
+ * @private
+ */
+ol.source.TileUTFGridTile_.prototype.handleError_ = function() {
+ this.state = ol.TileState.ERROR;
+ this.changed();
+};
+
+
+/**
+ * @param {!UTFGridJSON} json UTFGrid data.
+ * @private
+ */
+ol.source.TileUTFGridTile_.prototype.handleLoad_ = function(json) {
+ this.grid_ = json.grid;
+ this.keys_ = json.keys;
+ this.data_ = json.data;
+
+ this.state = ol.TileState.EMPTY;
+ this.changed();
+};
+
+
+/**
+ * @private
+ */
+ol.source.TileUTFGridTile_.prototype.loadInternal_ = function() {
+ if (this.state == ol.TileState.IDLE) {
+ this.state = ol.TileState.LOADING;
+ if (this.jsonp_) {
+ ol.net.jsonp(this.src_, this.handleLoad_.bind(this),
+ this.handleError_.bind(this));
+ } else {
+ var client = new XMLHttpRequest();
+ client.addEventListener('load', this.onXHRLoad_.bind(this));
+ client.addEventListener('error', this.onXHRError_.bind(this));
+ client.open('GET', this.src_);
+ client.send();
+ }
+ }
+};
+
+
+/**
+ * @private
+ * @param {Event} event The load event.
+ */
+ol.source.TileUTFGridTile_.prototype.onXHRLoad_ = function(event) {
+ var client = /** @type {XMLHttpRequest} */ (event.target);
+ if (client.status >= 200 && client.status < 300) {
+ var response;
+ try {
+ response = /** @type {!UTFGridJSON} */(JSON.parse(client.responseText));
+ } catch (err) {
+ this.handleError_();
+ return;
+ }
+ this.handleLoad_(response);
+ } else {
+ this.handleError_();
+ }
+};
+
+
+/**
+ * @private
+ * @param {Event} event The error event.
+ */
+ol.source.TileUTFGridTile_.prototype.onXHRError_ = function(event) {
+ this.handleError_();
+};
+
+
+/**
+ * Load not yet loaded URI.
+ */
+ol.source.TileUTFGridTile_.prototype.load = function() {
+ if (this.preemptive_) {
+ this.loadInternal_();
+ }
+};
+
+// FIXME add minZoom support
+// FIXME add date line wrap (tile coord transform)
+// FIXME cannot be shared between maps with different projections
+
+goog.provide('ol.source.TileWMS');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.math');
+goog.require('ol.proj');
+goog.require('ol.size');
+goog.require('ol.source.TileImage');
+goog.require('ol.source.wms');
+goog.require('ol.source.wms.ServerType');
+goog.require('ol.tilecoord');
+goog.require('ol.string');
+goog.require('ol.uri');
+
+/**
+ * @classdesc
+ * Layer source for tile data from WMS servers.
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.TileWMSOptions=} opt_options Tile WMS options.
+ * @api stable
+ */
+ol.source.TileWMS = function(opt_options) {
+
+ var options = opt_options || {};
+
+ var params = options.params || {};
+
+ var transparent = 'TRANSPARENT' in params ? params['TRANSPARENT'] : true;
+
+ ol.source.TileImage.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ logo: options.logo,
+ opaque: !transparent,
+ projection: options.projection,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileGrid: options.tileGrid,
+ tileLoadFunction: options.tileLoadFunction,
+ url: options.url,
+ urls: options.urls,
+ wrapX: options.wrapX !== undefined ? options.wrapX : true
+ });
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
+
+ /**
+ * @private
+ * @type {!Object}
+ */
+ this.params_ = params;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.v13_ = true;
+
+ /**
+ * @private
+ * @type {ol.source.wms.ServerType|undefined}
+ */
+ this.serverType_ =
+ /** @type {ol.source.wms.ServerType|undefined} */ (options.serverType);
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.coordKeyPrefix_ = '';
+ this.resetCoordKeyPrefix_();
+
+ /**
+ * @private
+ * @type {ol.Extent}
+ */
+ this.tmpExtent_ = ol.extent.createEmpty();
+
+ this.updateV13_();
+ this.setKey(this.getKeyForParams_());
+
+};
+ol.inherits(ol.source.TileWMS, ol.source.TileImage);
+
+
+/**
+ * Return the GetFeatureInfo URL for the passed coordinate, resolution, and
+ * projection. Return `undefined` if the GetFeatureInfo URL cannot be
+ * constructed.
+ * @param {ol.Coordinate} coordinate Coordinate.
+ * @param {number} resolution Resolution.
+ * @param {ol.ProjectionLike} projection Projection.
+ * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
+ * be provided. If `QUERY_LAYERS` is not provided then the layers specified
+ * in the `LAYERS` parameter will be used. `VERSION` should not be
+ * specified here.
+ * @return {string|undefined} GetFeatureInfo URL.
+ * @api stable
+ */
+ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
+
+ goog.asserts.assert(!('VERSION' in params),
+ 'key VERSION is not allowed in params');
+
+ var projectionObj = ol.proj.get(projection);
+
+ var tileGrid = this.getTileGrid();
+ if (!tileGrid) {
+ tileGrid = this.getTileGridForProjection(projectionObj);
+ }
+
+ var tileCoord = tileGrid.getTileCoordForCoordAndResolution(
+ coordinate, resolution);
+
+ if (tileGrid.getResolutions().length <= tileCoord[0]) {
+ return undefined;
+ }
+
+ var tileResolution = tileGrid.getResolution(tileCoord[0]);
+ var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
+ var tileSize = ol.size.toSize(
+ tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
+
+ var gutter = this.gutter_;
+ if (gutter !== 0) {
+ tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
+ tileExtent = ol.extent.buffer(tileExtent,
+ tileResolution * gutter, tileExtent);
+ }
+
+ var baseParams = {
+ 'SERVICE': 'WMS',
+ 'VERSION': ol.DEFAULT_WMS_VERSION,
+ 'REQUEST': 'GetFeatureInfo',
+ 'FORMAT': 'image/png',
+ 'TRANSPARENT': true,
+ 'QUERY_LAYERS': this.params_['LAYERS']
+ };
+ ol.object.assign(baseParams, this.params_, params);
+
+ var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution);
+ var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution);
+
+ baseParams[this.v13_ ? 'I' : 'X'] = x;
+ baseParams[this.v13_ ? 'J' : 'Y'] = y;
+
+ return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
+ 1, projectionObj, baseParams);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileWMS.prototype.getGutterInternal = function() {
+ return this.gutter_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) {
+ return this.coordKeyPrefix_ + ol.source.TileImage.prototype.getKeyZXY.call(this, z, x, y);
+};
+
+
+/**
+ * Get the user-provided params, i.e. those passed to the constructor through
+ * the "params" option, and possibly updated using the updateParams method.
+ * @return {Object} Params.
+ * @api stable
+ */
+ol.source.TileWMS.prototype.getParams = function() {
+ return this.params_;
+};
+
+
+/**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.Size} tileSize Tile size.
+ * @param {ol.Extent} tileExtent Tile extent.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @param {Object} params Params.
+ * @return {string|undefined} Request URL.
+ * @private
+ */
+ol.source.TileWMS.prototype.getRequestUrl_ = function(tileCoord, tileSize, tileExtent,
+ pixelRatio, projection, params) {
+
+ var urls = this.urls;
+ if (!urls) {
+ return undefined;
+ }
+
+ params['WIDTH'] = tileSize[0];
+ params['HEIGHT'] = tileSize[1];
+
+ params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
+
+ if (!('STYLES' in this.params_)) {
+ params['STYLES'] = '';
+ }
+
+ if (pixelRatio != 1) {
+ switch (this.serverType_) {
+ case ol.source.wms.ServerType.GEOSERVER:
+ var dpi = (90 * pixelRatio + 0.5) | 0;
+ if ('FORMAT_OPTIONS' in params) {
+ params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
+ } else {
+ params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
+ }
+ break;
+ case ol.source.wms.ServerType.MAPSERVER:
+ params['MAP_RESOLUTION'] = 90 * pixelRatio;
+ break;
+ case ol.source.wms.ServerType.CARMENTA_SERVER:
+ case ol.source.wms.ServerType.QGIS:
+ params['DPI'] = 90 * pixelRatio;
+ break;
+ default:
+ goog.asserts.fail('unknown serverType configured');
+ break;
+ }
+ }
+
+ var axisOrientation = projection.getAxisOrientation();
+ var bbox = tileExtent;
+ if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
+ var tmp;
+ tmp = tileExtent[0];
+ bbox[0] = tileExtent[1];
+ bbox[1] = tmp;
+ tmp = tileExtent[2];
+ bbox[2] = tileExtent[3];
+ bbox[3] = tmp;
+ }
+ params['BBOX'] = bbox.join(',');
+
+ var url;
+ if (urls.length == 1) {
+ url = urls[0];
+ } else {
+ var index = ol.math.modulo(ol.tilecoord.hash(tileCoord), urls.length);
+ url = urls[index];
+ }
+ return ol.uri.appendParams(url, params);
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileWMS.prototype.getTilePixelRatio = function(pixelRatio) {
+ return (!this.hidpi_ || this.serverType_ === undefined) ? 1 : pixelRatio;
+};
+
+
+/**
+ * @private
+ */
+ol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() {
+ var i = 0;
+ var res = [];
+
+ if (this.urls) {
+ var j, jj;
+ for (j = 0, jj = this.urls.length; j < jj; ++j) {
+ res[i++] = this.urls[j];
+ }
+ }
+
+ this.coordKeyPrefix_ = res.join('#');
+};
+
+
+/**
+ * @private
+ * @return {string} The key for the current params.
+ */
+ol.source.TileWMS.prototype.getKeyForParams_ = function() {
+ var i = 0;
+ var res = [];
+ for (var key in this.params_) {
+ res[i++] = key + '-' + this.params_[key];
+ }
+ return res.join('/');
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.TileWMS.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {
+
+ var tileGrid = this.getTileGrid();
+ if (!tileGrid) {
+ tileGrid = this.getTileGridForProjection(projection);
+ }
+
+ if (tileGrid.getResolutions().length <= tileCoord[0]) {
+ return undefined;
+ }
+
+ if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
+ pixelRatio = 1;
+ }
+
+ var tileResolution = tileGrid.getResolution(tileCoord[0]);
+ var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
+ var tileSize = ol.size.toSize(
+ tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
+
+ var gutter = this.gutter_;
+ if (gutter !== 0) {
+ tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
+ tileExtent = ol.extent.buffer(tileExtent,
+ tileResolution * gutter, tileExtent);
+ }
+
+ if (pixelRatio != 1) {
+ tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);
+ }
+
+ var baseParams = {
+ 'SERVICE': 'WMS',
+ 'VERSION': ol.DEFAULT_WMS_VERSION,
+ 'REQUEST': 'GetMap',
+ 'FORMAT': 'image/png',
+ 'TRANSPARENT': true
+ };
+ ol.object.assign(baseParams, this.params_);
+
+ return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
+ pixelRatio, projection, baseParams);
+};
+
+
+/**
+ * Update the user-provided params.
+ * @param {Object} params Params.
+ * @api stable
+ */
+ol.source.TileWMS.prototype.updateParams = function(params) {
+ ol.object.assign(this.params_, params);
+ this.resetCoordKeyPrefix_();
+ this.updateV13_();
+ this.setKey(this.getKeyForParams_());
+};
+
+
+/**
+ * @private
+ */
+ol.source.TileWMS.prototype.updateV13_ = function() {
+ var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;
+ this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;
+};
+
+goog.provide('ol.tilegrid.WMTS');
+
+goog.require('goog.asserts');
+goog.require('ol.proj');
+goog.require('ol.tilegrid.TileGrid');
+
+
+/**
+ * @classdesc
+ * Set the grid pattern for sources accessing WMTS tiled-image servers.
+ *
+ * @constructor
+ * @extends {ol.tilegrid.TileGrid}
+ * @param {olx.tilegrid.WMTSOptions} options WMTS options.
+ * @struct
+ * @api
+ */
+ol.tilegrid.WMTS = function(options) {
+
+ goog.asserts.assert(
+ options.resolutions.length == options.matrixIds.length,
+ 'options resolutions and matrixIds must have equal length (%s == %s)',
+ options.resolutions.length, options.matrixIds.length);
+
+ /**
+ * @private
+ * @type {!Array.<string>}
+ */
+ this.matrixIds_ = options.matrixIds;
+ // FIXME: should the matrixIds become optionnal?
+
+ ol.tilegrid.TileGrid.call(this, {
+ extent: options.extent,
+ origin: options.origin,
+ origins: options.origins,
+ resolutions: options.resolutions,
+ tileSize: options.tileSize,
+ tileSizes: options.tileSizes,
+ sizes: options.sizes
+ });
+
+};
+ol.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid);
+
+
+/**
+ * @param {number} z Z.
+ * @return {string} MatrixId..
+ */
+ol.tilegrid.WMTS.prototype.getMatrixId = function(z) {
+ goog.asserts.assert(0 <= z && z < this.matrixIds_.length,
+ 'attempted to retrive matrixId for illegal z (%s)', z);
+ return this.matrixIds_[z];
+};
+
+
+/**
+ * Get the list of matrix identifiers.
+ * @return {Array.<string>} MatrixIds.
+ * @api
+ */
+ol.tilegrid.WMTS.prototype.getMatrixIds = function() {
+ return this.matrixIds_;
+};
+
+
+/**
+ * Create a tile grid from a WMTS capabilities matrix set.
+ * @param {Object} matrixSet An object representing a matrixSet in the
+ * capabilities document.
+ * @param {ol.Extent=} opt_extent An optional extent to restrict the tile
+ * ranges the server provides.
+ * @return {ol.tilegrid.WMTS} WMTS tileGrid instance.
+ * @api
+ */
+ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_extent) {
+
+ /** @type {!Array.<number>} */
+ var resolutions = [];
+ /** @type {!Array.<string>} */
+ var matrixIds = [];
+ /** @type {!Array.<ol.Coordinate>} */
+ var origins = [];
+ /** @type {!Array.<ol.Size>} */
+ var tileSizes = [];
+ /** @type {!Array.<ol.Size>} */
+ var sizes = [];
+
+ var supportedCRSPropName = 'SupportedCRS';
+ var matrixIdsPropName = 'TileMatrix';
+ var identifierPropName = 'Identifier';
+ var scaleDenominatorPropName = 'ScaleDenominator';
+ var topLeftCornerPropName = 'TopLeftCorner';
+ var tileWidthPropName = 'TileWidth';
+ var tileHeightPropName = 'TileHeight';
+
+ var projection;
+ projection = ol.proj.get(matrixSet[supportedCRSPropName].replace(
+ /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'));
+ var metersPerUnit = projection.getMetersPerUnit();
+ // swap origin x and y coordinates if axis orientation is lat/long
+ var switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne';
+
+ matrixSet[matrixIdsPropName].sort(function(a, b) {
+ return b[scaleDenominatorPropName] - a[scaleDenominatorPropName];
+ });
+
+ matrixSet[matrixIdsPropName].forEach(function(elt, index, array) {
+ matrixIds.push(elt[identifierPropName]);
+ var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit;
+ var tileWidth = elt[tileWidthPropName];
+ var tileHeight = elt[tileHeightPropName];
+ if (switchOriginXY) {
+ origins.push([elt[topLeftCornerPropName][1],
+ elt[topLeftCornerPropName][0]]);
+ } else {
+ origins.push(elt[topLeftCornerPropName]);
+ }
+ resolutions.push(resolution);
+ tileSizes.push(tileWidth == tileHeight ?
+ tileWidth : [tileWidth, tileHeight]);
+ // top-left origin, so height is negative
+ sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]);
+ });
+
+ return new ol.tilegrid.WMTS({
+ extent: opt_extent,
+ origins: origins,
+ resolutions: resolutions,
+ matrixIds: matrixIds,
+ tileSizes: tileSizes,
+ sizes: sizes
+ });
+};
+
+goog.provide('ol.source.WMTS');
+
+goog.require('goog.asserts');
+goog.require('ol.TileUrlFunction');
+goog.require('ol.array');
+goog.require('ol.extent');
+goog.require('ol.object');
+goog.require('ol.proj');
+goog.require('ol.source.TileImage');
+goog.require('ol.tilegrid.WMTS');
+goog.require('ol.uri');
+
+
+/**
+ * Request encoding. One of 'KVP', 'REST'.
+ * @enum {string}
+ */
+ol.source.WMTSRequestEncoding = {
+ KVP: 'KVP', // see spec §8
+ REST: 'REST' // see spec §10
+};
+
+
+/**
+ * @classdesc
+ * Layer source for tile data from WMTS servers.
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.WMTSOptions} options WMTS options.
+ * @api stable
+ */
+ol.source.WMTS = function(options) {
+
+ // TODO: add support for TileMatrixLimits
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.version_ = options.version !== undefined ? options.version : '1.0.0';
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.format_ = options.format !== undefined ? options.format : 'image/jpeg';
+
+ /**
+ * @private
+ * @type {!Object}
+ */
+ this.dimensions_ = options.dimensions !== undefined ? options.dimensions : {};
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.layer_ = options.layer;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.matrixSet_ = options.matrixSet;
+
+ /**
+ * @private
+ * @type {string}
+ */
+ this.style_ = options.style;
+
+ var urls = options.urls;
+ if (urls === undefined && options.url !== undefined) {
+ urls = ol.TileUrlFunction.expandUrl(options.url);
+ }
+
+ // FIXME: should we guess this requestEncoding from options.url(s)
+ // structure? that would mean KVP only if a template is not provided.
+
+ /**
+ * @private
+ * @type {ol.source.WMTSRequestEncoding}
+ */
+ this.requestEncoding_ = options.requestEncoding !== undefined ?
+ /** @type {ol.source.WMTSRequestEncoding} */ (options.requestEncoding) :
+ ol.source.WMTSRequestEncoding.KVP;
+
+ var requestEncoding = this.requestEncoding_;
+
+ // FIXME: should we create a default tileGrid?
+ // we could issue a getCapabilities xhr to retrieve missing configuration
+ var tileGrid = options.tileGrid;
+
+ // context property names are lower case to allow for a case insensitive
+ // replacement as some services use different naming conventions
+ var context = {
+ 'layer': this.layer_,
+ 'style': this.style_,
+ 'tilematrixset': this.matrixSet_
+ };
+
+ if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) {
+ ol.object.assign(context, {
+ 'Service': 'WMTS',
+ 'Request': 'GetTile',
+ 'Version': this.version_,
+ 'Format': this.format_
+ });
+ }
+
+ var dimensions = this.dimensions_;
+
+ /**
+ * @param {string} template Template.
+ * @return {ol.TileUrlFunctionType} Tile URL function.
+ */
+ function createFromWMTSTemplate(template) {
+
+ // TODO: we may want to create our own appendParams function so that params
+ // order conforms to wmts spec guidance, and so that we can avoid to escape
+ // special template params
+
+ template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ?
+ ol.uri.appendParams(template, context) :
+ template.replace(/\{(\w+?)\}/g, function(m, p) {
+ return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m;
+ });
+
+ return (
+ /**
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string|undefined} Tile URL.
+ */
+ function(tileCoord, pixelRatio, projection) {
+ if (!tileCoord) {
+ return undefined;
+ } else {
+ var localContext = {
+ 'TileMatrix': tileGrid.getMatrixId(tileCoord[0]),
+ 'TileCol': tileCoord[1],
+ 'TileRow': -tileCoord[2] - 1
+ };
+ ol.object.assign(localContext, dimensions);
+ var url = template;
+ if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) {
+ url = ol.uri.appendParams(url, localContext);
+ } else {
+ url = url.replace(/\{(\w+?)\}/g, function(m, p) {
+ return localContext[p];
+ });
+ }
+ return url;
+ }
+ });
+ }
+
+ var tileUrlFunction = (urls && urls.length > 0) ?
+ ol.TileUrlFunction.createFromTileUrlFunctions(
+ urls.map(createFromWMTSTemplate)) :
+ ol.TileUrlFunction.nullTileUrlFunction;
+
+ ol.source.TileImage.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ logo: options.logo,
+ projection: options.projection,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileClass: options.tileClass,
+ tileGrid: tileGrid,
+ tileLoadFunction: options.tileLoadFunction,
+ tilePixelRatio: options.tilePixelRatio,
+ tileUrlFunction: tileUrlFunction,
+ urls: urls,
+ wrapX: options.wrapX !== undefined ? options.wrapX : false
+ });
+
+ this.setKey(this.getKeyForDimensions_());
+
+};
+ol.inherits(ol.source.WMTS, ol.source.TileImage);
+
+
+/**
+ * Get the dimensions, i.e. those passed to the constructor through the
+ * "dimensions" option, and possibly updated using the updateDimensions
+ * method.
+ * @return {!Object} Dimensions.
+ * @api
+ */
+ol.source.WMTS.prototype.getDimensions = function() {
+ return this.dimensions_;
+};
+
+
+/**
+ * Return the image format of the WMTS source.
+ * @return {string} Format.
+ * @api
+ */
+ol.source.WMTS.prototype.getFormat = function() {
+ return this.format_;
+};
+
+
+/**
+ * Return the layer of the WMTS source.
+ * @return {string} Layer.
+ * @api
+ */
+ol.source.WMTS.prototype.getLayer = function() {
+ return this.layer_;
+};
+
+
+/**
+ * Return the matrix set of the WMTS source.
+ * @return {string} MatrixSet.
+ * @api
+ */
+ol.source.WMTS.prototype.getMatrixSet = function() {
+ return this.matrixSet_;
+};
+
+
+/**
+ * Return the request encoding, either "KVP" or "REST".
+ * @return {ol.source.WMTSRequestEncoding} Request encoding.
+ * @api
+ */
+ol.source.WMTS.prototype.getRequestEncoding = function() {
+ return this.requestEncoding_;
+};
+
+
+/**
+ * Return the style of the WMTS source.
+ * @return {string} Style.
+ * @api
+ */
+ol.source.WMTS.prototype.getStyle = function() {
+ return this.style_;
+};
+
+
+/**
+ * Return the version of the WMTS source.
+ * @return {string} Version.
+ * @api
+ */
+ol.source.WMTS.prototype.getVersion = function() {
+ return this.version_;
+};
+
+
+/**
+ * @private
+ * @return {string} The key for the current dimensions.
+ */
+ol.source.WMTS.prototype.getKeyForDimensions_ = function() {
+ var i = 0;
+ var res = [];
+ for (var key in this.dimensions_) {
+ res[i++] = key + '-' + this.dimensions_[key];
+ }
+ return res.join('/');
+};
+
+
+/**
+ * Update the dimensions.
+ * @param {Object} dimensions Dimensions.
+ * @api
+ */
+ol.source.WMTS.prototype.updateDimensions = function(dimensions) {
+ ol.object.assign(this.dimensions_, dimensions);
+ this.setKey(this.getKeyForDimensions_());
+};
+
+
+/**
+ * Generate source options from a capabilities object.
+ * @param {Object} wmtsCap An object representing the capabilities document.
+ * @param {Object} config Configuration properties for the layer. Defaults for
+ * the layer will apply if not provided.
+ *
+ * Required config properties:
+ * - layer - {string} The layer identifier.
+ *
+ * Optional config properties:
+ * - matrixSet - {string} The matrix set identifier, required if there is
+ * more than one matrix set in the layer capabilities.
+ * - projection - {string} The desired CRS when no matrixSet is specified.
+ * eg: "EPSG:3857". If the desired projection is not available,
+ * an error is thrown.
+ * - requestEncoding - {string} url encoding format for the layer. Default is
+ * the first tile url format found in the GetCapabilities response.
+ * - style - {string} The name of the style
+ * - format - {string} Image format for the layer. Default is the first
+ * format returned in the GetCapabilities response.
+ * @return {olx.source.WMTSOptions} WMTS source options object.
+ * @api
+ */
+ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
+
+ // TODO: add support for TileMatrixLimits
+ goog.asserts.assert(config['layer'],
+ 'config "layer" must not be null');
+
+ var layers = wmtsCap['Contents']['Layer'];
+ var l = ol.array.find(layers, function(elt, index, array) {
+ return elt['Identifier'] == config['layer'];
+ });
+ goog.asserts.assert(l, 'found a matching layer in Contents/Layer');
+
+ goog.asserts.assert(l['TileMatrixSetLink'].length > 0,
+ 'layer has TileMatrixSetLink');
+ var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet'];
+ var idx, matrixSet;
+ if (l['TileMatrixSetLink'].length > 1) {
+ if ('projection' in config) {
+ idx = ol.array.findIndex(l['TileMatrixSetLink'],
+ function(elt, index, array) {
+ var tileMatrixSet = ol.array.find(tileMatrixSets, function(el) {
+ return el['Identifier'] == elt['TileMatrixSet'];
+ });
+ return tileMatrixSet['SupportedCRS'].replace(
+ /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'
+ ) == config['projection'];
+ });
+ } else {
+ idx = ol.array.findIndex(l['TileMatrixSetLink'],
+ function(elt, index, array) {
+ return elt['TileMatrixSet'] == config['matrixSet'];
+ });
+ }
+ } else {
+ idx = 0;
+ }
+ if (idx < 0) {
+ idx = 0;
+ }
+ matrixSet = /** @type {string} */
+ (l['TileMatrixSetLink'][idx]['TileMatrixSet']);
+
+ goog.asserts.assert(matrixSet, 'TileMatrixSet must not be null');
+
+ var format = /** @type {string} */ (l['Format'][0]);
+ if ('format' in config) {
+ format = config['format'];
+ }
+ idx = ol.array.findIndex(l['Style'], function(elt, index, array) {
+ if ('style' in config) {
+ return elt['Title'] == config['style'];
+ } else {
+ return elt['isDefault'];
+ }
+ });
+ if (idx < 0) {
+ idx = 0;
+ }
+ var style = /** @type {string} */ (l['Style'][idx]['Identifier']);
+
+ var dimensions = {};
+ if ('Dimension' in l) {
+ l['Dimension'].forEach(function(elt, index, array) {
+ var key = elt['Identifier'];
+ var value = elt['Default'];
+ if (value !== undefined) {
+ goog.asserts.assert(ol.array.includes(elt['Value'], value),
+ 'default value contained in values');
+ } else {
+ value = elt['Value'][0];
+ }
+ goog.asserts.assert(value !== undefined, 'value could be found');
+ dimensions[key] = value;
+ });
+ }
+
+ var matrixSets = wmtsCap['Contents']['TileMatrixSet'];
+ var matrixSetObj = ol.array.find(matrixSets, function(elt, index, array) {
+ return elt['Identifier'] == matrixSet;
+ });
+ goog.asserts.assert(matrixSetObj,
+ 'found matrixSet in Contents/TileMatrixSet');
+
+ var projection;
+ if ('projection' in config) {
+ projection = ol.proj.get(config['projection']);
+ } else {
+ projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace(
+ /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'));
+ }
+
+ var wgs84BoundingBox = l['WGS84BoundingBox'];
+ var extent, wrapX;
+ if (wgs84BoundingBox !== undefined) {
+ var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent();
+ wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] &&
+ wgs84BoundingBox[2] == wgs84ProjectionExtent[2]);
+ extent = ol.proj.transformExtent(
+ wgs84BoundingBox, 'EPSG:4326', projection);
+ var projectionExtent = projection.getExtent();
+ if (projectionExtent) {
+ // If possible, do a sanity check on the extent - it should never be
+ // bigger than the validity extent of the projection of a matrix set.
+ if (!ol.extent.containsExtent(projectionExtent, extent)) {
+ extent = undefined;
+ }
+ }
+ }
+
+ var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
+ matrixSetObj, extent);
+
+ /** @type {!Array.<string>} */
+ var urls = [];
+ var requestEncoding = config['requestEncoding'];
+ requestEncoding = requestEncoding !== undefined ? requestEncoding : '';
+
+ goog.asserts.assert(
+ ol.array.includes(['REST', 'RESTful', 'KVP', ''], requestEncoding),
+ 'requestEncoding (%s) is one of "REST", "RESTful", "KVP" or ""',
+ requestEncoding);
+
+ if ('OperationsMetadata' in wmtsCap && 'GetTile' in wmtsCap['OperationsMetadata']) {
+ var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get'];
+ goog.asserts.assert(gets.length >= 1);
+
+ for (var i = 0, ii = gets.length; i < ii; ++i) {
+ var constraint = ol.array.find(gets[i]['Constraint'], function(element) {
+ return element['name'] == 'GetEncoding';
+ });
+ var encodings = constraint['AllowedValues']['Value'];
+ goog.asserts.assert(encodings.length >= 1);
+
+ if (requestEncoding === '') {
+ // requestEncoding not provided, use the first encoding from the list
+ requestEncoding = encodings[0];
+ }
+ if (requestEncoding === ol.source.WMTSRequestEncoding.KVP) {
+ if (ol.array.includes(encodings, ol.source.WMTSRequestEncoding.KVP)) {
+ urls.push(/** @type {string} */ (gets[i]['href']));
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ if (urls.length === 0) {
+ requestEncoding = ol.source.WMTSRequestEncoding.REST;
+ l['ResourceURL'].forEach(function(element) {
+ if (element['resourceType'] === 'tile') {
+ format = element['format'];
+ urls.push(/** @type {string} */ (element['template']));
+ }
+ });
+ }
+ goog.asserts.assert(urls.length > 0, 'At least one URL found');
+
+ return {
+ urls: urls,
+ layer: config['layer'],
+ matrixSet: matrixSet,
+ format: format,
+ projection: projection,
+ requestEncoding: requestEncoding,
+ tileGrid: tileGrid,
+ style: style,
+ dimensions: dimensions,
+ wrapX: wrapX
+ };
+
+};
+
+goog.provide('ol.source.Zoomify');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.ImageTile');
+goog.require('ol.TileState');
+goog.require('ol.dom');
+goog.require('ol.extent');
+goog.require('ol.proj');
+goog.require('ol.source.TileImage');
+goog.require('ol.tilegrid.TileGrid');
+
+
+/**
+ * @enum {string}
+ */
+ol.source.ZoomifyTierSizeCalculation = {
+ DEFAULT: 'default',
+ TRUNCATED: 'truncated'
+};
+
+
+/**
+ * @classdesc
+ * Layer source for tile data in Zoomify format.
+ *
+ * @constructor
+ * @extends {ol.source.TileImage}
+ * @param {olx.source.ZoomifyOptions=} opt_options Options.
+ * @api stable
+ */
+ol.source.Zoomify = function(opt_options) {
+
+ var options = opt_options || {};
+
+ var size = options.size;
+ var tierSizeCalculation = options.tierSizeCalculation !== undefined ?
+ options.tierSizeCalculation :
+ ol.source.ZoomifyTierSizeCalculation.DEFAULT;
+
+ var imageWidth = size[0];
+ var imageHeight = size[1];
+ var tierSizeInTiles = [];
+ var tileSize = ol.DEFAULT_TILE_SIZE;
+
+ switch (tierSizeCalculation) {
+ case ol.source.ZoomifyTierSizeCalculation.DEFAULT:
+ while (imageWidth > tileSize || imageHeight > tileSize) {
+ tierSizeInTiles.push([
+ Math.ceil(imageWidth / tileSize),
+ Math.ceil(imageHeight / tileSize)
+ ]);
+ tileSize += tileSize;
+ }
+ break;
+ case ol.source.ZoomifyTierSizeCalculation.TRUNCATED:
+ var width = imageWidth;
+ var height = imageHeight;
+ while (width > tileSize || height > tileSize) {
+ tierSizeInTiles.push([
+ Math.ceil(width / tileSize),
+ Math.ceil(height / tileSize)
+ ]);
+ width >>= 1;
+ height >>= 1;
+ }
+ break;
+ default:
+ goog.asserts.fail();
+ break;
+ }
+
+ tierSizeInTiles.push([1, 1]);
+ tierSizeInTiles.reverse();
+
+ var resolutions = [1];
+ var tileCountUpToTier = [0];
+ var i, ii;
+ for (i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
+ resolutions.push(1 << i);
+ tileCountUpToTier.push(
+ tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
+ tileCountUpToTier[i - 1]
+ );
+ }
+ resolutions.reverse();
+
+ var extent = [0, -size[1], size[0], 0];
+ var tileGrid = new ol.tilegrid.TileGrid({
+ extent: extent,
+ origin: ol.extent.getTopLeft(extent),
+ resolutions: resolutions
+ });
+
+ var url = options.url;
+
+ /**
+ * @this {ol.source.TileImage}
+ * @param {ol.TileCoord} tileCoord Tile Coordinate.
+ * @param {number} pixelRatio Pixel ratio.
+ * @param {ol.proj.Projection} projection Projection.
+ * @return {string|undefined} Tile URL.
+ */
+ function tileUrlFunction(tileCoord, pixelRatio, projection) {
+ if (!tileCoord) {
+ return undefined;
+ } else {
+ var tileCoordZ = tileCoord[0];
+ var tileCoordX = tileCoord[1];
+ var tileCoordY = -tileCoord[2] - 1;
+ var tileIndex =
+ tileCoordX +
+ tileCoordY * tierSizeInTiles[tileCoordZ][0] +
+ tileCountUpToTier[tileCoordZ];
+ var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0;
+ return url + 'TileGroup' + tileGroup + '/' +
+ tileCoordZ + '-' + tileCoordX + '-' + tileCoordY + '.jpg';
+ }
+ }
+
+ ol.source.TileImage.call(this, {
+ attributions: options.attributions,
+ cacheSize: options.cacheSize,
+ crossOrigin: options.crossOrigin,
+ logo: options.logo,
+ reprojectionErrorThreshold: options.reprojectionErrorThreshold,
+ tileClass: ol.source.ZoomifyTile_,
+ tileGrid: tileGrid,
+ tileUrlFunction: tileUrlFunction
+ });
+
+};
+ol.inherits(ol.source.Zoomify, ol.source.TileImage);
+
+
+/**
+ * @constructor
+ * @extends {ol.ImageTile}
+ * @param {ol.TileCoord} tileCoord Tile coordinate.
+ * @param {ol.TileState} state State.
+ * @param {string} src Image source URI.
+ * @param {?string} crossOrigin Cross origin.
+ * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
+ * @private
+ */
+ol.source.ZoomifyTile_ = function(
+ tileCoord, state, src, crossOrigin, tileLoadFunction) {
+
+ ol.ImageTile.call(this, tileCoord, state, src, crossOrigin, tileLoadFunction);
+
+ /**
+ * @private
+ * @type {Object.<string,
+ * HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}
+ */
+ this.zoomifyImageByContext_ = {};
+
+};
+ol.inherits(ol.source.ZoomifyTile_, ol.ImageTile);
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ZoomifyTile_.prototype.getImage = function(opt_context) {
+ var tileSize = ol.DEFAULT_TILE_SIZE;
+ var key = opt_context !== undefined ?
+ goog.getUid(opt_context).toString() : '';
+ if (key in this.zoomifyImageByContext_) {
+ return this.zoomifyImageByContext_[key];
+ } else {
+ var image = ol.ImageTile.prototype.getImage.call(this, opt_context);
+ if (this.state == ol.TileState.LOADED) {
+ if (image.width == tileSize && image.height == tileSize) {
+ this.zoomifyImageByContext_[key] = image;
+ return image;
+ } else {
+ var context = ol.dom.createCanvasContext2D(tileSize, tileSize);
+ context.drawImage(image, 0, 0);
+ this.zoomifyImageByContext_[key] = context.canvas;
+ return context.canvas;
+ }
+ } else {
+ return image;
+ }
+ }
+};
+
+goog.provide('ol.style.Atlas');
+goog.provide('ol.style.AtlasManager');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.dom');
+
+
+/**
+ * Manages the creation of image atlases.
+ *
+ * Images added to this manager will be inserted into an atlas, which
+ * will be used for rendering.
+ * The `size` given in the constructor is the size for the first
+ * atlas. After that, when new atlases are created, they will have
+ * twice the size as the latest atlas (until `maxSize` is reached).
+ *
+ * If an application uses many images or very large images, it is recommended
+ * to set a higher `size` value to avoid the creation of too many atlases.
+ *
+ * @constructor
+ * @struct
+ * @api
+ * @param {olx.style.AtlasManagerOptions=} opt_options Options.
+ */
+ol.style.AtlasManager = function(opt_options) {
+
+ var options = opt_options || {};
+
+ /**
+ * The size in pixels of the latest atlas image.
+ * @private
+ * @type {number}
+ */
+ this.currentSize_ = options.initialSize !== undefined ?
+ options.initialSize : ol.INITIAL_ATLAS_SIZE;
+
+ /**
+ * The maximum size in pixels of atlas images.
+ * @private
+ * @type {number}
+ */
+ this.maxSize_ = options.maxSize !== undefined ?
+ options.maxSize : ol.MAX_ATLAS_SIZE != -1 ?
+ ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ?
+ ol.WEBGL_MAX_TEXTURE_SIZE : 2048;
+
+ /**
+ * The size in pixels between images.
+ * @private
+ * @type {number}
+ */
+ this.space_ = options.space !== undefined ? options.space : 1;
+
+ /**
+ * @private
+ * @type {Array.<ol.style.Atlas>}
+ */
+ this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)];
+
+ /**
+ * The size in pixels of the latest atlas image for hit-detection images.
+ * @private
+ * @type {number}
+ */
+ this.currentHitSize_ = this.currentSize_;
+
+ /**
+ * @private
+ * @type {Array.<ol.style.Atlas>}
+ */
+ this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)];
+};
+
+
+/**
+ * @param {string} id The identifier of the entry to check.
+ * @return {?ol.AtlasManagerInfo} The position and atlas image for the
+ * entry, or `null` if the entry is not part of the atlas manager.
+ */
+ol.style.AtlasManager.prototype.getInfo = function(id) {
+ /** @type {?ol.AtlasInfo} */
+ var info = this.getInfo_(this.atlases_, id);
+
+ if (!info) {
+ return null;
+ }
+ /** @type {?ol.AtlasInfo} */
+ var hitInfo = this.getInfo_(this.hitAtlases_, id);
+ goog.asserts.assert(hitInfo, 'hitInfo must not be null');
+
+ return this.mergeInfos_(info, hitInfo);
+};
+
+
+/**
+ * @private
+ * @param {Array.<ol.style.Atlas>} atlases The atlases to search.
+ * @param {string} id The identifier of the entry to check.
+ * @return {?ol.AtlasInfo} The position and atlas image for the entry,
+ * or `null` if the entry is not part of the atlases.
+ */
+ol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) {
+ var atlas, info, i, ii;
+ for (i = 0, ii = atlases.length; i < ii; ++i) {
+ atlas = atlases[i];
+ info = atlas.get(id);
+ if (info) {
+ return info;
+ }
+ }
+ return null;
+};
+
+
+/**
+ * @private
+ * @param {ol.AtlasInfo} info The info for the real image.
+ * @param {ol.AtlasInfo} hitInfo The info for the hit-detection
+ * image.
+ * @return {?ol.AtlasManagerInfo} The position and atlas image for the
+ * entry, or `null` if the entry is not part of the atlases.
+ */
+ol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) {
+ goog.asserts.assert(info.offsetX === hitInfo.offsetX,
+ 'in order to merge, offsetX of info and hitInfo must be equal');
+ goog.asserts.assert(info.offsetY === hitInfo.offsetY,
+ 'in order to merge, offsetY of info and hitInfo must be equal');
+ return /** @type {ol.AtlasManagerInfo} */ ({
+ offsetX: info.offsetX,
+ offsetY: info.offsetY,
+ image: info.image,
+ hitImage: hitInfo.image
+ });
+};
+
+
+/**
+ * Add an image to the atlas manager.
+ *
+ * If an entry for the given id already exists, the entry will
+ * be overridden (but the space on the atlas graphic will not be freed).
+ *
+ * If `renderHitCallback` is provided, the image (or the hit-detection version
+ * of the image) will be rendered into a separate hit-detection atlas image.
+ *
+ * @param {string} id The identifier of the entry to add.
+ * @param {number} width The width.
+ * @param {number} height The height.
+ * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
+ * Called to render the new image onto an atlas image.
+ * @param {function(CanvasRenderingContext2D, number, number)=}
+ * opt_renderHitCallback Called to render a hit-detection image onto a hit
+ * detection atlas image.
+ * @param {Object=} opt_this Value to use as `this` when executing
+ * `renderCallback` and `renderHitCallback`.
+ * @return {?ol.AtlasManagerInfo} The position and atlas image for the
+ * entry, or `null` if the image is too big.
+ */
+ol.style.AtlasManager.prototype.add = function(id, width, height,
+ renderCallback, opt_renderHitCallback, opt_this) {
+ if (width + this.space_ > this.maxSize_ ||
+ height + this.space_ > this.maxSize_) {
+ return null;
+ }
+
+ /** @type {?ol.AtlasInfo} */
+ var info = this.add_(false,
+ id, width, height, renderCallback, opt_this);
+ if (!info) {
+ return null;
+ }
+
+ // even if no hit-detection entry is requested, we insert a fake entry into
+ // the hit-detection atlas, to make sure that the offset is the same for
+ // the original image and the hit-detection image.
+ var renderHitCallback = opt_renderHitCallback !== undefined ?
+ opt_renderHitCallback : ol.nullFunction;
+
+ /** @type {?ol.AtlasInfo} */
+ var hitInfo = this.add_(true,
+ id, width, height, renderHitCallback, opt_this);
+ goog.asserts.assert(hitInfo, 'hitInfo must not be null');
+
+ return this.mergeInfos_(info, hitInfo);
+};
+
+
+/**
+ * @private
+ * @param {boolean} isHitAtlas If the hit-detection atlases are used.
+ * @param {string} id The identifier of the entry to add.
+ * @param {number} width The width.
+ * @param {number} height The height.
+ * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
+ * Called to render the new image onto an atlas image.
+ * @param {Object=} opt_this Value to use as `this` when executing
+ * `renderCallback` and `renderHitCallback`.
+ * @return {?ol.AtlasInfo} The position and atlas image for the entry,
+ * or `null` if the image is too big.
+ */
+ol.style.AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height,
+ renderCallback, opt_this) {
+ var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_;
+ var atlas, info, i, ii;
+ for (i = 0, ii = atlases.length; i < ii; ++i) {
+ atlas = atlases[i];
+ info = atlas.add(id, width, height, renderCallback, opt_this);
+ if (info) {
+ return info;
+ } else if (!info && i === ii - 1) {
+ // the entry could not be added to one of the existing atlases,
+ // create a new atlas that is twice as big and try to add to this one.
+ var size;
+ if (isHitAtlas) {
+ size = Math.min(this.currentHitSize_ * 2, this.maxSize_);
+ this.currentHitSize_ = size;
+ } else {
+ size = Math.min(this.currentSize_ * 2, this.maxSize_);
+ this.currentSize_ = size;
+ }
+ atlas = new ol.style.Atlas(size, this.space_);
+ atlases.push(atlas);
+ // run the loop another time
+ ++ii;
+ }
+ }
+ goog.asserts.fail('Failed to add to atlasmanager');
+};
+
+
+/**
+ * This class facilitates the creation of image atlases.
+ *
+ * Images added to an atlas will be rendered onto a single
+ * atlas canvas. The distribution of images on the canvas is
+ * managed with the bin packing algorithm described in:
+ * http://www.blackpawn.com/texts/lightmaps/
+ *
+ * @constructor
+ * @struct
+ * @param {number} size The size in pixels of the sprite image.
+ * @param {number} space The space in pixels between images.
+ * Because texture coordinates are float values, the edges of
+ * images might not be completely correct (in a way that the
+ * edges overlap when being rendered). To avoid this we add a
+ * padding around each image.
+ */
+ol.style.Atlas = function(size, space) {
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.space_ = space;
+
+ /**
+ * @private
+ * @type {Array.<ol.AtlasBlock>}
+ */
+ this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}];
+
+ /**
+ * @private
+ * @type {Object.<string, ol.AtlasInfo>}
+ */
+ this.entries_ = {};
+
+ /**
+ * @private
+ * @type {CanvasRenderingContext2D}
+ */
+ this.context_ = ol.dom.createCanvasContext2D(size, size);
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = this.context_.canvas;
+};
+
+
+/**
+ * @param {string} id The identifier of the entry to check.
+ * @return {?ol.AtlasInfo} The atlas info.
+ */
+ol.style.Atlas.prototype.get = function(id) {
+ return this.entries_[id] || null;
+};
+
+
+/**
+ * @param {string} id The identifier of the entry to add.
+ * @param {number} width The width.
+ * @param {number} height The height.
+ * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
+ * Called to render the new image onto an atlas image.
+ * @param {Object=} opt_this Value to use as `this` when executing
+ * `renderCallback`.
+ * @return {?ol.AtlasInfo} The position and atlas image for the entry.
+ */
+ol.style.Atlas.prototype.add = function(id, width, height, renderCallback, opt_this) {
+ var block, i, ii;
+ for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) {
+ block = this.emptyBlocks_[i];
+ if (block.width >= width + this.space_ &&
+ block.height >= height + this.space_) {
+ // we found a block that is big enough for our entry
+ var entry = {
+ offsetX: block.x + this.space_,
+ offsetY: block.y + this.space_,
+ image: this.canvas_
+ };
+ this.entries_[id] = entry;
+
+ // render the image on the atlas image
+ renderCallback.call(opt_this, this.context_,
+ block.x + this.space_, block.y + this.space_);
+
+ // split the block after the insertion, either horizontally or vertically
+ this.split_(i, block, width + this.space_, height + this.space_);
+
+ return entry;
+ }
+ }
+
+ // there is no space for the new entry in this atlas
+ return null;
+};
+
+
+/**
+ * @private
+ * @param {number} index The index of the block.
+ * @param {ol.AtlasBlock} block The block to split.
+ * @param {number} width The width of the entry to insert.
+ * @param {number} height The height of the entry to insert.
+ */
+ol.style.Atlas.prototype.split_ = function(index, block, width, height) {
+ var deltaWidth = block.width - width;
+ var deltaHeight = block.height - height;
+
+ /** @type {ol.AtlasBlock} */
+ var newBlock1;
+ /** @type {ol.AtlasBlock} */
+ var newBlock2;
+
+ if (deltaWidth > deltaHeight) {
+ // split vertically
+ // block right of the inserted entry
+ newBlock1 = {
+ x: block.x + width,
+ y: block.y,
+ width: block.width - width,
+ height: block.height
+ };
+
+ // block below the inserted entry
+ newBlock2 = {
+ x: block.x,
+ y: block.y + height,
+ width: width,
+ height: block.height - height
+ };
+ this.updateBlocks_(index, newBlock1, newBlock2);
+ } else {
+ // split horizontally
+ // block right of the inserted entry
+ newBlock1 = {
+ x: block.x + width,
+ y: block.y,
+ width: block.width - width,
+ height: height
+ };
+
+ // block below the inserted entry
+ newBlock2 = {
+ x: block.x,
+ y: block.y + height,
+ width: block.width,
+ height: block.height - height
+ };
+ this.updateBlocks_(index, newBlock1, newBlock2);
+ }
+};
+
+
+/**
+ * Remove the old block and insert new blocks at the same array position.
+ * The new blocks are inserted at the same position, so that splitted
+ * blocks (that are potentially smaller) are filled first.
+ * @private
+ * @param {number} index The index of the block to remove.
+ * @param {ol.AtlasBlock} newBlock1 The 1st block to add.
+ * @param {ol.AtlasBlock} newBlock2 The 2nd block to add.
+ */
+ol.style.Atlas.prototype.updateBlocks_ = function(index, newBlock1, newBlock2) {
+ var args = [index, 1];
+ if (newBlock1.width > 0 && newBlock1.height > 0) {
+ args.push(newBlock1);
+ }
+ if (newBlock2.width > 0 && newBlock2.height > 0) {
+ args.push(newBlock2);
+ }
+ this.emptyBlocks_.splice.apply(this.emptyBlocks_, args);
+};
+
+goog.provide('ol.style.RegularShape');
+
+goog.require('goog.asserts');
+goog.require('ol');
+goog.require('ol.color');
+goog.require('ol.colorlike');
+goog.require('ol.dom');
+goog.require('ol.has');
+goog.require('ol.render.canvas');
+goog.require('ol.style.AtlasManager');
+goog.require('ol.style.Fill');
+goog.require('ol.style.Image');
+goog.require('ol.style.ImageState');
+goog.require('ol.style.Stroke');
+
+
+/**
+ * @classdesc
+ * Set regular shape style for vector features. The resulting shape will be
+ * a regular polygon when `radius` is provided, or a star when `radius1` and
+ * `radius2` are provided.
+ *
+ * @constructor
+ * @param {olx.style.RegularShapeOptions} options Options.
+ * @extends {ol.style.Image}
+ * @api
+ */
+ol.style.RegularShape = function(options) {
+
+ goog.asserts.assert(
+ options.radius !== undefined || options.radius1 !== undefined,
+ 'must provide either "radius" or "radius1"');
+
+ /**
+ * @private
+ * @type {Array.<string>}
+ */
+ this.checksums_ = null;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.canvas_ = null;
+
+ /**
+ * @private
+ * @type {HTMLCanvasElement}
+ */
+ this.hitDetectionCanvas_ = null;
+
+ /**
+ * @private
+ * @type {ol.style.Fill}
+ */
+ this.fill_ = options.fill !== undefined ? options.fill : null;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.origin_ = [0, 0];
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.points_ = options.points;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.radius_ = /** @type {number} */ (options.radius !== undefined ?
+ options.radius : options.radius1);
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.radius2_ =
+ options.radius2 !== undefined ? options.radius2 : this.radius_;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.angle_ = options.angle !== undefined ? options.angle : 0;
+
+ /**
+ * @private
+ * @type {ol.style.Stroke}
+ */
+ this.stroke_ = options.stroke !== undefined ? options.stroke : null;
+
+ /**
+ * @private
+ * @type {Array.<number>}
+ */
+ this.anchor_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.size_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.imageSize_ = null;
+
+ /**
+ * @private
+ * @type {ol.Size}
+ */
+ this.hitDetectionImageSize_ = null;
+
+ this.render_(options.atlasManager);
+
+ /**
+ * @type {boolean}
+ */
+ var snapToPixel = options.snapToPixel !== undefined ?
+ options.snapToPixel : true;
+
+ /**
+ * @type {boolean}
+ */
+ var rotateWithView = options.rotateWithView !== undefined ?
+ options.rotateWithView : false;
+
+ ol.style.Image.call(this, {
+ opacity: 1,
+ rotateWithView: rotateWithView,
+ rotation: options.rotation !== undefined ? options.rotation : 0,
+ scale: 1,
+ snapToPixel: snapToPixel
+ });
+
+};
+ol.inherits(ol.style.RegularShape, ol.style.Image);
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.RegularShape.prototype.getAnchor = function() {
+ return this.anchor_;
+};
+
+
+/**
+ * Get the angle used in generating the shape.
+ * @return {number} Shape's rotation in radians.
+ * @api
+ */
+ol.style.RegularShape.prototype.getAngle = function() {
+ return this.angle_;
+};
+
+
+/**
+ * Get the fill style for the shape.
+ * @return {ol.style.Fill} Fill style.
+ * @api
+ */
+ol.style.RegularShape.prototype.getFill = function() {
+ return this.fill_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.getHitDetectionImage = function(pixelRatio) {
+ return this.hitDetectionCanvas_;
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.RegularShape.prototype.getImage = function(pixelRatio) {
+ return this.canvas_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.getImageSize = function() {
+ return this.imageSize_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.getHitDetectionImageSize = function() {
+ return this.hitDetectionImageSize_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.getImageState = function() {
+ return ol.style.ImageState.LOADED;
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.RegularShape.prototype.getOrigin = function() {
+ return this.origin_;
+};
+
+
+/**
+ * Get the number of points for generating the shape.
+ * @return {number} Number of points for stars and regular polygons.
+ * @api
+ */
+ol.style.RegularShape.prototype.getPoints = function() {
+ return this.points_;
+};
+
+
+/**
+ * Get the (primary) radius for the shape.
+ * @return {number} Radius.
+ * @api
+ */
+ol.style.RegularShape.prototype.getRadius = function() {
+ return this.radius_;
+};
+
+
+/**
+ * Get the secondary radius for the shape.
+ * @return {number} Radius2.
+ * @api
+ */
+ol.style.RegularShape.prototype.getRadius2 = function() {
+ return this.radius2_;
+};
+
+
+/**
+ * @inheritDoc
+ * @api
+ */
+ol.style.RegularShape.prototype.getSize = function() {
+ return this.size_;
+};
+
+
+/**
+ * Get the stroke style for the shape.
+ * @return {ol.style.Stroke} Stroke style.
+ * @api
+ */
+ol.style.RegularShape.prototype.getStroke = function() {
+ return this.stroke_;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.listenImageChange = ol.nullFunction;
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.load = ol.nullFunction;
+
+
+/**
+ * @inheritDoc
+ */
+ol.style.RegularShape.prototype.unlistenImageChange = ol.nullFunction;
+
+
+/**
+ * @private
+ * @param {ol.style.AtlasManager|undefined} atlasManager An atlas manager.
+ */
+ol.style.RegularShape.prototype.render_ = function(atlasManager) {
+ var imageSize;
+ var lineCap = '';
+ var lineJoin = '';
+ var miterLimit = 0;
+ var lineDash = null;
+ var strokeStyle;
+ var strokeWidth = 0;
+
+ if (this.stroke_) {
+ strokeStyle = ol.color.asString(this.stroke_.getColor());
+ strokeWidth = this.stroke_.getWidth();
+ if (strokeWidth === undefined) {
+ strokeWidth = ol.render.canvas.defaultLineWidth;
+ }
+ lineDash = this.stroke_.getLineDash();
+ if (!ol.has.CANVAS_LINE_DASH) {
+ lineDash = null;
+ }
+ lineJoin = this.stroke_.getLineJoin();
+ if (lineJoin === undefined) {
+ lineJoin = ol.render.canvas.defaultLineJoin;
+ }
+ lineCap = this.stroke_.getLineCap();
+ if (lineCap === undefined) {
+ lineCap = ol.render.canvas.defaultLineCap;
+ }
+ miterLimit = this.stroke_.getMiterLimit();
+ if (miterLimit === undefined) {
+ miterLimit = ol.render.canvas.defaultMiterLimit;
+ }
+ }
+
+ var size = 2 * (this.radius_ + strokeWidth) + 1;
+
+ /** @type {ol.RegularShapeRenderOptions} */
+ var renderOptions = {
+ strokeStyle: strokeStyle,
+ strokeWidth: strokeWidth,
+ size: size,
+ lineCap: lineCap,
+ lineDash: lineDash,
+ lineJoin: lineJoin,
+ miterLimit: miterLimit
+ };
+
+ if (atlasManager === undefined) {
+ // no atlas manager is used, create a new canvas
+ var context = ol.dom.createCanvasContext2D(size, size);
+ this.canvas_ = context.canvas;
+
+ // canvas.width and height are rounded to the closest integer
+ size = this.canvas_.width;
+ imageSize = size;
+
+ this.draw_(renderOptions, context, 0, 0);
+
+ this.createHitDetectionCanvas_(renderOptions);
+ } else {
+ // an atlas manager is used, add the symbol to an atlas
+ size = Math.round(size);
+
+ var hasCustomHitDetectionImage = !this.fill_;
+ var renderHitDetectionCallback;
+ if (hasCustomHitDetectionImage) {
+ // render the hit-detection image into a separate atlas image
+ renderHitDetectionCallback =
+ this.drawHitDetectionCanvas_.bind(this, renderOptions);
+ }
+
+ var id = this.getChecksum();
+ var info = atlasManager.add(
+ id, size, size, this.draw_.bind(this, renderOptions),
+ renderHitDetectionCallback);
+ goog.asserts.assert(info, 'shape size is too large');
+
+ this.canvas_ = info.image;
+ this.origin_ = [info.offsetX, info.offsetY];
+ imageSize = info.image.width;
+
+ if (hasCustomHitDetectionImage) {
+ this.hitDetectionCanvas_ = info.hitImage;
+ this.hitDetectionImageSize_ =
+ [info.hitImage.width, info.hitImage.height];
+ } else {
+ this.hitDetectionCanvas_ = this.canvas_;
+ this.hitDetectionImageSize_ = [imageSize, imageSize];
+ }
+ }
+
+ this.anchor_ = [size / 2, size / 2];
+ this.size_ = [size, size];
+ this.imageSize_ = [imageSize, imageSize];
+};
+
+
+/**
+ * @private
+ * @param {ol.RegularShapeRenderOptions} renderOptions Render options.
+ * @param {CanvasRenderingContext2D} context The rendering context.
+ * @param {number} x The origin for the symbol (x).
+ * @param {number} y The origin for the symbol (y).
+ */
+ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) {
+ var i, angle0, radiusC;
+ // reset transform
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // then move to (x, y)
+ context.translate(x, y);
+
+ context.beginPath();
+ if (this.radius2_ !== this.radius_) {
+ this.points_ = 2 * this.points_;
+ }
+ for (i = 0; i <= this.points_; i++) {
+ angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;
+ radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;
+ context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
+ renderOptions.size / 2 + radiusC * Math.sin(angle0));
+ }
+
+ if (this.fill_) {
+ context.fillStyle = ol.colorlike.asColorLike(this.fill_.getColor());
+ context.fill();
+ }
+ if (this.stroke_) {
+ context.strokeStyle = renderOptions.strokeStyle;
+ context.lineWidth = renderOptions.strokeWidth;
+ if (renderOptions.lineDash) {
+ context.setLineDash(renderOptions.lineDash);
+ }
+ context.lineCap = renderOptions.lineCap;
+ context.lineJoin = renderOptions.lineJoin;
+ context.miterLimit = renderOptions.miterLimit;
+ context.stroke();
+ }
+ context.closePath();
+};
+
+
+/**
+ * @private
+ * @param {ol.RegularShapeRenderOptions} renderOptions Render options.
+ */
+ol.style.RegularShape.prototype.createHitDetectionCanvas_ = function(renderOptions) {
+ this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size];
+ if (this.fill_) {
+ this.hitDetectionCanvas_ = this.canvas_;
+ return;
+ }
+
+ // if no fill style is set, create an extra hit-detection image with a
+ // default fill style
+ var context = ol.dom.createCanvasContext2D(renderOptions.size, renderOptions.size);
+ this.hitDetectionCanvas_ = context.canvas;
+
+ this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);
+};
+
+
+/**
+ * @private
+ * @param {ol.RegularShapeRenderOptions} renderOptions Render options.
+ * @param {CanvasRenderingContext2D} context The context.
+ * @param {number} x The origin for the symbol (x).
+ * @param {number} y The origin for the symbol (y).
+ */
+ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = function(renderOptions, context, x, y) {
+ // reset transform
+ context.setTransform(1, 0, 0, 1, 0, 0);
+
+ // then move to (x, y)
+ context.translate(x, y);
+
+ context.beginPath();
+ if (this.radius2_ !== this.radius_) {
+ this.points_ = 2 * this.points_;
+ }
+ var i, radiusC, angle0;
+ for (i = 0; i <= this.points_; i++) {
+ angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;
+ radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;
+ context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
+ renderOptions.size / 2 + radiusC * Math.sin(angle0));
+ }
+
+ context.fillStyle = ol.render.canvas.defaultFillStyle;
+ context.fill();
+ if (this.stroke_) {
+ context.strokeStyle = renderOptions.strokeStyle;
+ context.lineWidth = renderOptions.strokeWidth;
+ if (renderOptions.lineDash) {
+ context.setLineDash(renderOptions.lineDash);
+ }
+ context.stroke();
+ }
+ context.closePath();
+};
+
+
+/**
+ * @return {string} The checksum.
+ */
+ol.style.RegularShape.prototype.getChecksum = function() {
+ var strokeChecksum = this.stroke_ ?
+ this.stroke_.getChecksum() : '-';
+ var fillChecksum = this.fill_ ?
+ this.fill_.getChecksum() : '-';
+
+ var recalculate = !this.checksums_ ||
+ (strokeChecksum != this.checksums_[1] ||
+ fillChecksum != this.checksums_[2] ||
+ this.radius_ != this.checksums_[3] ||
+ this.radius2_ != this.checksums_[4] ||
+ this.angle_ != this.checksums_[5] ||
+ this.points_ != this.checksums_[6]);
+
+ if (recalculate) {
+ var checksum = 'r' + strokeChecksum + fillChecksum +
+ (this.radius_ !== undefined ? this.radius_.toString() : '-') +
+ (this.radius2_ !== undefined ? this.radius2_.toString() : '-') +
+ (this.angle_ !== undefined ? this.angle_.toString() : '-') +
+ (this.points_ !== undefined ? this.points_.toString() : '-');
+ this.checksums_ = [checksum, strokeChecksum, fillChecksum,
+ this.radius_, this.radius2_, this.angle_, this.points_];
+ }
+
+ return this.checksums_[0];
+};
+
+// Copyright 2009 The Closure Library Authors.
+// All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file has been auto-generated by GenJsDeps, please do not edit.
+
+goog.addDependency(
+ 'demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'],
+ ['goog.ui.equation.EquationEditorDialog']);
+goog.addDependency(
+ 'demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'],
+ ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']);
+goog.addDependency(
+ 'demos/editor/helloworlddialog.js',
+ [
+ 'goog.demos.editor.HelloWorldDialog',
+ 'goog.demos.editor.HelloWorldDialog.OkEvent'
+ ],
+ [
+ 'goog.dom.TagName', 'goog.events.Event', 'goog.string',
+ 'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder',
+ 'goog.ui.editor.AbstractDialog.EventType'
+ ]);
+goog.addDependency(
+ 'demos/editor/helloworlddialogplugin.js',
+ [
+ 'goog.demos.editor.HelloWorldDialogPlugin',
+ 'goog.demos.editor.HelloWorldDialogPlugin.Command'
+ ],
+ [
+ 'goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName',
+ 'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range',
+ 'goog.functions', 'goog.ui.editor.AbstractDialog.EventType'
+ ]);
+
+/**
+ * @fileoverview Custom exports file.
+ * @suppress {checkVars,extraRequire}
+ */
+
+goog.require('ol');
+goog.require('ol.Attribution');
+goog.require('ol.Collection');
+goog.require('ol.CollectionEvent');
+goog.require('ol.CollectionEventType');
+goog.require('ol.DeviceOrientation');
+goog.require('ol.DragBoxEvent');
+goog.require('ol.Feature');
+goog.require('ol.Geolocation');
+goog.require('ol.Graticule');
+goog.require('ol.Image');
+goog.require('ol.ImageTile');
+goog.require('ol.Kinetic');
+goog.require('ol.Map');
+goog.require('ol.MapBrowserEvent');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.MapBrowserEventHandler');
+goog.require('ol.MapBrowserPointerEvent');
+goog.require('ol.MapEvent');
+goog.require('ol.MapEventType');
+goog.require('ol.MapProperty');
+goog.require('ol.Object');
+goog.require('ol.ObjectEvent');
+goog.require('ol.ObjectEventType');
+goog.require('ol.Observable');
+goog.require('ol.Overlay');
+goog.require('ol.OverlayPositioning');
+goog.require('ol.RasterOperationType');
+goog.require('ol.Sphere');
+goog.require('ol.Tile');
+goog.require('ol.TileState');
+goog.require('ol.VectorTile');
+goog.require('ol.View');
+goog.require('ol.ViewHint');
+goog.require('ol.ViewProperty');
+goog.require('ol.animation');
+goog.require('ol.color');
+goog.require('ol.colorlike');
+goog.require('ol.control');
+goog.require('ol.control.Attribution');
+goog.require('ol.control.Control');
+goog.require('ol.control.FullScreen');
+goog.require('ol.control.MousePosition');
+goog.require('ol.control.OverviewMap');
+goog.require('ol.control.Rotate');
+goog.require('ol.control.ScaleLine');
+goog.require('ol.control.Zoom');
+goog.require('ol.control.ZoomSlider');
+goog.require('ol.control.ZoomToExtent');
+goog.require('ol.coordinate');
+goog.require('ol.easing');
+goog.require('ol.events.Event');
+goog.require('ol.events.condition');
+goog.require('ol.extent');
+goog.require('ol.extent.Corner');
+goog.require('ol.extent.Relationship');
+goog.require('ol.featureloader');
+goog.require('ol.format.EsriJSON');
+goog.require('ol.format.Feature');
+goog.require('ol.format.GML');
+goog.require('ol.format.GML2');
+goog.require('ol.format.GML3');
+goog.require('ol.format.GMLBase');
+goog.require('ol.format.GPX');
+goog.require('ol.format.GeoJSON');
+goog.require('ol.format.IGC');
+goog.require('ol.format.KML');
+goog.require('ol.format.MVT');
+goog.require('ol.format.OSMXML');
+goog.require('ol.format.Polyline');
+goog.require('ol.format.TopoJSON');
+goog.require('ol.format.WFS');
+goog.require('ol.format.WKT');
+goog.require('ol.format.WMSCapabilities');
+goog.require('ol.format.WMSGetFeatureInfo');
+goog.require('ol.format.WMTSCapabilities');
+goog.require('ol.format.ogc.filter');
+goog.require('ol.format.ogc.filter.And');
+goog.require('ol.format.ogc.filter.Bbox');
+goog.require('ol.format.ogc.filter.Comparison');
+goog.require('ol.format.ogc.filter.ComparisonBinary');
+goog.require('ol.format.ogc.filter.EqualTo');
+goog.require('ol.format.ogc.filter.Filter');
+goog.require('ol.format.ogc.filter.GreaterThan');
+goog.require('ol.format.ogc.filter.GreaterThanOrEqualTo');
+goog.require('ol.format.ogc.filter.IsBetween');
+goog.require('ol.format.ogc.filter.IsLike');
+goog.require('ol.format.ogc.filter.IsNull');
+goog.require('ol.format.ogc.filter.LessThan');
+goog.require('ol.format.ogc.filter.LessThanOrEqualTo');
+goog.require('ol.format.ogc.filter.Logical');
+goog.require('ol.format.ogc.filter.LogicalBinary');
+goog.require('ol.format.ogc.filter.Not');
+goog.require('ol.format.ogc.filter.NotEqualTo');
+goog.require('ol.format.ogc.filter.Or');
+goog.require('ol.geom.Circle');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.GeometryCollection');
+goog.require('ol.geom.GeometryLayout');
+goog.require('ol.geom.GeometryType');
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.LinearRing');
+goog.require('ol.geom.MultiLineString');
+goog.require('ol.geom.MultiPoint');
+goog.require('ol.geom.MultiPolygon');
+goog.require('ol.geom.Point');
+goog.require('ol.geom.Polygon');
+goog.require('ol.geom.SimpleGeometry');
+goog.require('ol.has');
+goog.require('ol.interaction');
+goog.require('ol.interaction.DoubleClickZoom');
+goog.require('ol.interaction.DragAndDrop');
+goog.require('ol.interaction.DragAndDropEvent');
+goog.require('ol.interaction.DragBox');
+goog.require('ol.interaction.DragPan');
+goog.require('ol.interaction.DragRotate');
+goog.require('ol.interaction.DragRotateAndZoom');
+goog.require('ol.interaction.DragZoom');
+goog.require('ol.interaction.Draw');
+goog.require('ol.interaction.DrawEvent');
+goog.require('ol.interaction.DrawEventType');
+goog.require('ol.interaction.DrawMode');
+goog.require('ol.interaction.Interaction');
+goog.require('ol.interaction.InteractionProperty');
+goog.require('ol.interaction.KeyboardPan');
+goog.require('ol.interaction.KeyboardZoom');
+goog.require('ol.interaction.Modify');
+goog.require('ol.interaction.ModifyEvent');
+goog.require('ol.interaction.MouseWheelZoom');
+goog.require('ol.interaction.PinchRotate');
+goog.require('ol.interaction.PinchZoom');
+goog.require('ol.interaction.Pointer');
+goog.require('ol.interaction.Select');
+goog.require('ol.interaction.SelectEvent');
+goog.require('ol.interaction.SelectEventType');
+goog.require('ol.interaction.Snap');
+goog.require('ol.interaction.SnapProperty');
+goog.require('ol.interaction.Translate');
+goog.require('ol.interaction.TranslateEvent');
+goog.require('ol.layer.Base');
+goog.require('ol.layer.Group');
+goog.require('ol.layer.Heatmap');
+goog.require('ol.layer.Image');
+goog.require('ol.layer.Layer');
+goog.require('ol.layer.LayerProperty');
+goog.require('ol.layer.Tile');
+goog.require('ol.layer.Vector');
+goog.require('ol.layer.VectorTile');
+goog.require('ol.loadingstrategy');
+goog.require('ol.proj');
+goog.require('ol.proj.METERS_PER_UNIT');
+goog.require('ol.proj.Projection');
+goog.require('ol.proj.Units');
+goog.require('ol.proj.common');
+goog.require('ol.render');
+goog.require('ol.render.Event');
+goog.require('ol.render.EventType');
+goog.require('ol.render.Feature');
+goog.require('ol.render.VectorContext');
+goog.require('ol.render.canvas.Immediate');
+goog.require('ol.render.webgl.Immediate');
+goog.require('ol.size');
+goog.require('ol.source.BingMaps');
+goog.require('ol.source.CartoDB');
+goog.require('ol.source.Cluster');
+goog.require('ol.source.Image');
+goog.require('ol.source.ImageArcGISRest');
+goog.require('ol.source.ImageCanvas');
+goog.require('ol.source.ImageEvent');
+goog.require('ol.source.ImageMapGuide');
+goog.require('ol.source.ImageStatic');
+goog.require('ol.source.ImageVector');
+goog.require('ol.source.ImageWMS');
+goog.require('ol.source.OSM');
+goog.require('ol.source.Raster');
+goog.require('ol.source.RasterEvent');
+goog.require('ol.source.RasterEventType');
+goog.require('ol.source.Source');
+goog.require('ol.source.Stamen');
+goog.require('ol.source.State');
+goog.require('ol.source.Tile');
+goog.require('ol.source.TileArcGISRest');
+goog.require('ol.source.TileDebug');
+goog.require('ol.source.TileEvent');
+goog.require('ol.source.TileImage');
+goog.require('ol.source.TileJSON');
+goog.require('ol.source.TileUTFGrid');
+goog.require('ol.source.TileWMS');
+goog.require('ol.source.UrlTile');
+goog.require('ol.source.Vector');
+goog.require('ol.source.VectorEvent');
+goog.require('ol.source.VectorEventType');
+goog.require('ol.source.VectorTile');
+goog.require('ol.source.WMTS');
+goog.require('ol.source.XYZ');
+goog.require('ol.source.Zoomify');
+goog.require('ol.style.Atlas');
+goog.require('ol.style.AtlasManager');
+goog.require('ol.style.Circle');
+goog.require('ol.style.Fill');
+goog.require('ol.style.Icon');
+goog.require('ol.style.IconAnchorUnits');
+goog.require('ol.style.IconImageCache');
+goog.require('ol.style.IconOrigin');
+goog.require('ol.style.Image');
+goog.require('ol.style.ImageState');
+goog.require('ol.style.RegularShape');
+goog.require('ol.style.Stroke');
+goog.require('ol.style.Style');
+goog.require('ol.style.Text');
+goog.require('ol.style.defaultGeometryFunction');
+goog.require('ol.tilegrid.TileGrid');
+goog.require('ol.tilegrid.WMTS');
+goog.require('ol.tilejson');
+goog.require('ol.webgl.Context');
+goog.require('ol.xml');
+
+
+goog.exportSymbol(
+ 'ol.animation.bounce',
+ ol.animation.bounce,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.animation.pan',
+ ol.animation.pan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.animation.rotate',
+ ol.animation.rotate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.animation.zoom',
+ ol.animation.zoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.Attribution',
+ ol.Attribution,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Attribution.prototype,
+ 'getHTML',
+ ol.Attribution.prototype.getHTML);
+
+goog.exportProperty(
+ ol.CollectionEvent.prototype,
+ 'element',
+ ol.CollectionEvent.prototype.element);
+
+goog.exportSymbol(
+ 'ol.Collection',
+ ol.Collection,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'clear',
+ ol.Collection.prototype.clear);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'extend',
+ ol.Collection.prototype.extend);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'forEach',
+ ol.Collection.prototype.forEach);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'getArray',
+ ol.Collection.prototype.getArray);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'item',
+ ol.Collection.prototype.item);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'getLength',
+ ol.Collection.prototype.getLength);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'insertAt',
+ ol.Collection.prototype.insertAt);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'pop',
+ ol.Collection.prototype.pop);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'push',
+ ol.Collection.prototype.push);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'remove',
+ ol.Collection.prototype.remove);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'removeAt',
+ ol.Collection.prototype.removeAt);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'setAt',
+ ol.Collection.prototype.setAt);
+
+goog.exportSymbol(
+ 'ol.colorlike.asColorLike',
+ ol.colorlike.asColorLike,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.coordinate.add',
+ ol.coordinate.add,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.coordinate.createStringXY',
+ ol.coordinate.createStringXY,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.coordinate.format',
+ ol.coordinate.format,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.coordinate.rotate',
+ ol.coordinate.rotate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.coordinate.toStringHDMS',
+ ol.coordinate.toStringHDMS,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.coordinate.toStringXY',
+ ol.coordinate.toStringXY,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.DeviceOrientation',
+ ol.DeviceOrientation,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getAlpha',
+ ol.DeviceOrientation.prototype.getAlpha);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getBeta',
+ ol.DeviceOrientation.prototype.getBeta);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getGamma',
+ ol.DeviceOrientation.prototype.getGamma);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getHeading',
+ ol.DeviceOrientation.prototype.getHeading);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getTracking',
+ ol.DeviceOrientation.prototype.getTracking);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'setTracking',
+ ol.DeviceOrientation.prototype.setTracking);
+
+goog.exportSymbol(
+ 'ol.easing.easeIn',
+ ol.easing.easeIn,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.easing.easeOut',
+ ol.easing.easeOut,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.easing.inAndOut',
+ ol.easing.inAndOut,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.easing.linear',
+ ol.easing.linear,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.easing.upAndDown',
+ ol.easing.upAndDown,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.boundingExtent',
+ ol.extent.boundingExtent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.buffer',
+ ol.extent.buffer,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.containsCoordinate',
+ ol.extent.containsCoordinate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.containsExtent',
+ ol.extent.containsExtent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.containsXY',
+ ol.extent.containsXY,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.createEmpty',
+ ol.extent.createEmpty,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.equals',
+ ol.extent.equals,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.extend',
+ ol.extent.extend,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getBottomLeft',
+ ol.extent.getBottomLeft,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getBottomRight',
+ ol.extent.getBottomRight,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getCenter',
+ ol.extent.getCenter,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getHeight',
+ ol.extent.getHeight,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getIntersection',
+ ol.extent.getIntersection,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getSize',
+ ol.extent.getSize,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getTopLeft',
+ ol.extent.getTopLeft,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getTopRight',
+ ol.extent.getTopRight,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.getWidth',
+ ol.extent.getWidth,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.intersects',
+ ol.extent.intersects,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.isEmpty',
+ ol.extent.isEmpty,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.extent.applyTransform',
+ ol.extent.applyTransform,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.Feature',
+ ol.Feature,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'clone',
+ ol.Feature.prototype.clone);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getGeometry',
+ ol.Feature.prototype.getGeometry);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getId',
+ ol.Feature.prototype.getId);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getGeometryName',
+ ol.Feature.prototype.getGeometryName);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getStyle',
+ ol.Feature.prototype.getStyle);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getStyleFunction',
+ ol.Feature.prototype.getStyleFunction);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'setGeometry',
+ ol.Feature.prototype.setGeometry);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'setStyle',
+ ol.Feature.prototype.setStyle);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'setId',
+ ol.Feature.prototype.setId);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'setGeometryName',
+ ol.Feature.prototype.setGeometryName);
+
+goog.exportSymbol(
+ 'ol.featureloader.tile',
+ ol.featureloader.tile,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.featureloader.xhr',
+ ol.featureloader.xhr,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.Geolocation',
+ ol.Geolocation,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getAccuracy',
+ ol.Geolocation.prototype.getAccuracy);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getAccuracyGeometry',
+ ol.Geolocation.prototype.getAccuracyGeometry);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getAltitude',
+ ol.Geolocation.prototype.getAltitude);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getAltitudeAccuracy',
+ ol.Geolocation.prototype.getAltitudeAccuracy);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getHeading',
+ ol.Geolocation.prototype.getHeading);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getPosition',
+ ol.Geolocation.prototype.getPosition);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getProjection',
+ ol.Geolocation.prototype.getProjection);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getSpeed',
+ ol.Geolocation.prototype.getSpeed);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getTracking',
+ ol.Geolocation.prototype.getTracking);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getTrackingOptions',
+ ol.Geolocation.prototype.getTrackingOptions);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'setProjection',
+ ol.Geolocation.prototype.setProjection);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'setTracking',
+ ol.Geolocation.prototype.setTracking);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'setTrackingOptions',
+ ol.Geolocation.prototype.setTrackingOptions);
+
+goog.exportSymbol(
+ 'ol.Graticule',
+ ol.Graticule,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Graticule.prototype,
+ 'getMap',
+ ol.Graticule.prototype.getMap);
+
+goog.exportProperty(
+ ol.Graticule.prototype,
+ 'getMeridians',
+ ol.Graticule.prototype.getMeridians);
+
+goog.exportProperty(
+ ol.Graticule.prototype,
+ 'getParallels',
+ ol.Graticule.prototype.getParallels);
+
+goog.exportProperty(
+ ol.Graticule.prototype,
+ 'setMap',
+ ol.Graticule.prototype.setMap);
+
+goog.exportSymbol(
+ 'ol.has.DEVICE_PIXEL_RATIO',
+ ol.has.DEVICE_PIXEL_RATIO,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.has.CANVAS',
+ ol.has.CANVAS,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.has.DEVICE_ORIENTATION',
+ ol.has.DEVICE_ORIENTATION,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.has.GEOLOCATION',
+ ol.has.GEOLOCATION,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.has.TOUCH',
+ ol.has.TOUCH,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.has.WEBGL',
+ ol.has.WEBGL,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Image.prototype,
+ 'getImage',
+ ol.Image.prototype.getImage);
+
+goog.exportProperty(
+ ol.Image.prototype,
+ 'load',
+ ol.Image.prototype.load);
+
+goog.exportProperty(
+ ol.ImageTile.prototype,
+ 'getImage',
+ ol.ImageTile.prototype.getImage);
+
+goog.exportProperty(
+ ol.ImageTile.prototype,
+ 'load',
+ ol.ImageTile.prototype.load);
+
+goog.exportSymbol(
+ 'ol.Kinetic',
+ ol.Kinetic,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.loadingstrategy.all',
+ ol.loadingstrategy.all,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.loadingstrategy.bbox',
+ ol.loadingstrategy.bbox,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.loadingstrategy.tile',
+ ol.loadingstrategy.tile,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.Map',
+ ol.Map,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'addControl',
+ ol.Map.prototype.addControl);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'addInteraction',
+ ol.Map.prototype.addInteraction);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'addLayer',
+ ol.Map.prototype.addLayer);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'addOverlay',
+ ol.Map.prototype.addOverlay);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'beforeRender',
+ ol.Map.prototype.beforeRender);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'forEachFeatureAtPixel',
+ ol.Map.prototype.forEachFeatureAtPixel);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'forEachLayerAtPixel',
+ ol.Map.prototype.forEachLayerAtPixel);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'hasFeatureAtPixel',
+ ol.Map.prototype.hasFeatureAtPixel);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getEventCoordinate',
+ ol.Map.prototype.getEventCoordinate);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getEventPixel',
+ ol.Map.prototype.getEventPixel);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getTarget',
+ ol.Map.prototype.getTarget);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getTargetElement',
+ ol.Map.prototype.getTargetElement);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getCoordinateFromPixel',
+ ol.Map.prototype.getCoordinateFromPixel);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getControls',
+ ol.Map.prototype.getControls);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getOverlays',
+ ol.Map.prototype.getOverlays);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getOverlayById',
+ ol.Map.prototype.getOverlayById);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getInteractions',
+ ol.Map.prototype.getInteractions);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getLayerGroup',
+ ol.Map.prototype.getLayerGroup);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getLayers',
+ ol.Map.prototype.getLayers);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getPixelFromCoordinate',
+ ol.Map.prototype.getPixelFromCoordinate);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getSize',
+ ol.Map.prototype.getSize);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getView',
+ ol.Map.prototype.getView);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getViewport',
+ ol.Map.prototype.getViewport);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'renderSync',
+ ol.Map.prototype.renderSync);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'render',
+ ol.Map.prototype.render);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'removeControl',
+ ol.Map.prototype.removeControl);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'removeInteraction',
+ ol.Map.prototype.removeInteraction);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'removeLayer',
+ ol.Map.prototype.removeLayer);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'removeOverlay',
+ ol.Map.prototype.removeOverlay);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'setLayerGroup',
+ ol.Map.prototype.setLayerGroup);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'setSize',
+ ol.Map.prototype.setSize);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'setTarget',
+ ol.Map.prototype.setTarget);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'setView',
+ ol.Map.prototype.setView);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'updateSize',
+ ol.Map.prototype.updateSize);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'originalEvent',
+ ol.MapBrowserEvent.prototype.originalEvent);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'pixel',
+ ol.MapBrowserEvent.prototype.pixel);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'coordinate',
+ ol.MapBrowserEvent.prototype.coordinate);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'dragging',
+ ol.MapBrowserEvent.prototype.dragging);
+
+goog.exportProperty(
+ ol.MapEvent.prototype,
+ 'map',
+ ol.MapEvent.prototype.map);
+
+goog.exportProperty(
+ ol.MapEvent.prototype,
+ 'frameState',
+ ol.MapEvent.prototype.frameState);
+
+goog.exportProperty(
+ ol.ObjectEvent.prototype,
+ 'key',
+ ol.ObjectEvent.prototype.key);
+
+goog.exportProperty(
+ ol.ObjectEvent.prototype,
+ 'oldValue',
+ ol.ObjectEvent.prototype.oldValue);
+
+goog.exportSymbol(
+ 'ol.Object',
+ ol.Object,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'get',
+ ol.Object.prototype.get);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'getKeys',
+ ol.Object.prototype.getKeys);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'getProperties',
+ ol.Object.prototype.getProperties);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'set',
+ ol.Object.prototype.set);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'setProperties',
+ ol.Object.prototype.setProperties);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'unset',
+ ol.Object.prototype.unset);
+
+goog.exportSymbol(
+ 'ol.Observable',
+ ol.Observable,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.Observable.unByKey',
+ ol.Observable.unByKey,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'changed',
+ ol.Observable.prototype.changed);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'dispatchEvent',
+ ol.Observable.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'getRevision',
+ ol.Observable.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'on',
+ ol.Observable.prototype.on);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'once',
+ ol.Observable.prototype.once);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'un',
+ ol.Observable.prototype.un);
+
+goog.exportProperty(
+ ol.Observable.prototype,
+ 'unByKey',
+ ol.Observable.prototype.unByKey);
+
+goog.exportSymbol(
+ 'ol.inherits',
+ ol.inherits,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.Overlay',
+ ol.Overlay,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getElement',
+ ol.Overlay.prototype.getElement);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getId',
+ ol.Overlay.prototype.getId);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getMap',
+ ol.Overlay.prototype.getMap);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getOffset',
+ ol.Overlay.prototype.getOffset);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getPosition',
+ ol.Overlay.prototype.getPosition);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getPositioning',
+ ol.Overlay.prototype.getPositioning);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'setElement',
+ ol.Overlay.prototype.setElement);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'setMap',
+ ol.Overlay.prototype.setMap);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'setOffset',
+ ol.Overlay.prototype.setOffset);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'setPosition',
+ ol.Overlay.prototype.setPosition);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'setPositioning',
+ ol.Overlay.prototype.setPositioning);
+
+goog.exportSymbol(
+ 'ol.render.toContext',
+ ol.render.toContext,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.size.toSize',
+ ol.size.toSize,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Tile.prototype,
+ 'getTileCoord',
+ ol.Tile.prototype.getTileCoord);
+
+goog.exportProperty(
+ ol.Tile.prototype,
+ 'load',
+ ol.Tile.prototype.load);
+
+goog.exportProperty(
+ ol.VectorTile.prototype,
+ 'getFormat',
+ ol.VectorTile.prototype.getFormat);
+
+goog.exportProperty(
+ ol.VectorTile.prototype,
+ 'setFeatures',
+ ol.VectorTile.prototype.setFeatures);
+
+goog.exportProperty(
+ ol.VectorTile.prototype,
+ 'setProjection',
+ ol.VectorTile.prototype.setProjection);
+
+goog.exportProperty(
+ ol.VectorTile.prototype,
+ 'setLoader',
+ ol.VectorTile.prototype.setLoader);
+
+goog.exportSymbol(
+ 'ol.View',
+ ol.View,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'constrainCenter',
+ ol.View.prototype.constrainCenter);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'constrainResolution',
+ ol.View.prototype.constrainResolution);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'constrainRotation',
+ ol.View.prototype.constrainRotation);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getCenter',
+ ol.View.prototype.getCenter);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'calculateExtent',
+ ol.View.prototype.calculateExtent);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getMaxResolution',
+ ol.View.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getMinResolution',
+ ol.View.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getProjection',
+ ol.View.prototype.getProjection);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getResolution',
+ ol.View.prototype.getResolution);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getResolutions',
+ ol.View.prototype.getResolutions);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getRotation',
+ ol.View.prototype.getRotation);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getZoom',
+ ol.View.prototype.getZoom);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'fit',
+ ol.View.prototype.fit);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'centerOn',
+ ol.View.prototype.centerOn);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'rotate',
+ ol.View.prototype.rotate);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'setCenter',
+ ol.View.prototype.setCenter);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'setResolution',
+ ol.View.prototype.setResolution);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'setRotation',
+ ol.View.prototype.setRotation);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'setZoom',
+ ol.View.prototype.setZoom);
+
+goog.exportSymbol(
+ 'ol.xml.getAllTextContent',
+ ol.xml.getAllTextContent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.xml.parse',
+ ol.xml.parse,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.webgl.Context.prototype,
+ 'getGL',
+ ol.webgl.Context.prototype.getGL);
+
+goog.exportProperty(
+ ol.webgl.Context.prototype,
+ 'useProgram',
+ ol.webgl.Context.prototype.useProgram);
+
+goog.exportSymbol(
+ 'ol.tilegrid.TileGrid',
+ ol.tilegrid.TileGrid,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'forEachTileCoord',
+ ol.tilegrid.TileGrid.prototype.forEachTileCoord);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getMaxZoom',
+ ol.tilegrid.TileGrid.prototype.getMaxZoom);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getMinZoom',
+ ol.tilegrid.TileGrid.prototype.getMinZoom);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getOrigin',
+ ol.tilegrid.TileGrid.prototype.getOrigin);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getResolution',
+ ol.tilegrid.TileGrid.prototype.getResolution);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getResolutions',
+ ol.tilegrid.TileGrid.prototype.getResolutions);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getTileCoordExtent',
+ ol.tilegrid.TileGrid.prototype.getTileCoordExtent);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getTileCoordForCoordAndResolution',
+ ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getTileCoordForCoordAndZ',
+ ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getTileSize',
+ ol.tilegrid.TileGrid.prototype.getTileSize);
+
+goog.exportProperty(
+ ol.tilegrid.TileGrid.prototype,
+ 'getZForResolution',
+ ol.tilegrid.TileGrid.prototype.getZForResolution);
+
+goog.exportSymbol(
+ 'ol.tilegrid.createXYZ',
+ ol.tilegrid.createXYZ,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.tilegrid.WMTS',
+ ol.tilegrid.WMTS,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getMatrixIds',
+ ol.tilegrid.WMTS.prototype.getMatrixIds);
+
+goog.exportSymbol(
+ 'ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet',
+ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.style.AtlasManager',
+ ol.style.AtlasManager,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.style.Circle',
+ ol.style.Circle,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getFill',
+ ol.style.Circle.prototype.getFill);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getImage',
+ ol.style.Circle.prototype.getImage);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getRadius',
+ ol.style.Circle.prototype.getRadius);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getStroke',
+ ol.style.Circle.prototype.getStroke);
+
+goog.exportSymbol(
+ 'ol.style.Fill',
+ ol.style.Fill,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Fill.prototype,
+ 'getColor',
+ ol.style.Fill.prototype.getColor);
+
+goog.exportProperty(
+ ol.style.Fill.prototype,
+ 'setColor',
+ ol.style.Fill.prototype.setColor);
+
+goog.exportSymbol(
+ 'ol.style.Icon',
+ ol.style.Icon,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getAnchor',
+ ol.style.Icon.prototype.getAnchor);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getImage',
+ ol.style.Icon.prototype.getImage);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getOrigin',
+ ol.style.Icon.prototype.getOrigin);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getSrc',
+ ol.style.Icon.prototype.getSrc);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getSize',
+ ol.style.Icon.prototype.getSize);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'load',
+ ol.style.Icon.prototype.load);
+
+goog.exportSymbol(
+ 'ol.style.Image',
+ ol.style.Image,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'getOpacity',
+ ol.style.Image.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'getRotateWithView',
+ ol.style.Image.prototype.getRotateWithView);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'getRotation',
+ ol.style.Image.prototype.getRotation);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'getScale',
+ ol.style.Image.prototype.getScale);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'getSnapToPixel',
+ ol.style.Image.prototype.getSnapToPixel);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'setOpacity',
+ ol.style.Image.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'setRotation',
+ ol.style.Image.prototype.setRotation);
+
+goog.exportProperty(
+ ol.style.Image.prototype,
+ 'setScale',
+ ol.style.Image.prototype.setScale);
+
+goog.exportSymbol(
+ 'ol.style.RegularShape',
+ ol.style.RegularShape,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getAnchor',
+ ol.style.RegularShape.prototype.getAnchor);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getAngle',
+ ol.style.RegularShape.prototype.getAngle);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getFill',
+ ol.style.RegularShape.prototype.getFill);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getImage',
+ ol.style.RegularShape.prototype.getImage);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getOrigin',
+ ol.style.RegularShape.prototype.getOrigin);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getPoints',
+ ol.style.RegularShape.prototype.getPoints);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getRadius',
+ ol.style.RegularShape.prototype.getRadius);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getRadius2',
+ ol.style.RegularShape.prototype.getRadius2);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getSize',
+ ol.style.RegularShape.prototype.getSize);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getStroke',
+ ol.style.RegularShape.prototype.getStroke);
+
+goog.exportSymbol(
+ 'ol.style.Stroke',
+ ol.style.Stroke,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'getColor',
+ ol.style.Stroke.prototype.getColor);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'getLineCap',
+ ol.style.Stroke.prototype.getLineCap);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'getLineDash',
+ ol.style.Stroke.prototype.getLineDash);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'getLineJoin',
+ ol.style.Stroke.prototype.getLineJoin);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'getMiterLimit',
+ ol.style.Stroke.prototype.getMiterLimit);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'getWidth',
+ ol.style.Stroke.prototype.getWidth);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'setColor',
+ ol.style.Stroke.prototype.setColor);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'setLineCap',
+ ol.style.Stroke.prototype.setLineCap);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'setLineDash',
+ ol.style.Stroke.prototype.setLineDash);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'setLineJoin',
+ ol.style.Stroke.prototype.setLineJoin);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'setMiterLimit',
+ ol.style.Stroke.prototype.setMiterLimit);
+
+goog.exportProperty(
+ ol.style.Stroke.prototype,
+ 'setWidth',
+ ol.style.Stroke.prototype.setWidth);
+
+goog.exportSymbol(
+ 'ol.style.Style',
+ ol.style.Style,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getGeometry',
+ ol.style.Style.prototype.getGeometry);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getGeometryFunction',
+ ol.style.Style.prototype.getGeometryFunction);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getFill',
+ ol.style.Style.prototype.getFill);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getImage',
+ ol.style.Style.prototype.getImage);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getStroke',
+ ol.style.Style.prototype.getStroke);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getText',
+ ol.style.Style.prototype.getText);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'getZIndex',
+ ol.style.Style.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'setGeometry',
+ ol.style.Style.prototype.setGeometry);
+
+goog.exportProperty(
+ ol.style.Style.prototype,
+ 'setZIndex',
+ ol.style.Style.prototype.setZIndex);
+
+goog.exportSymbol(
+ 'ol.style.Text',
+ ol.style.Text,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getFont',
+ ol.style.Text.prototype.getFont);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getOffsetX',
+ ol.style.Text.prototype.getOffsetX);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getOffsetY',
+ ol.style.Text.prototype.getOffsetY);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getFill',
+ ol.style.Text.prototype.getFill);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getRotation',
+ ol.style.Text.prototype.getRotation);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getScale',
+ ol.style.Text.prototype.getScale);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getStroke',
+ ol.style.Text.prototype.getStroke);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getText',
+ ol.style.Text.prototype.getText);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getTextAlign',
+ ol.style.Text.prototype.getTextAlign);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'getTextBaseline',
+ ol.style.Text.prototype.getTextBaseline);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setFont',
+ ol.style.Text.prototype.setFont);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setOffsetX',
+ ol.style.Text.prototype.setOffsetX);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setOffsetY',
+ ol.style.Text.prototype.setOffsetY);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setFill',
+ ol.style.Text.prototype.setFill);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setRotation',
+ ol.style.Text.prototype.setRotation);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setScale',
+ ol.style.Text.prototype.setScale);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setStroke',
+ ol.style.Text.prototype.setStroke);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setText',
+ ol.style.Text.prototype.setText);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setTextAlign',
+ ol.style.Text.prototype.setTextAlign);
+
+goog.exportProperty(
+ ol.style.Text.prototype,
+ 'setTextBaseline',
+ ol.style.Text.prototype.setTextBaseline);
+
+goog.exportSymbol(
+ 'ol.Sphere',
+ ol.Sphere,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.Sphere.prototype,
+ 'geodesicArea',
+ ol.Sphere.prototype.geodesicArea);
+
+goog.exportProperty(
+ ol.Sphere.prototype,
+ 'haversineDistance',
+ ol.Sphere.prototype.haversineDistance);
+
+goog.exportSymbol(
+ 'ol.source.BingMaps',
+ ol.source.BingMaps,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.BingMaps.TOS_ATTRIBUTION',
+ ol.source.BingMaps.TOS_ATTRIBUTION,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.CartoDB',
+ ol.source.CartoDB,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getConfig',
+ ol.source.CartoDB.prototype.getConfig);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'updateConfig',
+ ol.source.CartoDB.prototype.updateConfig);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setConfig',
+ ol.source.CartoDB.prototype.setConfig);
+
+goog.exportSymbol(
+ 'ol.source.Cluster',
+ ol.source.Cluster,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getSource',
+ ol.source.Cluster.prototype.getSource);
+
+goog.exportSymbol(
+ 'ol.source.ImageArcGISRest',
+ ol.source.ImageArcGISRest,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getParams',
+ ol.source.ImageArcGISRest.prototype.getParams);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getImageLoadFunction',
+ ol.source.ImageArcGISRest.prototype.getImageLoadFunction);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getUrl',
+ ol.source.ImageArcGISRest.prototype.getUrl);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'setImageLoadFunction',
+ ol.source.ImageArcGISRest.prototype.setImageLoadFunction);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'setUrl',
+ ol.source.ImageArcGISRest.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'updateParams',
+ ol.source.ImageArcGISRest.prototype.updateParams);
+
+goog.exportSymbol(
+ 'ol.source.ImageCanvas',
+ ol.source.ImageCanvas,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.ImageMapGuide',
+ ol.source.ImageMapGuide,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getParams',
+ ol.source.ImageMapGuide.prototype.getParams);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getImageLoadFunction',
+ ol.source.ImageMapGuide.prototype.getImageLoadFunction);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'updateParams',
+ ol.source.ImageMapGuide.prototype.updateParams);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'setImageLoadFunction',
+ ol.source.ImageMapGuide.prototype.setImageLoadFunction);
+
+goog.exportSymbol(
+ 'ol.source.Image',
+ ol.source.Image,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.ImageEvent.prototype,
+ 'image',
+ ol.source.ImageEvent.prototype.image);
+
+goog.exportSymbol(
+ 'ol.source.ImageStatic',
+ ol.source.ImageStatic,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.ImageVector',
+ ol.source.ImageVector,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getSource',
+ ol.source.ImageVector.prototype.getSource);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getStyle',
+ ol.source.ImageVector.prototype.getStyle);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getStyleFunction',
+ ol.source.ImageVector.prototype.getStyleFunction);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'setStyle',
+ ol.source.ImageVector.prototype.setStyle);
+
+goog.exportSymbol(
+ 'ol.source.ImageWMS',
+ ol.source.ImageWMS,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getGetFeatureInfoUrl',
+ ol.source.ImageWMS.prototype.getGetFeatureInfoUrl);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getParams',
+ ol.source.ImageWMS.prototype.getParams);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getImageLoadFunction',
+ ol.source.ImageWMS.prototype.getImageLoadFunction);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getUrl',
+ ol.source.ImageWMS.prototype.getUrl);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'setImageLoadFunction',
+ ol.source.ImageWMS.prototype.setImageLoadFunction);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'setUrl',
+ ol.source.ImageWMS.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'updateParams',
+ ol.source.ImageWMS.prototype.updateParams);
+
+goog.exportSymbol(
+ 'ol.source.OSM',
+ ol.source.OSM,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.OSM.ATTRIBUTION',
+ ol.source.OSM.ATTRIBUTION,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.Raster',
+ ol.source.Raster,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'setOperation',
+ ol.source.Raster.prototype.setOperation);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'extent',
+ ol.source.RasterEvent.prototype.extent);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'resolution',
+ ol.source.RasterEvent.prototype.resolution);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'data',
+ ol.source.RasterEvent.prototype.data);
+
+goog.exportSymbol(
+ 'ol.source.Source',
+ ol.source.Source,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getAttributions',
+ ol.source.Source.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getLogo',
+ ol.source.Source.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getProjection',
+ ol.source.Source.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getState',
+ ol.source.Source.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'refresh',
+ ol.source.Source.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'setAttributions',
+ ol.source.Source.prototype.setAttributions);
+
+goog.exportSymbol(
+ 'ol.source.Stamen',
+ ol.source.Stamen,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.TileArcGISRest',
+ ol.source.TileArcGISRest,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getParams',
+ ol.source.TileArcGISRest.prototype.getParams);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'updateParams',
+ ol.source.TileArcGISRest.prototype.updateParams);
+
+goog.exportSymbol(
+ 'ol.source.TileDebug',
+ ol.source.TileDebug,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.TileImage',
+ ol.source.TileImage,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.TileImage.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setTileGridForProjection',
+ ol.source.TileImage.prototype.setTileGridForProjection);
+
+goog.exportSymbol(
+ 'ol.source.TileJSON',
+ ol.source.TileJSON,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getTileJSON',
+ ol.source.TileJSON.prototype.getTileJSON);
+
+goog.exportSymbol(
+ 'ol.source.Tile',
+ ol.source.Tile,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getTileGrid',
+ ol.source.Tile.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileEvent.prototype,
+ 'tile',
+ ol.source.TileEvent.prototype.tile);
+
+goog.exportSymbol(
+ 'ol.source.TileUTFGrid',
+ ol.source.TileUTFGrid,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getTemplate',
+ ol.source.TileUTFGrid.prototype.getTemplate);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'forDataAtCoordinateAndResolution',
+ ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution);
+
+goog.exportSymbol(
+ 'ol.source.TileWMS',
+ ol.source.TileWMS,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getGetFeatureInfoUrl',
+ ol.source.TileWMS.prototype.getGetFeatureInfoUrl);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getParams',
+ ol.source.TileWMS.prototype.getParams);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'updateParams',
+ ol.source.TileWMS.prototype.updateParams);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getTileLoadFunction',
+ ol.source.UrlTile.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getTileUrlFunction',
+ ol.source.UrlTile.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getUrls',
+ ol.source.UrlTile.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'setTileLoadFunction',
+ ol.source.UrlTile.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'setTileUrlFunction',
+ ol.source.UrlTile.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'setUrl',
+ ol.source.UrlTile.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'setUrls',
+ ol.source.UrlTile.prototype.setUrls);
+
+goog.exportSymbol(
+ 'ol.source.Vector',
+ ol.source.Vector,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'addFeature',
+ ol.source.Vector.prototype.addFeature);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'addFeatures',
+ ol.source.Vector.prototype.addFeatures);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'clear',
+ ol.source.Vector.prototype.clear);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'forEachFeature',
+ ol.source.Vector.prototype.forEachFeature);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'forEachFeatureInExtent',
+ ol.source.Vector.prototype.forEachFeatureInExtent);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'forEachFeatureIntersectingExtent',
+ ol.source.Vector.prototype.forEachFeatureIntersectingExtent);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getFeaturesCollection',
+ ol.source.Vector.prototype.getFeaturesCollection);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getFeatures',
+ ol.source.Vector.prototype.getFeatures);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getFeaturesAtCoordinate',
+ ol.source.Vector.prototype.getFeaturesAtCoordinate);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getFeaturesInExtent',
+ ol.source.Vector.prototype.getFeaturesInExtent);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getClosestFeatureToCoordinate',
+ ol.source.Vector.prototype.getClosestFeatureToCoordinate);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getExtent',
+ ol.source.Vector.prototype.getExtent);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getFeatureById',
+ ol.source.Vector.prototype.getFeatureById);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getFormat',
+ ol.source.Vector.prototype.getFormat);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getUrl',
+ ol.source.Vector.prototype.getUrl);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'removeFeature',
+ ol.source.Vector.prototype.removeFeature);
+
+goog.exportProperty(
+ ol.source.VectorEvent.prototype,
+ 'feature',
+ ol.source.VectorEvent.prototype.feature);
+
+goog.exportSymbol(
+ 'ol.source.VectorTile',
+ ol.source.VectorTile,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.WMTS',
+ ol.source.WMTS,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getDimensions',
+ ol.source.WMTS.prototype.getDimensions);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getFormat',
+ ol.source.WMTS.prototype.getFormat);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getLayer',
+ ol.source.WMTS.prototype.getLayer);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getMatrixSet',
+ ol.source.WMTS.prototype.getMatrixSet);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getRequestEncoding',
+ ol.source.WMTS.prototype.getRequestEncoding);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getStyle',
+ ol.source.WMTS.prototype.getStyle);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getVersion',
+ ol.source.WMTS.prototype.getVersion);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'updateDimensions',
+ ol.source.WMTS.prototype.updateDimensions);
+
+goog.exportSymbol(
+ 'ol.source.WMTS.optionsFromCapabilities',
+ ol.source.WMTS.optionsFromCapabilities,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.XYZ',
+ ol.source.XYZ,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.source.Zoomify',
+ ol.source.Zoomify,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'vectorContext',
+ ol.render.Event.prototype.vectorContext);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'frameState',
+ ol.render.Event.prototype.frameState);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'context',
+ ol.render.Event.prototype.context);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'glContext',
+ ol.render.Event.prototype.glContext);
+
+goog.exportProperty(
+ ol.render.Feature.prototype,
+ 'get',
+ ol.render.Feature.prototype.get);
+
+goog.exportProperty(
+ ol.render.Feature.prototype,
+ 'getExtent',
+ ol.render.Feature.prototype.getExtent);
+
+goog.exportProperty(
+ ol.render.Feature.prototype,
+ 'getGeometry',
+ ol.render.Feature.prototype.getGeometry);
+
+goog.exportProperty(
+ ol.render.Feature.prototype,
+ 'getProperties',
+ ol.render.Feature.prototype.getProperties);
+
+goog.exportProperty(
+ ol.render.Feature.prototype,
+ 'getType',
+ ol.render.Feature.prototype.getType);
+
+goog.exportSymbol(
+ 'ol.render.VectorContext',
+ ol.render.VectorContext,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.render.webgl.Immediate.prototype,
+ 'setStyle',
+ ol.render.webgl.Immediate.prototype.setStyle);
+
+goog.exportProperty(
+ ol.render.webgl.Immediate.prototype,
+ 'drawGeometry',
+ ol.render.webgl.Immediate.prototype.drawGeometry);
+
+goog.exportProperty(
+ ol.render.webgl.Immediate.prototype,
+ 'drawFeature',
+ ol.render.webgl.Immediate.prototype.drawFeature);
+
+goog.exportProperty(
+ ol.render.canvas.Immediate.prototype,
+ 'drawCircle',
+ ol.render.canvas.Immediate.prototype.drawCircle);
+
+goog.exportProperty(
+ ol.render.canvas.Immediate.prototype,
+ 'setStyle',
+ ol.render.canvas.Immediate.prototype.setStyle);
+
+goog.exportProperty(
+ ol.render.canvas.Immediate.prototype,
+ 'drawGeometry',
+ ol.render.canvas.Immediate.prototype.drawGeometry);
+
+goog.exportProperty(
+ ol.render.canvas.Immediate.prototype,
+ 'drawFeature',
+ ol.render.canvas.Immediate.prototype.drawFeature);
+
+goog.exportSymbol(
+ 'ol.proj.common.add',
+ ol.proj.common.add,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.METERS_PER_UNIT',
+ ol.proj.METERS_PER_UNIT,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.Projection',
+ ol.proj.Projection,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'getCode',
+ ol.proj.Projection.prototype.getCode);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'getExtent',
+ ol.proj.Projection.prototype.getExtent);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'getUnits',
+ ol.proj.Projection.prototype.getUnits);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'getMetersPerUnit',
+ ol.proj.Projection.prototype.getMetersPerUnit);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'getWorldExtent',
+ ol.proj.Projection.prototype.getWorldExtent);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'isGlobal',
+ ol.proj.Projection.prototype.isGlobal);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'setGlobal',
+ ol.proj.Projection.prototype.setGlobal);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'setExtent',
+ ol.proj.Projection.prototype.setExtent);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'setWorldExtent',
+ ol.proj.Projection.prototype.setWorldExtent);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'setGetPointResolution',
+ ol.proj.Projection.prototype.setGetPointResolution);
+
+goog.exportProperty(
+ ol.proj.Projection.prototype,
+ 'getPointResolution',
+ ol.proj.Projection.prototype.getPointResolution);
+
+goog.exportSymbol(
+ 'ol.proj.setProj4',
+ ol.proj.setProj4,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.addEquivalentProjections',
+ ol.proj.addEquivalentProjections,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.addProjection',
+ ol.proj.addProjection,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.addCoordinateTransforms',
+ ol.proj.addCoordinateTransforms,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.fromLonLat',
+ ol.proj.fromLonLat,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.toLonLat',
+ ol.proj.toLonLat,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.get',
+ ol.proj.get,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.equivalent',
+ ol.proj.equivalent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.getTransform',
+ ol.proj.getTransform,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.transform',
+ ol.proj.transform,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.proj.transformExtent',
+ ol.proj.transformExtent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.layer.Heatmap',
+ ol.layer.Heatmap,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getBlur',
+ ol.layer.Heatmap.prototype.getBlur);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getGradient',
+ ol.layer.Heatmap.prototype.getGradient);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getRadius',
+ ol.layer.Heatmap.prototype.getRadius);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setBlur',
+ ol.layer.Heatmap.prototype.setBlur);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setGradient',
+ ol.layer.Heatmap.prototype.setGradient);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setRadius',
+ ol.layer.Heatmap.prototype.setRadius);
+
+goog.exportSymbol(
+ 'ol.layer.Image',
+ ol.layer.Image,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getSource',
+ ol.layer.Image.prototype.getSource);
+
+goog.exportSymbol(
+ 'ol.layer.Layer',
+ ol.layer.Layer,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getSource',
+ ol.layer.Layer.prototype.getSource);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setMap',
+ ol.layer.Layer.prototype.setMap);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setSource',
+ ol.layer.Layer.prototype.setSource);
+
+goog.exportSymbol(
+ 'ol.layer.Base',
+ ol.layer.Base,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getExtent',
+ ol.layer.Base.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getMaxResolution',
+ ol.layer.Base.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getMinResolution',
+ ol.layer.Base.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getOpacity',
+ ol.layer.Base.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getVisible',
+ ol.layer.Base.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getZIndex',
+ ol.layer.Base.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setExtent',
+ ol.layer.Base.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setMaxResolution',
+ ol.layer.Base.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setMinResolution',
+ ol.layer.Base.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setOpacity',
+ ol.layer.Base.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setVisible',
+ ol.layer.Base.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setZIndex',
+ ol.layer.Base.prototype.setZIndex);
+
+goog.exportSymbol(
+ 'ol.layer.Group',
+ ol.layer.Group,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getLayers',
+ ol.layer.Group.prototype.getLayers);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setLayers',
+ ol.layer.Group.prototype.setLayers);
+
+goog.exportSymbol(
+ 'ol.layer.Tile',
+ ol.layer.Tile,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getPreload',
+ ol.layer.Tile.prototype.getPreload);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getSource',
+ ol.layer.Tile.prototype.getSource);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setPreload',
+ ol.layer.Tile.prototype.setPreload);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getUseInterimTilesOnError',
+ ol.layer.Tile.prototype.getUseInterimTilesOnError);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setUseInterimTilesOnError',
+ ol.layer.Tile.prototype.setUseInterimTilesOnError);
+
+goog.exportSymbol(
+ 'ol.layer.Vector',
+ ol.layer.Vector,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getSource',
+ ol.layer.Vector.prototype.getSource);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getStyle',
+ ol.layer.Vector.prototype.getStyle);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getStyleFunction',
+ ol.layer.Vector.prototype.getStyleFunction);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setStyle',
+ ol.layer.Vector.prototype.setStyle);
+
+goog.exportSymbol(
+ 'ol.layer.VectorTile',
+ ol.layer.VectorTile,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getPreload',
+ ol.layer.VectorTile.prototype.getPreload);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getUseInterimTilesOnError',
+ ol.layer.VectorTile.prototype.getUseInterimTilesOnError);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setPreload',
+ ol.layer.VectorTile.prototype.setPreload);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setUseInterimTilesOnError',
+ ol.layer.VectorTile.prototype.setUseInterimTilesOnError);
+
+goog.exportSymbol(
+ 'ol.interaction.DoubleClickZoom',
+ ol.interaction.DoubleClickZoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.DoubleClickZoom.handleEvent',
+ ol.interaction.DoubleClickZoom.handleEvent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.DragAndDrop',
+ ol.interaction.DragAndDrop,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.DragAndDrop.handleEvent',
+ ol.interaction.DragAndDrop.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'features',
+ ol.interaction.DragAndDropEvent.prototype.features);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'file',
+ ol.interaction.DragAndDropEvent.prototype.file);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'projection',
+ ol.interaction.DragAndDropEvent.prototype.projection);
+
+goog.exportProperty(
+ ol.DragBoxEvent.prototype,
+ 'coordinate',
+ ol.DragBoxEvent.prototype.coordinate);
+
+goog.exportProperty(
+ ol.DragBoxEvent.prototype,
+ 'mapBrowserEvent',
+ ol.DragBoxEvent.prototype.mapBrowserEvent);
+
+goog.exportSymbol(
+ 'ol.interaction.DragBox',
+ ol.interaction.DragBox,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'getGeometry',
+ ol.interaction.DragBox.prototype.getGeometry);
+
+goog.exportSymbol(
+ 'ol.interaction.DragPan',
+ ol.interaction.DragPan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.DragRotateAndZoom',
+ ol.interaction.DragRotateAndZoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.DragRotate',
+ ol.interaction.DragRotate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.DragZoom',
+ ol.interaction.DragZoom,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.DrawEvent.prototype,
+ 'feature',
+ ol.interaction.DrawEvent.prototype.feature);
+
+goog.exportSymbol(
+ 'ol.interaction.Draw',
+ ol.interaction.Draw,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.Draw.handleEvent',
+ ol.interaction.Draw.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'removeLastPoint',
+ ol.interaction.Draw.prototype.removeLastPoint);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'finishDrawing',
+ ol.interaction.Draw.prototype.finishDrawing);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'extend',
+ ol.interaction.Draw.prototype.extend);
+
+goog.exportSymbol(
+ 'ol.interaction.Draw.createRegularPolygon',
+ ol.interaction.Draw.createRegularPolygon,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.Interaction',
+ ol.interaction.Interaction,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'getActive',
+ ol.interaction.Interaction.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'getMap',
+ ol.interaction.Interaction.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'setActive',
+ ol.interaction.Interaction.prototype.setActive);
+
+goog.exportSymbol(
+ 'ol.interaction.defaults',
+ ol.interaction.defaults,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.KeyboardPan',
+ ol.interaction.KeyboardPan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.KeyboardPan.handleEvent',
+ ol.interaction.KeyboardPan.handleEvent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.KeyboardZoom',
+ ol.interaction.KeyboardZoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.KeyboardZoom.handleEvent',
+ ol.interaction.KeyboardZoom.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.ModifyEvent.prototype,
+ 'features',
+ ol.interaction.ModifyEvent.prototype.features);
+
+goog.exportProperty(
+ ol.interaction.ModifyEvent.prototype,
+ 'mapBrowserEvent',
+ ol.interaction.ModifyEvent.prototype.mapBrowserEvent);
+
+goog.exportSymbol(
+ 'ol.interaction.Modify',
+ ol.interaction.Modify,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.Modify.handleEvent',
+ ol.interaction.Modify.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'removePoint',
+ ol.interaction.Modify.prototype.removePoint);
+
+goog.exportSymbol(
+ 'ol.interaction.MouseWheelZoom',
+ ol.interaction.MouseWheelZoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.MouseWheelZoom.handleEvent',
+ ol.interaction.MouseWheelZoom.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'setMouseAnchor',
+ ol.interaction.MouseWheelZoom.prototype.setMouseAnchor);
+
+goog.exportSymbol(
+ 'ol.interaction.PinchRotate',
+ ol.interaction.PinchRotate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.PinchZoom',
+ ol.interaction.PinchZoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.Pointer',
+ ol.interaction.Pointer,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.interaction.Pointer.handleEvent',
+ ol.interaction.Pointer.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'selected',
+ ol.interaction.SelectEvent.prototype.selected);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'deselected',
+ ol.interaction.SelectEvent.prototype.deselected);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'mapBrowserEvent',
+ ol.interaction.SelectEvent.prototype.mapBrowserEvent);
+
+goog.exportSymbol(
+ 'ol.interaction.Select',
+ ol.interaction.Select,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getFeatures',
+ ol.interaction.Select.prototype.getFeatures);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getLayer',
+ ol.interaction.Select.prototype.getLayer);
+
+goog.exportSymbol(
+ 'ol.interaction.Select.handleEvent',
+ ol.interaction.Select.handleEvent,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'setMap',
+ ol.interaction.Select.prototype.setMap);
+
+goog.exportSymbol(
+ 'ol.interaction.Snap',
+ ol.interaction.Snap,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'addFeature',
+ ol.interaction.Snap.prototype.addFeature);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'removeFeature',
+ ol.interaction.Snap.prototype.removeFeature);
+
+goog.exportProperty(
+ ol.interaction.TranslateEvent.prototype,
+ 'features',
+ ol.interaction.TranslateEvent.prototype.features);
+
+goog.exportProperty(
+ ol.interaction.TranslateEvent.prototype,
+ 'coordinate',
+ ol.interaction.TranslateEvent.prototype.coordinate);
+
+goog.exportSymbol(
+ 'ol.interaction.Translate',
+ ol.interaction.Translate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.geom.Circle',
+ ol.geom.Circle,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'clone',
+ ol.geom.Circle.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getCenter',
+ ol.geom.Circle.prototype.getCenter);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getRadius',
+ ol.geom.Circle.prototype.getRadius);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getType',
+ ol.geom.Circle.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'intersectsExtent',
+ ol.geom.Circle.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'setCenter',
+ ol.geom.Circle.prototype.setCenter);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'setCenterAndRadius',
+ ol.geom.Circle.prototype.setCenterAndRadius);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'setRadius',
+ ol.geom.Circle.prototype.setRadius);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'transform',
+ ol.geom.Circle.prototype.transform);
+
+goog.exportSymbol(
+ 'ol.geom.Geometry',
+ ol.geom.Geometry,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'getClosestPoint',
+ ol.geom.Geometry.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'getExtent',
+ ol.geom.Geometry.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'rotate',
+ ol.geom.Geometry.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'simplify',
+ ol.geom.Geometry.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'transform',
+ ol.geom.Geometry.prototype.transform);
+
+goog.exportSymbol(
+ 'ol.geom.GeometryCollection',
+ ol.geom.GeometryCollection,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'clone',
+ ol.geom.GeometryCollection.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getGeometries',
+ ol.geom.GeometryCollection.prototype.getGeometries);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getType',
+ ol.geom.GeometryCollection.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'intersectsExtent',
+ ol.geom.GeometryCollection.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'setGeometries',
+ ol.geom.GeometryCollection.prototype.setGeometries);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'applyTransform',
+ ol.geom.GeometryCollection.prototype.applyTransform);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'translate',
+ ol.geom.GeometryCollection.prototype.translate);
+
+goog.exportSymbol(
+ 'ol.geom.LinearRing',
+ ol.geom.LinearRing,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'clone',
+ ol.geom.LinearRing.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getArea',
+ ol.geom.LinearRing.prototype.getArea);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getCoordinates',
+ ol.geom.LinearRing.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getType',
+ ol.geom.LinearRing.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'setCoordinates',
+ ol.geom.LinearRing.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.LineString',
+ ol.geom.LineString,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'appendCoordinate',
+ ol.geom.LineString.prototype.appendCoordinate);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'clone',
+ ol.geom.LineString.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'forEachSegment',
+ ol.geom.LineString.prototype.forEachSegment);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getCoordinateAtM',
+ ol.geom.LineString.prototype.getCoordinateAtM);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getCoordinates',
+ ol.geom.LineString.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getCoordinateAt',
+ ol.geom.LineString.prototype.getCoordinateAt);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getLength',
+ ol.geom.LineString.prototype.getLength);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getType',
+ ol.geom.LineString.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'intersectsExtent',
+ ol.geom.LineString.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'setCoordinates',
+ ol.geom.LineString.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.MultiLineString',
+ ol.geom.MultiLineString,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'appendLineString',
+ ol.geom.MultiLineString.prototype.appendLineString);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'clone',
+ ol.geom.MultiLineString.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getCoordinateAtM',
+ ol.geom.MultiLineString.prototype.getCoordinateAtM);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getCoordinates',
+ ol.geom.MultiLineString.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getLineString',
+ ol.geom.MultiLineString.prototype.getLineString);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getLineStrings',
+ ol.geom.MultiLineString.prototype.getLineStrings);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getType',
+ ol.geom.MultiLineString.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'intersectsExtent',
+ ol.geom.MultiLineString.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'setCoordinates',
+ ol.geom.MultiLineString.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.MultiPoint',
+ ol.geom.MultiPoint,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'appendPoint',
+ ol.geom.MultiPoint.prototype.appendPoint);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'clone',
+ ol.geom.MultiPoint.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getCoordinates',
+ ol.geom.MultiPoint.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getPoint',
+ ol.geom.MultiPoint.prototype.getPoint);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getPoints',
+ ol.geom.MultiPoint.prototype.getPoints);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getType',
+ ol.geom.MultiPoint.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'intersectsExtent',
+ ol.geom.MultiPoint.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'setCoordinates',
+ ol.geom.MultiPoint.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.MultiPolygon',
+ ol.geom.MultiPolygon,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'appendPolygon',
+ ol.geom.MultiPolygon.prototype.appendPolygon);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'clone',
+ ol.geom.MultiPolygon.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getArea',
+ ol.geom.MultiPolygon.prototype.getArea);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getCoordinates',
+ ol.geom.MultiPolygon.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getInteriorPoints',
+ ol.geom.MultiPolygon.prototype.getInteriorPoints);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getPolygon',
+ ol.geom.MultiPolygon.prototype.getPolygon);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getPolygons',
+ ol.geom.MultiPolygon.prototype.getPolygons);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getType',
+ ol.geom.MultiPolygon.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'intersectsExtent',
+ ol.geom.MultiPolygon.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'setCoordinates',
+ ol.geom.MultiPolygon.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.Point',
+ ol.geom.Point,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'clone',
+ ol.geom.Point.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getCoordinates',
+ ol.geom.Point.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getType',
+ ol.geom.Point.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'intersectsExtent',
+ ol.geom.Point.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'setCoordinates',
+ ol.geom.Point.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.Polygon',
+ ol.geom.Polygon,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'appendLinearRing',
+ ol.geom.Polygon.prototype.appendLinearRing);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'clone',
+ ol.geom.Polygon.prototype.clone);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getArea',
+ ol.geom.Polygon.prototype.getArea);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getCoordinates',
+ ol.geom.Polygon.prototype.getCoordinates);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getInteriorPoint',
+ ol.geom.Polygon.prototype.getInteriorPoint);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getLinearRingCount',
+ ol.geom.Polygon.prototype.getLinearRingCount);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getLinearRing',
+ ol.geom.Polygon.prototype.getLinearRing);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getLinearRings',
+ ol.geom.Polygon.prototype.getLinearRings);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getType',
+ ol.geom.Polygon.prototype.getType);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'intersectsExtent',
+ ol.geom.Polygon.prototype.intersectsExtent);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'setCoordinates',
+ ol.geom.Polygon.prototype.setCoordinates);
+
+goog.exportSymbol(
+ 'ol.geom.Polygon.circular',
+ ol.geom.Polygon.circular,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.geom.Polygon.fromExtent',
+ ol.geom.Polygon.fromExtent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.geom.Polygon.fromCircle',
+ ol.geom.Polygon.fromCircle,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.geom.SimpleGeometry',
+ ol.geom.SimpleGeometry,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getFirstCoordinate',
+ ol.geom.SimpleGeometry.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getLastCoordinate',
+ ol.geom.SimpleGeometry.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getLayout',
+ ol.geom.SimpleGeometry.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'applyTransform',
+ ol.geom.SimpleGeometry.prototype.applyTransform);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'translate',
+ ol.geom.SimpleGeometry.prototype.translate);
+
+goog.exportSymbol(
+ 'ol.format.EsriJSON',
+ ol.format.EsriJSON,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'readFeature',
+ ol.format.EsriJSON.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'readFeatures',
+ ol.format.EsriJSON.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'readGeometry',
+ ol.format.EsriJSON.prototype.readGeometry);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'readProjection',
+ ol.format.EsriJSON.prototype.readProjection);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'writeGeometry',
+ ol.format.EsriJSON.prototype.writeGeometry);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'writeGeometryObject',
+ ol.format.EsriJSON.prototype.writeGeometryObject);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'writeFeature',
+ ol.format.EsriJSON.prototype.writeFeature);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'writeFeatureObject',
+ ol.format.EsriJSON.prototype.writeFeatureObject);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'writeFeatures',
+ ol.format.EsriJSON.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.EsriJSON.prototype,
+ 'writeFeaturesObject',
+ ol.format.EsriJSON.prototype.writeFeaturesObject);
+
+goog.exportSymbol(
+ 'ol.format.Feature',
+ ol.format.Feature,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.GeoJSON',
+ ol.format.GeoJSON,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'readFeature',
+ ol.format.GeoJSON.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'readFeatures',
+ ol.format.GeoJSON.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'readGeometry',
+ ol.format.GeoJSON.prototype.readGeometry);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'readProjection',
+ ol.format.GeoJSON.prototype.readProjection);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'writeFeature',
+ ol.format.GeoJSON.prototype.writeFeature);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'writeFeatureObject',
+ ol.format.GeoJSON.prototype.writeFeatureObject);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'writeFeatures',
+ ol.format.GeoJSON.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'writeFeaturesObject',
+ ol.format.GeoJSON.prototype.writeFeaturesObject);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'writeGeometry',
+ ol.format.GeoJSON.prototype.writeGeometry);
+
+goog.exportProperty(
+ ol.format.GeoJSON.prototype,
+ 'writeGeometryObject',
+ ol.format.GeoJSON.prototype.writeGeometryObject);
+
+goog.exportSymbol(
+ 'ol.format.GPX',
+ ol.format.GPX,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.GPX.prototype,
+ 'readFeature',
+ ol.format.GPX.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.GPX.prototype,
+ 'readFeatures',
+ ol.format.GPX.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.GPX.prototype,
+ 'readProjection',
+ ol.format.GPX.prototype.readProjection);
+
+goog.exportProperty(
+ ol.format.GPX.prototype,
+ 'writeFeatures',
+ ol.format.GPX.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.GPX.prototype,
+ 'writeFeaturesNode',
+ ol.format.GPX.prototype.writeFeaturesNode);
+
+goog.exportSymbol(
+ 'ol.format.IGC',
+ ol.format.IGC,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.IGC.prototype,
+ 'readFeature',
+ ol.format.IGC.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.IGC.prototype,
+ 'readFeatures',
+ ol.format.IGC.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.IGC.prototype,
+ 'readProjection',
+ ol.format.IGC.prototype.readProjection);
+
+goog.exportSymbol(
+ 'ol.format.KML',
+ ol.format.KML,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'readFeature',
+ ol.format.KML.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'readFeatures',
+ ol.format.KML.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'readName',
+ ol.format.KML.prototype.readName);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'readNetworkLinks',
+ ol.format.KML.prototype.readNetworkLinks);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'readProjection',
+ ol.format.KML.prototype.readProjection);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'writeFeatures',
+ ol.format.KML.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.KML.prototype,
+ 'writeFeaturesNode',
+ ol.format.KML.prototype.writeFeaturesNode);
+
+goog.exportSymbol(
+ 'ol.format.MVT',
+ ol.format.MVT,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.MVT.prototype,
+ 'readFeatures',
+ ol.format.MVT.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.MVT.prototype,
+ 'readProjection',
+ ol.format.MVT.prototype.readProjection);
+
+goog.exportProperty(
+ ol.format.MVT.prototype,
+ 'setLayers',
+ ol.format.MVT.prototype.setLayers);
+
+goog.exportSymbol(
+ 'ol.format.OSMXML',
+ ol.format.OSMXML,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.OSMXML.prototype,
+ 'readFeatures',
+ ol.format.OSMXML.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.OSMXML.prototype,
+ 'readProjection',
+ ol.format.OSMXML.prototype.readProjection);
+
+goog.exportSymbol(
+ 'ol.format.Polyline',
+ ol.format.Polyline,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.Polyline.encodeDeltas',
+ ol.format.Polyline.encodeDeltas,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.Polyline.decodeDeltas',
+ ol.format.Polyline.decodeDeltas,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.Polyline.encodeFloats',
+ ol.format.Polyline.encodeFloats,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.Polyline.decodeFloats',
+ ol.format.Polyline.decodeFloats,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.Polyline.prototype,
+ 'readFeature',
+ ol.format.Polyline.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.Polyline.prototype,
+ 'readFeatures',
+ ol.format.Polyline.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.Polyline.prototype,
+ 'readGeometry',
+ ol.format.Polyline.prototype.readGeometry);
+
+goog.exportProperty(
+ ol.format.Polyline.prototype,
+ 'readProjection',
+ ol.format.Polyline.prototype.readProjection);
+
+goog.exportProperty(
+ ol.format.Polyline.prototype,
+ 'writeGeometry',
+ ol.format.Polyline.prototype.writeGeometry);
+
+goog.exportSymbol(
+ 'ol.format.TopoJSON',
+ ol.format.TopoJSON,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.TopoJSON.prototype,
+ 'readFeatures',
+ ol.format.TopoJSON.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.TopoJSON.prototype,
+ 'readProjection',
+ ol.format.TopoJSON.prototype.readProjection);
+
+goog.exportSymbol(
+ 'ol.format.WFS',
+ ol.format.WFS,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.WFS.prototype,
+ 'readFeatures',
+ ol.format.WFS.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.WFS.prototype,
+ 'readTransactionResponse',
+ ol.format.WFS.prototype.readTransactionResponse);
+
+goog.exportProperty(
+ ol.format.WFS.prototype,
+ 'readFeatureCollectionMetadata',
+ ol.format.WFS.prototype.readFeatureCollectionMetadata);
+
+goog.exportProperty(
+ ol.format.WFS.prototype,
+ 'writeGetFeature',
+ ol.format.WFS.prototype.writeGetFeature);
+
+goog.exportProperty(
+ ol.format.WFS.prototype,
+ 'writeTransaction',
+ ol.format.WFS.prototype.writeTransaction);
+
+goog.exportProperty(
+ ol.format.WFS.prototype,
+ 'readProjection',
+ ol.format.WFS.prototype.readProjection);
+
+goog.exportSymbol(
+ 'ol.format.WKT',
+ ol.format.WKT,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.WKT.prototype,
+ 'readFeature',
+ ol.format.WKT.prototype.readFeature);
+
+goog.exportProperty(
+ ol.format.WKT.prototype,
+ 'readFeatures',
+ ol.format.WKT.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.WKT.prototype,
+ 'readGeometry',
+ ol.format.WKT.prototype.readGeometry);
+
+goog.exportProperty(
+ ol.format.WKT.prototype,
+ 'writeFeature',
+ ol.format.WKT.prototype.writeFeature);
+
+goog.exportProperty(
+ ol.format.WKT.prototype,
+ 'writeFeatures',
+ ol.format.WKT.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.WKT.prototype,
+ 'writeGeometry',
+ ol.format.WKT.prototype.writeGeometry);
+
+goog.exportSymbol(
+ 'ol.format.WMSCapabilities',
+ ol.format.WMSCapabilities,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.WMSCapabilities.prototype,
+ 'read',
+ ol.format.WMSCapabilities.prototype.read);
+
+goog.exportSymbol(
+ 'ol.format.WMSGetFeatureInfo',
+ ol.format.WMSGetFeatureInfo,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.WMSGetFeatureInfo.prototype,
+ 'readFeatures',
+ ol.format.WMSGetFeatureInfo.prototype.readFeatures);
+
+goog.exportSymbol(
+ 'ol.format.WMTSCapabilities',
+ ol.format.WMTSCapabilities,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.WMTSCapabilities.prototype,
+ 'read',
+ ol.format.WMTSCapabilities.prototype.read);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.and',
+ ol.format.ogc.filter.and,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.or',
+ ol.format.ogc.filter.or,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.not',
+ ol.format.ogc.filter.not,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.bbox',
+ ol.format.ogc.filter.bbox,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.equalTo',
+ ol.format.ogc.filter.equalTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.notEqualTo',
+ ol.format.ogc.filter.notEqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.lessThan',
+ ol.format.ogc.filter.lessThan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.lessThanOrEqualTo',
+ ol.format.ogc.filter.lessThanOrEqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.greaterThan',
+ ol.format.ogc.filter.greaterThan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.greaterThanOrEqualTo',
+ ol.format.ogc.filter.greaterThanOrEqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.isNull',
+ ol.format.ogc.filter.isNull,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.between',
+ ol.format.ogc.filter.between,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.like',
+ ol.format.ogc.filter.like,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.Filter',
+ ol.format.ogc.filter.Filter,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.And',
+ ol.format.ogc.filter.And,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.Or',
+ ol.format.ogc.filter.Or,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.Not',
+ ol.format.ogc.filter.Not,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.Bbox',
+ ol.format.ogc.filter.Bbox,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.Comparison',
+ ol.format.ogc.filter.Comparison,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.ComparisonBinary',
+ ol.format.ogc.filter.ComparisonBinary,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.EqualTo',
+ ol.format.ogc.filter.EqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.NotEqualTo',
+ ol.format.ogc.filter.NotEqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.LessThan',
+ ol.format.ogc.filter.LessThan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.LessThanOrEqualTo',
+ ol.format.ogc.filter.LessThanOrEqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.GreaterThan',
+ ol.format.ogc.filter.GreaterThan,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.GreaterThanOrEqualTo',
+ ol.format.ogc.filter.GreaterThanOrEqualTo,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.IsNull',
+ ol.format.ogc.filter.IsNull,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.IsBetween',
+ ol.format.ogc.filter.IsBetween,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.ogc.filter.IsLike',
+ ol.format.ogc.filter.IsLike,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.GML2',
+ ol.format.GML2,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.format.GML3',
+ ol.format.GML3,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.GML3.prototype,
+ 'writeGeometryNode',
+ ol.format.GML3.prototype.writeGeometryNode);
+
+goog.exportProperty(
+ ol.format.GML3.prototype,
+ 'writeFeatures',
+ ol.format.GML3.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.GML3.prototype,
+ 'writeFeaturesNode',
+ ol.format.GML3.prototype.writeFeaturesNode);
+
+goog.exportSymbol(
+ 'ol.format.GML',
+ ol.format.GML,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.format.GML.prototype,
+ 'writeFeatures',
+ ol.format.GML.prototype.writeFeatures);
+
+goog.exportProperty(
+ ol.format.GML.prototype,
+ 'writeFeaturesNode',
+ ol.format.GML.prototype.writeFeaturesNode);
+
+goog.exportProperty(
+ ol.format.GMLBase.prototype,
+ 'readFeatures',
+ ol.format.GMLBase.prototype.readFeatures);
+
+goog.exportSymbol(
+ 'ol.events.condition.altKeyOnly',
+ ol.events.condition.altKeyOnly,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.altShiftKeysOnly',
+ ol.events.condition.altShiftKeysOnly,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.always',
+ ol.events.condition.always,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.click',
+ ol.events.condition.click,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.never',
+ ol.events.condition.never,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.pointerMove',
+ ol.events.condition.pointerMove,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.singleClick',
+ ol.events.condition.singleClick,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.doubleClick',
+ ol.events.condition.doubleClick,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.noModifierKeys',
+ ol.events.condition.noModifierKeys,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.platformModifierKeyOnly',
+ ol.events.condition.platformModifierKeyOnly,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.shiftKeyOnly',
+ ol.events.condition.shiftKeyOnly,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.targetNotEditable',
+ ol.events.condition.targetNotEditable,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.mouseOnly',
+ ol.events.condition.mouseOnly,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.events.condition.primaryAction',
+ ol.events.condition.primaryAction,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.events.Event.prototype,
+ 'type',
+ ol.events.Event.prototype.type);
+
+goog.exportProperty(
+ ol.events.Event.prototype,
+ 'target',
+ ol.events.Event.prototype.target);
+
+goog.exportProperty(
+ ol.events.Event.prototype,
+ 'preventDefault',
+ ol.events.Event.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.events.Event.prototype,
+ 'stopPropagation',
+ ol.events.Event.prototype.stopPropagation);
+
+goog.exportSymbol(
+ 'ol.control.Attribution',
+ ol.control.Attribution,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.Attribution.render',
+ ol.control.Attribution.render,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'getCollapsible',
+ ol.control.Attribution.prototype.getCollapsible);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'setCollapsible',
+ ol.control.Attribution.prototype.setCollapsible);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'setCollapsed',
+ ol.control.Attribution.prototype.setCollapsed);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'getCollapsed',
+ ol.control.Attribution.prototype.getCollapsed);
+
+goog.exportSymbol(
+ 'ol.control.Control',
+ ol.control.Control,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'getMap',
+ ol.control.Control.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'setMap',
+ ol.control.Control.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'setTarget',
+ ol.control.Control.prototype.setTarget);
+
+goog.exportSymbol(
+ 'ol.control.defaults',
+ ol.control.defaults,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.FullScreen',
+ ol.control.FullScreen,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.MousePosition',
+ ol.control.MousePosition,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.MousePosition.render',
+ ol.control.MousePosition.render,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'getCoordinateFormat',
+ ol.control.MousePosition.prototype.getCoordinateFormat);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'getProjection',
+ ol.control.MousePosition.prototype.getProjection);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'setCoordinateFormat',
+ ol.control.MousePosition.prototype.setCoordinateFormat);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'setProjection',
+ ol.control.MousePosition.prototype.setProjection);
+
+goog.exportSymbol(
+ 'ol.control.OverviewMap',
+ ol.control.OverviewMap,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.OverviewMap.render',
+ ol.control.OverviewMap.render,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getCollapsible',
+ ol.control.OverviewMap.prototype.getCollapsible);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'setCollapsible',
+ ol.control.OverviewMap.prototype.setCollapsible);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'setCollapsed',
+ ol.control.OverviewMap.prototype.setCollapsed);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getCollapsed',
+ ol.control.OverviewMap.prototype.getCollapsed);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getOverviewMap',
+ ol.control.OverviewMap.prototype.getOverviewMap);
+
+goog.exportSymbol(
+ 'ol.control.Rotate',
+ ol.control.Rotate,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.Rotate.render',
+ ol.control.Rotate.render,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.ScaleLine',
+ ol.control.ScaleLine,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'getUnits',
+ ol.control.ScaleLine.prototype.getUnits);
+
+goog.exportSymbol(
+ 'ol.control.ScaleLine.render',
+ ol.control.ScaleLine.render,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'setUnits',
+ ol.control.ScaleLine.prototype.setUnits);
+
+goog.exportSymbol(
+ 'ol.control.Zoom',
+ ol.control.Zoom,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.ZoomSlider',
+ ol.control.ZoomSlider,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.ZoomSlider.render',
+ ol.control.ZoomSlider.render,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.control.ZoomToExtent',
+ ol.control.ZoomToExtent,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.color.asArray',
+ ol.color.asArray,
+ OPENLAYERS);
+
+goog.exportSymbol(
+ 'ol.color.asString',
+ ol.color.asString,
+ OPENLAYERS);
+
+goog.exportProperty(
+ ol.CollectionEvent.prototype,
+ 'type',
+ ol.CollectionEvent.prototype.type);
+
+goog.exportProperty(
+ ol.CollectionEvent.prototype,
+ 'target',
+ ol.CollectionEvent.prototype.target);
+
+goog.exportProperty(
+ ol.CollectionEvent.prototype,
+ 'preventDefault',
+ ol.CollectionEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.CollectionEvent.prototype,
+ 'stopPropagation',
+ ol.CollectionEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'changed',
+ ol.Object.prototype.changed);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'dispatchEvent',
+ ol.Object.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'getRevision',
+ ol.Object.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'on',
+ ol.Object.prototype.on);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'once',
+ ol.Object.prototype.once);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'un',
+ ol.Object.prototype.un);
+
+goog.exportProperty(
+ ol.Object.prototype,
+ 'unByKey',
+ ol.Object.prototype.unByKey);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'get',
+ ol.Collection.prototype.get);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'getKeys',
+ ol.Collection.prototype.getKeys);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'getProperties',
+ ol.Collection.prototype.getProperties);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'set',
+ ol.Collection.prototype.set);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'setProperties',
+ ol.Collection.prototype.setProperties);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'unset',
+ ol.Collection.prototype.unset);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'changed',
+ ol.Collection.prototype.changed);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'dispatchEvent',
+ ol.Collection.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'getRevision',
+ ol.Collection.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'on',
+ ol.Collection.prototype.on);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'once',
+ ol.Collection.prototype.once);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'un',
+ ol.Collection.prototype.un);
+
+goog.exportProperty(
+ ol.Collection.prototype,
+ 'unByKey',
+ ol.Collection.prototype.unByKey);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'get',
+ ol.DeviceOrientation.prototype.get);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getKeys',
+ ol.DeviceOrientation.prototype.getKeys);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getProperties',
+ ol.DeviceOrientation.prototype.getProperties);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'set',
+ ol.DeviceOrientation.prototype.set);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'setProperties',
+ ol.DeviceOrientation.prototype.setProperties);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'unset',
+ ol.DeviceOrientation.prototype.unset);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'changed',
+ ol.DeviceOrientation.prototype.changed);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'dispatchEvent',
+ ol.DeviceOrientation.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'getRevision',
+ ol.DeviceOrientation.prototype.getRevision);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'on',
+ ol.DeviceOrientation.prototype.on);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'once',
+ ol.DeviceOrientation.prototype.once);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'un',
+ ol.DeviceOrientation.prototype.un);
+
+goog.exportProperty(
+ ol.DeviceOrientation.prototype,
+ 'unByKey',
+ ol.DeviceOrientation.prototype.unByKey);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'get',
+ ol.Feature.prototype.get);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getKeys',
+ ol.Feature.prototype.getKeys);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getProperties',
+ ol.Feature.prototype.getProperties);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'set',
+ ol.Feature.prototype.set);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'setProperties',
+ ol.Feature.prototype.setProperties);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'unset',
+ ol.Feature.prototype.unset);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'changed',
+ ol.Feature.prototype.changed);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'dispatchEvent',
+ ol.Feature.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'getRevision',
+ ol.Feature.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'on',
+ ol.Feature.prototype.on);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'once',
+ ol.Feature.prototype.once);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'un',
+ ol.Feature.prototype.un);
+
+goog.exportProperty(
+ ol.Feature.prototype,
+ 'unByKey',
+ ol.Feature.prototype.unByKey);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'get',
+ ol.Geolocation.prototype.get);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getKeys',
+ ol.Geolocation.prototype.getKeys);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getProperties',
+ ol.Geolocation.prototype.getProperties);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'set',
+ ol.Geolocation.prototype.set);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'setProperties',
+ ol.Geolocation.prototype.setProperties);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'unset',
+ ol.Geolocation.prototype.unset);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'changed',
+ ol.Geolocation.prototype.changed);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'dispatchEvent',
+ ol.Geolocation.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'getRevision',
+ ol.Geolocation.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'on',
+ ol.Geolocation.prototype.on);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'once',
+ ol.Geolocation.prototype.once);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'un',
+ ol.Geolocation.prototype.un);
+
+goog.exportProperty(
+ ol.Geolocation.prototype,
+ 'unByKey',
+ ol.Geolocation.prototype.unByKey);
+
+goog.exportProperty(
+ ol.ImageTile.prototype,
+ 'getTileCoord',
+ ol.ImageTile.prototype.getTileCoord);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'get',
+ ol.Map.prototype.get);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getKeys',
+ ol.Map.prototype.getKeys);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getProperties',
+ ol.Map.prototype.getProperties);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'set',
+ ol.Map.prototype.set);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'setProperties',
+ ol.Map.prototype.setProperties);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'unset',
+ ol.Map.prototype.unset);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'changed',
+ ol.Map.prototype.changed);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'dispatchEvent',
+ ol.Map.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'getRevision',
+ ol.Map.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'on',
+ ol.Map.prototype.on);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'once',
+ ol.Map.prototype.once);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'un',
+ ol.Map.prototype.un);
+
+goog.exportProperty(
+ ol.Map.prototype,
+ 'unByKey',
+ ol.Map.prototype.unByKey);
+
+goog.exportProperty(
+ ol.MapEvent.prototype,
+ 'type',
+ ol.MapEvent.prototype.type);
+
+goog.exportProperty(
+ ol.MapEvent.prototype,
+ 'target',
+ ol.MapEvent.prototype.target);
+
+goog.exportProperty(
+ ol.MapEvent.prototype,
+ 'preventDefault',
+ ol.MapEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.MapEvent.prototype,
+ 'stopPropagation',
+ ol.MapEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'map',
+ ol.MapBrowserEvent.prototype.map);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'frameState',
+ ol.MapBrowserEvent.prototype.frameState);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'type',
+ ol.MapBrowserEvent.prototype.type);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'target',
+ ol.MapBrowserEvent.prototype.target);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'preventDefault',
+ ol.MapBrowserEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.MapBrowserEvent.prototype,
+ 'stopPropagation',
+ ol.MapBrowserEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'originalEvent',
+ ol.MapBrowserPointerEvent.prototype.originalEvent);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'pixel',
+ ol.MapBrowserPointerEvent.prototype.pixel);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'coordinate',
+ ol.MapBrowserPointerEvent.prototype.coordinate);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'dragging',
+ ol.MapBrowserPointerEvent.prototype.dragging);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'preventDefault',
+ ol.MapBrowserPointerEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'stopPropagation',
+ ol.MapBrowserPointerEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'map',
+ ol.MapBrowserPointerEvent.prototype.map);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'frameState',
+ ol.MapBrowserPointerEvent.prototype.frameState);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'type',
+ ol.MapBrowserPointerEvent.prototype.type);
+
+goog.exportProperty(
+ ol.MapBrowserPointerEvent.prototype,
+ 'target',
+ ol.MapBrowserPointerEvent.prototype.target);
+
+goog.exportProperty(
+ ol.ObjectEvent.prototype,
+ 'type',
+ ol.ObjectEvent.prototype.type);
+
+goog.exportProperty(
+ ol.ObjectEvent.prototype,
+ 'target',
+ ol.ObjectEvent.prototype.target);
+
+goog.exportProperty(
+ ol.ObjectEvent.prototype,
+ 'preventDefault',
+ ol.ObjectEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.ObjectEvent.prototype,
+ 'stopPropagation',
+ ol.ObjectEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'get',
+ ol.Overlay.prototype.get);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getKeys',
+ ol.Overlay.prototype.getKeys);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getProperties',
+ ol.Overlay.prototype.getProperties);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'set',
+ ol.Overlay.prototype.set);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'setProperties',
+ ol.Overlay.prototype.setProperties);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'unset',
+ ol.Overlay.prototype.unset);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'changed',
+ ol.Overlay.prototype.changed);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'dispatchEvent',
+ ol.Overlay.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'getRevision',
+ ol.Overlay.prototype.getRevision);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'on',
+ ol.Overlay.prototype.on);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'once',
+ ol.Overlay.prototype.once);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'un',
+ ol.Overlay.prototype.un);
+
+goog.exportProperty(
+ ol.Overlay.prototype,
+ 'unByKey',
+ ol.Overlay.prototype.unByKey);
+
+goog.exportProperty(
+ ol.VectorTile.prototype,
+ 'getTileCoord',
+ ol.VectorTile.prototype.getTileCoord);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'get',
+ ol.View.prototype.get);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getKeys',
+ ol.View.prototype.getKeys);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getProperties',
+ ol.View.prototype.getProperties);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'set',
+ ol.View.prototype.set);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'setProperties',
+ ol.View.prototype.setProperties);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'unset',
+ ol.View.prototype.unset);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'changed',
+ ol.View.prototype.changed);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'dispatchEvent',
+ ol.View.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'getRevision',
+ ol.View.prototype.getRevision);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'on',
+ ol.View.prototype.on);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'once',
+ ol.View.prototype.once);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'un',
+ ol.View.prototype.un);
+
+goog.exportProperty(
+ ol.View.prototype,
+ 'unByKey',
+ ol.View.prototype.unByKey);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'forEachTileCoord',
+ ol.tilegrid.WMTS.prototype.forEachTileCoord);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getMaxZoom',
+ ol.tilegrid.WMTS.prototype.getMaxZoom);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getMinZoom',
+ ol.tilegrid.WMTS.prototype.getMinZoom);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getOrigin',
+ ol.tilegrid.WMTS.prototype.getOrigin);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getResolution',
+ ol.tilegrid.WMTS.prototype.getResolution);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getResolutions',
+ ol.tilegrid.WMTS.prototype.getResolutions);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getTileCoordExtent',
+ ol.tilegrid.WMTS.prototype.getTileCoordExtent);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getTileCoordForCoordAndResolution',
+ ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndResolution);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getTileCoordForCoordAndZ',
+ ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndZ);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getTileSize',
+ ol.tilegrid.WMTS.prototype.getTileSize);
+
+goog.exportProperty(
+ ol.tilegrid.WMTS.prototype,
+ 'getZForResolution',
+ ol.tilegrid.WMTS.prototype.getZForResolution);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getOpacity',
+ ol.style.Circle.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getRotateWithView',
+ ol.style.Circle.prototype.getRotateWithView);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getRotation',
+ ol.style.Circle.prototype.getRotation);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getScale',
+ ol.style.Circle.prototype.getScale);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'getSnapToPixel',
+ ol.style.Circle.prototype.getSnapToPixel);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'setOpacity',
+ ol.style.Circle.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'setRotation',
+ ol.style.Circle.prototype.setRotation);
+
+goog.exportProperty(
+ ol.style.Circle.prototype,
+ 'setScale',
+ ol.style.Circle.prototype.setScale);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getOpacity',
+ ol.style.Icon.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getRotateWithView',
+ ol.style.Icon.prototype.getRotateWithView);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getRotation',
+ ol.style.Icon.prototype.getRotation);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getScale',
+ ol.style.Icon.prototype.getScale);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'getSnapToPixel',
+ ol.style.Icon.prototype.getSnapToPixel);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'setOpacity',
+ ol.style.Icon.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'setRotation',
+ ol.style.Icon.prototype.setRotation);
+
+goog.exportProperty(
+ ol.style.Icon.prototype,
+ 'setScale',
+ ol.style.Icon.prototype.setScale);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getOpacity',
+ ol.style.RegularShape.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getRotateWithView',
+ ol.style.RegularShape.prototype.getRotateWithView);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getRotation',
+ ol.style.RegularShape.prototype.getRotation);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getScale',
+ ol.style.RegularShape.prototype.getScale);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'getSnapToPixel',
+ ol.style.RegularShape.prototype.getSnapToPixel);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'setOpacity',
+ ol.style.RegularShape.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'setRotation',
+ ol.style.RegularShape.prototype.setRotation);
+
+goog.exportProperty(
+ ol.style.RegularShape.prototype,
+ 'setScale',
+ ol.style.RegularShape.prototype.setScale);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'get',
+ ol.source.Source.prototype.get);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getKeys',
+ ol.source.Source.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getProperties',
+ ol.source.Source.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'set',
+ ol.source.Source.prototype.set);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'setProperties',
+ ol.source.Source.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'unset',
+ ol.source.Source.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'changed',
+ ol.source.Source.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'dispatchEvent',
+ ol.source.Source.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'getRevision',
+ ol.source.Source.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'on',
+ ol.source.Source.prototype.on);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'once',
+ ol.source.Source.prototype.once);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'un',
+ ol.source.Source.prototype.un);
+
+goog.exportProperty(
+ ol.source.Source.prototype,
+ 'unByKey',
+ ol.source.Source.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getAttributions',
+ ol.source.Tile.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getLogo',
+ ol.source.Tile.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getProjection',
+ ol.source.Tile.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getState',
+ ol.source.Tile.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'refresh',
+ ol.source.Tile.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'setAttributions',
+ ol.source.Tile.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'get',
+ ol.source.Tile.prototype.get);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getKeys',
+ ol.source.Tile.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getProperties',
+ ol.source.Tile.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'set',
+ ol.source.Tile.prototype.set);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'setProperties',
+ ol.source.Tile.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'unset',
+ ol.source.Tile.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'changed',
+ ol.source.Tile.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'dispatchEvent',
+ ol.source.Tile.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'getRevision',
+ ol.source.Tile.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'on',
+ ol.source.Tile.prototype.on);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'once',
+ ol.source.Tile.prototype.once);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'un',
+ ol.source.Tile.prototype.un);
+
+goog.exportProperty(
+ ol.source.Tile.prototype,
+ 'unByKey',
+ ol.source.Tile.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getTileGrid',
+ ol.source.UrlTile.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'refresh',
+ ol.source.UrlTile.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getAttributions',
+ ol.source.UrlTile.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getLogo',
+ ol.source.UrlTile.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getProjection',
+ ol.source.UrlTile.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getState',
+ ol.source.UrlTile.prototype.getState);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'setAttributions',
+ ol.source.UrlTile.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'get',
+ ol.source.UrlTile.prototype.get);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getKeys',
+ ol.source.UrlTile.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getProperties',
+ ol.source.UrlTile.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'set',
+ ol.source.UrlTile.prototype.set);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'setProperties',
+ ol.source.UrlTile.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'unset',
+ ol.source.UrlTile.prototype.unset);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'changed',
+ ol.source.UrlTile.prototype.changed);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'dispatchEvent',
+ ol.source.UrlTile.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'getRevision',
+ ol.source.UrlTile.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'on',
+ ol.source.UrlTile.prototype.on);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'once',
+ ol.source.UrlTile.prototype.once);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'un',
+ ol.source.UrlTile.prototype.un);
+
+goog.exportProperty(
+ ol.source.UrlTile.prototype,
+ 'unByKey',
+ ol.source.UrlTile.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getTileLoadFunction',
+ ol.source.TileImage.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getTileUrlFunction',
+ ol.source.TileImage.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getUrls',
+ ol.source.TileImage.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setTileLoadFunction',
+ ol.source.TileImage.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setTileUrlFunction',
+ ol.source.TileImage.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setUrl',
+ ol.source.TileImage.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setUrls',
+ ol.source.TileImage.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getTileGrid',
+ ol.source.TileImage.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'refresh',
+ ol.source.TileImage.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getAttributions',
+ ol.source.TileImage.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getLogo',
+ ol.source.TileImage.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getProjection',
+ ol.source.TileImage.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getState',
+ ol.source.TileImage.prototype.getState);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setAttributions',
+ ol.source.TileImage.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'get',
+ ol.source.TileImage.prototype.get);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getKeys',
+ ol.source.TileImage.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getProperties',
+ ol.source.TileImage.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'set',
+ ol.source.TileImage.prototype.set);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'setProperties',
+ ol.source.TileImage.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'unset',
+ ol.source.TileImage.prototype.unset);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'changed',
+ ol.source.TileImage.prototype.changed);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'dispatchEvent',
+ ol.source.TileImage.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'getRevision',
+ ol.source.TileImage.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'on',
+ ol.source.TileImage.prototype.on);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'once',
+ ol.source.TileImage.prototype.once);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'un',
+ ol.source.TileImage.prototype.un);
+
+goog.exportProperty(
+ ol.source.TileImage.prototype,
+ 'unByKey',
+ ol.source.TileImage.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.BingMaps.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setTileGridForProjection',
+ ol.source.BingMaps.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getTileLoadFunction',
+ ol.source.BingMaps.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getTileUrlFunction',
+ ol.source.BingMaps.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getUrls',
+ ol.source.BingMaps.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setTileLoadFunction',
+ ol.source.BingMaps.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setTileUrlFunction',
+ ol.source.BingMaps.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setUrl',
+ ol.source.BingMaps.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setUrls',
+ ol.source.BingMaps.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getTileGrid',
+ ol.source.BingMaps.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'refresh',
+ ol.source.BingMaps.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getAttributions',
+ ol.source.BingMaps.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getLogo',
+ ol.source.BingMaps.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getProjection',
+ ol.source.BingMaps.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getState',
+ ol.source.BingMaps.prototype.getState);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setAttributions',
+ ol.source.BingMaps.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'get',
+ ol.source.BingMaps.prototype.get);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getKeys',
+ ol.source.BingMaps.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getProperties',
+ ol.source.BingMaps.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'set',
+ ol.source.BingMaps.prototype.set);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'setProperties',
+ ol.source.BingMaps.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'unset',
+ ol.source.BingMaps.prototype.unset);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'changed',
+ ol.source.BingMaps.prototype.changed);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'dispatchEvent',
+ ol.source.BingMaps.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'getRevision',
+ ol.source.BingMaps.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'on',
+ ol.source.BingMaps.prototype.on);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'once',
+ ol.source.BingMaps.prototype.once);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'un',
+ ol.source.BingMaps.prototype.un);
+
+goog.exportProperty(
+ ol.source.BingMaps.prototype,
+ 'unByKey',
+ ol.source.BingMaps.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.XYZ.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setTileGridForProjection',
+ ol.source.XYZ.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getTileLoadFunction',
+ ol.source.XYZ.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getTileUrlFunction',
+ ol.source.XYZ.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getUrls',
+ ol.source.XYZ.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setTileLoadFunction',
+ ol.source.XYZ.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setTileUrlFunction',
+ ol.source.XYZ.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setUrl',
+ ol.source.XYZ.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setUrls',
+ ol.source.XYZ.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getTileGrid',
+ ol.source.XYZ.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'refresh',
+ ol.source.XYZ.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getAttributions',
+ ol.source.XYZ.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getLogo',
+ ol.source.XYZ.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getProjection',
+ ol.source.XYZ.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getState',
+ ol.source.XYZ.prototype.getState);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setAttributions',
+ ol.source.XYZ.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'get',
+ ol.source.XYZ.prototype.get);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getKeys',
+ ol.source.XYZ.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getProperties',
+ ol.source.XYZ.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'set',
+ ol.source.XYZ.prototype.set);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'setProperties',
+ ol.source.XYZ.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'unset',
+ ol.source.XYZ.prototype.unset);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'changed',
+ ol.source.XYZ.prototype.changed);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'dispatchEvent',
+ ol.source.XYZ.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'getRevision',
+ ol.source.XYZ.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'on',
+ ol.source.XYZ.prototype.on);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'once',
+ ol.source.XYZ.prototype.once);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'un',
+ ol.source.XYZ.prototype.un);
+
+goog.exportProperty(
+ ol.source.XYZ.prototype,
+ 'unByKey',
+ ol.source.XYZ.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.CartoDB.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setTileGridForProjection',
+ ol.source.CartoDB.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getTileLoadFunction',
+ ol.source.CartoDB.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getTileUrlFunction',
+ ol.source.CartoDB.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getUrls',
+ ol.source.CartoDB.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setTileLoadFunction',
+ ol.source.CartoDB.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setTileUrlFunction',
+ ol.source.CartoDB.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setUrl',
+ ol.source.CartoDB.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setUrls',
+ ol.source.CartoDB.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getTileGrid',
+ ol.source.CartoDB.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'refresh',
+ ol.source.CartoDB.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getAttributions',
+ ol.source.CartoDB.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getLogo',
+ ol.source.CartoDB.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getProjection',
+ ol.source.CartoDB.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getState',
+ ol.source.CartoDB.prototype.getState);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setAttributions',
+ ol.source.CartoDB.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'get',
+ ol.source.CartoDB.prototype.get);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getKeys',
+ ol.source.CartoDB.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getProperties',
+ ol.source.CartoDB.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'set',
+ ol.source.CartoDB.prototype.set);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'setProperties',
+ ol.source.CartoDB.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'unset',
+ ol.source.CartoDB.prototype.unset);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'changed',
+ ol.source.CartoDB.prototype.changed);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'dispatchEvent',
+ ol.source.CartoDB.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'getRevision',
+ ol.source.CartoDB.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'on',
+ ol.source.CartoDB.prototype.on);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'once',
+ ol.source.CartoDB.prototype.once);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'un',
+ ol.source.CartoDB.prototype.un);
+
+goog.exportProperty(
+ ol.source.CartoDB.prototype,
+ 'unByKey',
+ ol.source.CartoDB.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getAttributions',
+ ol.source.Vector.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getLogo',
+ ol.source.Vector.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getProjection',
+ ol.source.Vector.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getState',
+ ol.source.Vector.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'refresh',
+ ol.source.Vector.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'setAttributions',
+ ol.source.Vector.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'get',
+ ol.source.Vector.prototype.get);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getKeys',
+ ol.source.Vector.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getProperties',
+ ol.source.Vector.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'set',
+ ol.source.Vector.prototype.set);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'setProperties',
+ ol.source.Vector.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'unset',
+ ol.source.Vector.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'changed',
+ ol.source.Vector.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'dispatchEvent',
+ ol.source.Vector.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'getRevision',
+ ol.source.Vector.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'on',
+ ol.source.Vector.prototype.on);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'once',
+ ol.source.Vector.prototype.once);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'un',
+ ol.source.Vector.prototype.un);
+
+goog.exportProperty(
+ ol.source.Vector.prototype,
+ 'unByKey',
+ ol.source.Vector.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'addFeature',
+ ol.source.Cluster.prototype.addFeature);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'addFeatures',
+ ol.source.Cluster.prototype.addFeatures);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'clear',
+ ol.source.Cluster.prototype.clear);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'forEachFeature',
+ ol.source.Cluster.prototype.forEachFeature);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'forEachFeatureInExtent',
+ ol.source.Cluster.prototype.forEachFeatureInExtent);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'forEachFeatureIntersectingExtent',
+ ol.source.Cluster.prototype.forEachFeatureIntersectingExtent);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getFeaturesCollection',
+ ol.source.Cluster.prototype.getFeaturesCollection);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getFeatures',
+ ol.source.Cluster.prototype.getFeatures);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getFeaturesAtCoordinate',
+ ol.source.Cluster.prototype.getFeaturesAtCoordinate);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getFeaturesInExtent',
+ ol.source.Cluster.prototype.getFeaturesInExtent);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getClosestFeatureToCoordinate',
+ ol.source.Cluster.prototype.getClosestFeatureToCoordinate);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getExtent',
+ ol.source.Cluster.prototype.getExtent);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getFeatureById',
+ ol.source.Cluster.prototype.getFeatureById);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getFormat',
+ ol.source.Cluster.prototype.getFormat);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getUrl',
+ ol.source.Cluster.prototype.getUrl);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'removeFeature',
+ ol.source.Cluster.prototype.removeFeature);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getAttributions',
+ ol.source.Cluster.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getLogo',
+ ol.source.Cluster.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getProjection',
+ ol.source.Cluster.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getState',
+ ol.source.Cluster.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'refresh',
+ ol.source.Cluster.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'setAttributions',
+ ol.source.Cluster.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'get',
+ ol.source.Cluster.prototype.get);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getKeys',
+ ol.source.Cluster.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getProperties',
+ ol.source.Cluster.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'set',
+ ol.source.Cluster.prototype.set);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'setProperties',
+ ol.source.Cluster.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'unset',
+ ol.source.Cluster.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'changed',
+ ol.source.Cluster.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'dispatchEvent',
+ ol.source.Cluster.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'getRevision',
+ ol.source.Cluster.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'on',
+ ol.source.Cluster.prototype.on);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'once',
+ ol.source.Cluster.prototype.once);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'un',
+ ol.source.Cluster.prototype.un);
+
+goog.exportProperty(
+ ol.source.Cluster.prototype,
+ 'unByKey',
+ ol.source.Cluster.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getAttributions',
+ ol.source.Image.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getLogo',
+ ol.source.Image.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getProjection',
+ ol.source.Image.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getState',
+ ol.source.Image.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'refresh',
+ ol.source.Image.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'setAttributions',
+ ol.source.Image.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'get',
+ ol.source.Image.prototype.get);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getKeys',
+ ol.source.Image.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getProperties',
+ ol.source.Image.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'set',
+ ol.source.Image.prototype.set);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'setProperties',
+ ol.source.Image.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'unset',
+ ol.source.Image.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'changed',
+ ol.source.Image.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'dispatchEvent',
+ ol.source.Image.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'getRevision',
+ ol.source.Image.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'on',
+ ol.source.Image.prototype.on);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'once',
+ ol.source.Image.prototype.once);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'un',
+ ol.source.Image.prototype.un);
+
+goog.exportProperty(
+ ol.source.Image.prototype,
+ 'unByKey',
+ ol.source.Image.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getAttributions',
+ ol.source.ImageArcGISRest.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getLogo',
+ ol.source.ImageArcGISRest.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getProjection',
+ ol.source.ImageArcGISRest.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getState',
+ ol.source.ImageArcGISRest.prototype.getState);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'refresh',
+ ol.source.ImageArcGISRest.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'setAttributions',
+ ol.source.ImageArcGISRest.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'get',
+ ol.source.ImageArcGISRest.prototype.get);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getKeys',
+ ol.source.ImageArcGISRest.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getProperties',
+ ol.source.ImageArcGISRest.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'set',
+ ol.source.ImageArcGISRest.prototype.set);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'setProperties',
+ ol.source.ImageArcGISRest.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'unset',
+ ol.source.ImageArcGISRest.prototype.unset);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'changed',
+ ol.source.ImageArcGISRest.prototype.changed);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'dispatchEvent',
+ ol.source.ImageArcGISRest.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'getRevision',
+ ol.source.ImageArcGISRest.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'on',
+ ol.source.ImageArcGISRest.prototype.on);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'once',
+ ol.source.ImageArcGISRest.prototype.once);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'un',
+ ol.source.ImageArcGISRest.prototype.un);
+
+goog.exportProperty(
+ ol.source.ImageArcGISRest.prototype,
+ 'unByKey',
+ ol.source.ImageArcGISRest.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getAttributions',
+ ol.source.ImageCanvas.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getLogo',
+ ol.source.ImageCanvas.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getProjection',
+ ol.source.ImageCanvas.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getState',
+ ol.source.ImageCanvas.prototype.getState);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'refresh',
+ ol.source.ImageCanvas.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'setAttributions',
+ ol.source.ImageCanvas.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'get',
+ ol.source.ImageCanvas.prototype.get);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getKeys',
+ ol.source.ImageCanvas.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getProperties',
+ ol.source.ImageCanvas.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'set',
+ ol.source.ImageCanvas.prototype.set);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'setProperties',
+ ol.source.ImageCanvas.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'unset',
+ ol.source.ImageCanvas.prototype.unset);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'changed',
+ ol.source.ImageCanvas.prototype.changed);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'dispatchEvent',
+ ol.source.ImageCanvas.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'getRevision',
+ ol.source.ImageCanvas.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'on',
+ ol.source.ImageCanvas.prototype.on);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'once',
+ ol.source.ImageCanvas.prototype.once);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'un',
+ ol.source.ImageCanvas.prototype.un);
+
+goog.exportProperty(
+ ol.source.ImageCanvas.prototype,
+ 'unByKey',
+ ol.source.ImageCanvas.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getAttributions',
+ ol.source.ImageMapGuide.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getLogo',
+ ol.source.ImageMapGuide.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getProjection',
+ ol.source.ImageMapGuide.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getState',
+ ol.source.ImageMapGuide.prototype.getState);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'refresh',
+ ol.source.ImageMapGuide.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'setAttributions',
+ ol.source.ImageMapGuide.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'get',
+ ol.source.ImageMapGuide.prototype.get);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getKeys',
+ ol.source.ImageMapGuide.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getProperties',
+ ol.source.ImageMapGuide.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'set',
+ ol.source.ImageMapGuide.prototype.set);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'setProperties',
+ ol.source.ImageMapGuide.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'unset',
+ ol.source.ImageMapGuide.prototype.unset);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'changed',
+ ol.source.ImageMapGuide.prototype.changed);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'dispatchEvent',
+ ol.source.ImageMapGuide.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'getRevision',
+ ol.source.ImageMapGuide.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'on',
+ ol.source.ImageMapGuide.prototype.on);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'once',
+ ol.source.ImageMapGuide.prototype.once);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'un',
+ ol.source.ImageMapGuide.prototype.un);
+
+goog.exportProperty(
+ ol.source.ImageMapGuide.prototype,
+ 'unByKey',
+ ol.source.ImageMapGuide.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.ImageEvent.prototype,
+ 'type',
+ ol.source.ImageEvent.prototype.type);
+
+goog.exportProperty(
+ ol.source.ImageEvent.prototype,
+ 'target',
+ ol.source.ImageEvent.prototype.target);
+
+goog.exportProperty(
+ ol.source.ImageEvent.prototype,
+ 'preventDefault',
+ ol.source.ImageEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.source.ImageEvent.prototype,
+ 'stopPropagation',
+ ol.source.ImageEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getAttributions',
+ ol.source.ImageStatic.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getLogo',
+ ol.source.ImageStatic.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getProjection',
+ ol.source.ImageStatic.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getState',
+ ol.source.ImageStatic.prototype.getState);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'refresh',
+ ol.source.ImageStatic.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'setAttributions',
+ ol.source.ImageStatic.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'get',
+ ol.source.ImageStatic.prototype.get);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getKeys',
+ ol.source.ImageStatic.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getProperties',
+ ol.source.ImageStatic.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'set',
+ ol.source.ImageStatic.prototype.set);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'setProperties',
+ ol.source.ImageStatic.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'unset',
+ ol.source.ImageStatic.prototype.unset);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'changed',
+ ol.source.ImageStatic.prototype.changed);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'dispatchEvent',
+ ol.source.ImageStatic.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'getRevision',
+ ol.source.ImageStatic.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'on',
+ ol.source.ImageStatic.prototype.on);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'once',
+ ol.source.ImageStatic.prototype.once);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'un',
+ ol.source.ImageStatic.prototype.un);
+
+goog.exportProperty(
+ ol.source.ImageStatic.prototype,
+ 'unByKey',
+ ol.source.ImageStatic.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getAttributions',
+ ol.source.ImageVector.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getLogo',
+ ol.source.ImageVector.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getProjection',
+ ol.source.ImageVector.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getState',
+ ol.source.ImageVector.prototype.getState);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'refresh',
+ ol.source.ImageVector.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'setAttributions',
+ ol.source.ImageVector.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'get',
+ ol.source.ImageVector.prototype.get);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getKeys',
+ ol.source.ImageVector.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getProperties',
+ ol.source.ImageVector.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'set',
+ ol.source.ImageVector.prototype.set);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'setProperties',
+ ol.source.ImageVector.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'unset',
+ ol.source.ImageVector.prototype.unset);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'changed',
+ ol.source.ImageVector.prototype.changed);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'dispatchEvent',
+ ol.source.ImageVector.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'getRevision',
+ ol.source.ImageVector.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'on',
+ ol.source.ImageVector.prototype.on);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'once',
+ ol.source.ImageVector.prototype.once);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'un',
+ ol.source.ImageVector.prototype.un);
+
+goog.exportProperty(
+ ol.source.ImageVector.prototype,
+ 'unByKey',
+ ol.source.ImageVector.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getAttributions',
+ ol.source.ImageWMS.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getLogo',
+ ol.source.ImageWMS.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getProjection',
+ ol.source.ImageWMS.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getState',
+ ol.source.ImageWMS.prototype.getState);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'refresh',
+ ol.source.ImageWMS.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'setAttributions',
+ ol.source.ImageWMS.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'get',
+ ol.source.ImageWMS.prototype.get);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getKeys',
+ ol.source.ImageWMS.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getProperties',
+ ol.source.ImageWMS.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'set',
+ ol.source.ImageWMS.prototype.set);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'setProperties',
+ ol.source.ImageWMS.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'unset',
+ ol.source.ImageWMS.prototype.unset);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'changed',
+ ol.source.ImageWMS.prototype.changed);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'dispatchEvent',
+ ol.source.ImageWMS.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'getRevision',
+ ol.source.ImageWMS.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'on',
+ ol.source.ImageWMS.prototype.on);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'once',
+ ol.source.ImageWMS.prototype.once);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'un',
+ ol.source.ImageWMS.prototype.un);
+
+goog.exportProperty(
+ ol.source.ImageWMS.prototype,
+ 'unByKey',
+ ol.source.ImageWMS.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.OSM.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setTileGridForProjection',
+ ol.source.OSM.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getTileLoadFunction',
+ ol.source.OSM.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getTileUrlFunction',
+ ol.source.OSM.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getUrls',
+ ol.source.OSM.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setTileLoadFunction',
+ ol.source.OSM.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setTileUrlFunction',
+ ol.source.OSM.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setUrl',
+ ol.source.OSM.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setUrls',
+ ol.source.OSM.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getTileGrid',
+ ol.source.OSM.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'refresh',
+ ol.source.OSM.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getAttributions',
+ ol.source.OSM.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getLogo',
+ ol.source.OSM.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getProjection',
+ ol.source.OSM.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getState',
+ ol.source.OSM.prototype.getState);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setAttributions',
+ ol.source.OSM.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'get',
+ ol.source.OSM.prototype.get);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getKeys',
+ ol.source.OSM.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getProperties',
+ ol.source.OSM.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'set',
+ ol.source.OSM.prototype.set);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'setProperties',
+ ol.source.OSM.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'unset',
+ ol.source.OSM.prototype.unset);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'changed',
+ ol.source.OSM.prototype.changed);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'dispatchEvent',
+ ol.source.OSM.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'getRevision',
+ ol.source.OSM.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'on',
+ ol.source.OSM.prototype.on);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'once',
+ ol.source.OSM.prototype.once);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'un',
+ ol.source.OSM.prototype.un);
+
+goog.exportProperty(
+ ol.source.OSM.prototype,
+ 'unByKey',
+ ol.source.OSM.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getAttributions',
+ ol.source.Raster.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getLogo',
+ ol.source.Raster.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getProjection',
+ ol.source.Raster.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getState',
+ ol.source.Raster.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'refresh',
+ ol.source.Raster.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'setAttributions',
+ ol.source.Raster.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'get',
+ ol.source.Raster.prototype.get);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getKeys',
+ ol.source.Raster.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getProperties',
+ ol.source.Raster.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'set',
+ ol.source.Raster.prototype.set);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'setProperties',
+ ol.source.Raster.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'unset',
+ ol.source.Raster.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'changed',
+ ol.source.Raster.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'dispatchEvent',
+ ol.source.Raster.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'getRevision',
+ ol.source.Raster.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'on',
+ ol.source.Raster.prototype.on);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'once',
+ ol.source.Raster.prototype.once);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'un',
+ ol.source.Raster.prototype.un);
+
+goog.exportProperty(
+ ol.source.Raster.prototype,
+ 'unByKey',
+ ol.source.Raster.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'type',
+ ol.source.RasterEvent.prototype.type);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'target',
+ ol.source.RasterEvent.prototype.target);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'preventDefault',
+ ol.source.RasterEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.source.RasterEvent.prototype,
+ 'stopPropagation',
+ ol.source.RasterEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.Stamen.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setTileGridForProjection',
+ ol.source.Stamen.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getTileLoadFunction',
+ ol.source.Stamen.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getTileUrlFunction',
+ ol.source.Stamen.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getUrls',
+ ol.source.Stamen.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setTileLoadFunction',
+ ol.source.Stamen.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setTileUrlFunction',
+ ol.source.Stamen.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setUrl',
+ ol.source.Stamen.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setUrls',
+ ol.source.Stamen.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getTileGrid',
+ ol.source.Stamen.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'refresh',
+ ol.source.Stamen.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getAttributions',
+ ol.source.Stamen.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getLogo',
+ ol.source.Stamen.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getProjection',
+ ol.source.Stamen.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getState',
+ ol.source.Stamen.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setAttributions',
+ ol.source.Stamen.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'get',
+ ol.source.Stamen.prototype.get);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getKeys',
+ ol.source.Stamen.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getProperties',
+ ol.source.Stamen.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'set',
+ ol.source.Stamen.prototype.set);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'setProperties',
+ ol.source.Stamen.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'unset',
+ ol.source.Stamen.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'changed',
+ ol.source.Stamen.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'dispatchEvent',
+ ol.source.Stamen.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'getRevision',
+ ol.source.Stamen.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'on',
+ ol.source.Stamen.prototype.on);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'once',
+ ol.source.Stamen.prototype.once);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'un',
+ ol.source.Stamen.prototype.un);
+
+goog.exportProperty(
+ ol.source.Stamen.prototype,
+ 'unByKey',
+ ol.source.Stamen.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.TileArcGISRest.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setTileGridForProjection',
+ ol.source.TileArcGISRest.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getTileLoadFunction',
+ ol.source.TileArcGISRest.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getTileUrlFunction',
+ ol.source.TileArcGISRest.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getUrls',
+ ol.source.TileArcGISRest.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setTileLoadFunction',
+ ol.source.TileArcGISRest.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setTileUrlFunction',
+ ol.source.TileArcGISRest.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setUrl',
+ ol.source.TileArcGISRest.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setUrls',
+ ol.source.TileArcGISRest.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getTileGrid',
+ ol.source.TileArcGISRest.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'refresh',
+ ol.source.TileArcGISRest.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getAttributions',
+ ol.source.TileArcGISRest.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getLogo',
+ ol.source.TileArcGISRest.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getProjection',
+ ol.source.TileArcGISRest.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getState',
+ ol.source.TileArcGISRest.prototype.getState);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setAttributions',
+ ol.source.TileArcGISRest.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'get',
+ ol.source.TileArcGISRest.prototype.get);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getKeys',
+ ol.source.TileArcGISRest.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getProperties',
+ ol.source.TileArcGISRest.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'set',
+ ol.source.TileArcGISRest.prototype.set);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'setProperties',
+ ol.source.TileArcGISRest.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'unset',
+ ol.source.TileArcGISRest.prototype.unset);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'changed',
+ ol.source.TileArcGISRest.prototype.changed);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'dispatchEvent',
+ ol.source.TileArcGISRest.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'getRevision',
+ ol.source.TileArcGISRest.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'on',
+ ol.source.TileArcGISRest.prototype.on);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'once',
+ ol.source.TileArcGISRest.prototype.once);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'un',
+ ol.source.TileArcGISRest.prototype.un);
+
+goog.exportProperty(
+ ol.source.TileArcGISRest.prototype,
+ 'unByKey',
+ ol.source.TileArcGISRest.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getTileGrid',
+ ol.source.TileDebug.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'refresh',
+ ol.source.TileDebug.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getAttributions',
+ ol.source.TileDebug.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getLogo',
+ ol.source.TileDebug.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getProjection',
+ ol.source.TileDebug.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getState',
+ ol.source.TileDebug.prototype.getState);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'setAttributions',
+ ol.source.TileDebug.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'get',
+ ol.source.TileDebug.prototype.get);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getKeys',
+ ol.source.TileDebug.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getProperties',
+ ol.source.TileDebug.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'set',
+ ol.source.TileDebug.prototype.set);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'setProperties',
+ ol.source.TileDebug.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'unset',
+ ol.source.TileDebug.prototype.unset);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'changed',
+ ol.source.TileDebug.prototype.changed);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'dispatchEvent',
+ ol.source.TileDebug.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'getRevision',
+ ol.source.TileDebug.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'on',
+ ol.source.TileDebug.prototype.on);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'once',
+ ol.source.TileDebug.prototype.once);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'un',
+ ol.source.TileDebug.prototype.un);
+
+goog.exportProperty(
+ ol.source.TileDebug.prototype,
+ 'unByKey',
+ ol.source.TileDebug.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.TileJSON.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setTileGridForProjection',
+ ol.source.TileJSON.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getTileLoadFunction',
+ ol.source.TileJSON.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getTileUrlFunction',
+ ol.source.TileJSON.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getUrls',
+ ol.source.TileJSON.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setTileLoadFunction',
+ ol.source.TileJSON.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setTileUrlFunction',
+ ol.source.TileJSON.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setUrl',
+ ol.source.TileJSON.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setUrls',
+ ol.source.TileJSON.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getTileGrid',
+ ol.source.TileJSON.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'refresh',
+ ol.source.TileJSON.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getAttributions',
+ ol.source.TileJSON.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getLogo',
+ ol.source.TileJSON.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getProjection',
+ ol.source.TileJSON.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getState',
+ ol.source.TileJSON.prototype.getState);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setAttributions',
+ ol.source.TileJSON.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'get',
+ ol.source.TileJSON.prototype.get);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getKeys',
+ ol.source.TileJSON.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getProperties',
+ ol.source.TileJSON.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'set',
+ ol.source.TileJSON.prototype.set);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'setProperties',
+ ol.source.TileJSON.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'unset',
+ ol.source.TileJSON.prototype.unset);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'changed',
+ ol.source.TileJSON.prototype.changed);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'dispatchEvent',
+ ol.source.TileJSON.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'getRevision',
+ ol.source.TileJSON.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'on',
+ ol.source.TileJSON.prototype.on);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'once',
+ ol.source.TileJSON.prototype.once);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'un',
+ ol.source.TileJSON.prototype.un);
+
+goog.exportProperty(
+ ol.source.TileJSON.prototype,
+ 'unByKey',
+ ol.source.TileJSON.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.TileEvent.prototype,
+ 'type',
+ ol.source.TileEvent.prototype.type);
+
+goog.exportProperty(
+ ol.source.TileEvent.prototype,
+ 'target',
+ ol.source.TileEvent.prototype.target);
+
+goog.exportProperty(
+ ol.source.TileEvent.prototype,
+ 'preventDefault',
+ ol.source.TileEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.source.TileEvent.prototype,
+ 'stopPropagation',
+ ol.source.TileEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getTileGrid',
+ ol.source.TileUTFGrid.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'refresh',
+ ol.source.TileUTFGrid.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getAttributions',
+ ol.source.TileUTFGrid.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getLogo',
+ ol.source.TileUTFGrid.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getProjection',
+ ol.source.TileUTFGrid.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getState',
+ ol.source.TileUTFGrid.prototype.getState);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'setAttributions',
+ ol.source.TileUTFGrid.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'get',
+ ol.source.TileUTFGrid.prototype.get);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getKeys',
+ ol.source.TileUTFGrid.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getProperties',
+ ol.source.TileUTFGrid.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'set',
+ ol.source.TileUTFGrid.prototype.set);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'setProperties',
+ ol.source.TileUTFGrid.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'unset',
+ ol.source.TileUTFGrid.prototype.unset);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'changed',
+ ol.source.TileUTFGrid.prototype.changed);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'dispatchEvent',
+ ol.source.TileUTFGrid.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'getRevision',
+ ol.source.TileUTFGrid.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'on',
+ ol.source.TileUTFGrid.prototype.on);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'once',
+ ol.source.TileUTFGrid.prototype.once);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'un',
+ ol.source.TileUTFGrid.prototype.un);
+
+goog.exportProperty(
+ ol.source.TileUTFGrid.prototype,
+ 'unByKey',
+ ol.source.TileUTFGrid.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.TileWMS.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setTileGridForProjection',
+ ol.source.TileWMS.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getTileLoadFunction',
+ ol.source.TileWMS.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getTileUrlFunction',
+ ol.source.TileWMS.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getUrls',
+ ol.source.TileWMS.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setTileLoadFunction',
+ ol.source.TileWMS.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setTileUrlFunction',
+ ol.source.TileWMS.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setUrl',
+ ol.source.TileWMS.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setUrls',
+ ol.source.TileWMS.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getTileGrid',
+ ol.source.TileWMS.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'refresh',
+ ol.source.TileWMS.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getAttributions',
+ ol.source.TileWMS.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getLogo',
+ ol.source.TileWMS.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getProjection',
+ ol.source.TileWMS.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getState',
+ ol.source.TileWMS.prototype.getState);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setAttributions',
+ ol.source.TileWMS.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'get',
+ ol.source.TileWMS.prototype.get);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getKeys',
+ ol.source.TileWMS.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getProperties',
+ ol.source.TileWMS.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'set',
+ ol.source.TileWMS.prototype.set);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'setProperties',
+ ol.source.TileWMS.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'unset',
+ ol.source.TileWMS.prototype.unset);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'changed',
+ ol.source.TileWMS.prototype.changed);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'dispatchEvent',
+ ol.source.TileWMS.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'getRevision',
+ ol.source.TileWMS.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'on',
+ ol.source.TileWMS.prototype.on);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'once',
+ ol.source.TileWMS.prototype.once);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'un',
+ ol.source.TileWMS.prototype.un);
+
+goog.exportProperty(
+ ol.source.TileWMS.prototype,
+ 'unByKey',
+ ol.source.TileWMS.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.VectorEvent.prototype,
+ 'type',
+ ol.source.VectorEvent.prototype.type);
+
+goog.exportProperty(
+ ol.source.VectorEvent.prototype,
+ 'target',
+ ol.source.VectorEvent.prototype.target);
+
+goog.exportProperty(
+ ol.source.VectorEvent.prototype,
+ 'preventDefault',
+ ol.source.VectorEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.source.VectorEvent.prototype,
+ 'stopPropagation',
+ ol.source.VectorEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getTileLoadFunction',
+ ol.source.VectorTile.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getTileUrlFunction',
+ ol.source.VectorTile.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getUrls',
+ ol.source.VectorTile.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'setTileLoadFunction',
+ ol.source.VectorTile.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'setTileUrlFunction',
+ ol.source.VectorTile.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'setUrl',
+ ol.source.VectorTile.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'setUrls',
+ ol.source.VectorTile.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getTileGrid',
+ ol.source.VectorTile.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'refresh',
+ ol.source.VectorTile.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getAttributions',
+ ol.source.VectorTile.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getLogo',
+ ol.source.VectorTile.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getProjection',
+ ol.source.VectorTile.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getState',
+ ol.source.VectorTile.prototype.getState);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'setAttributions',
+ ol.source.VectorTile.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'get',
+ ol.source.VectorTile.prototype.get);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getKeys',
+ ol.source.VectorTile.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getProperties',
+ ol.source.VectorTile.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'set',
+ ol.source.VectorTile.prototype.set);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'setProperties',
+ ol.source.VectorTile.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'unset',
+ ol.source.VectorTile.prototype.unset);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'changed',
+ ol.source.VectorTile.prototype.changed);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'dispatchEvent',
+ ol.source.VectorTile.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'getRevision',
+ ol.source.VectorTile.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'on',
+ ol.source.VectorTile.prototype.on);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'once',
+ ol.source.VectorTile.prototype.once);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'un',
+ ol.source.VectorTile.prototype.un);
+
+goog.exportProperty(
+ ol.source.VectorTile.prototype,
+ 'unByKey',
+ ol.source.VectorTile.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.WMTS.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setTileGridForProjection',
+ ol.source.WMTS.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getTileLoadFunction',
+ ol.source.WMTS.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getTileUrlFunction',
+ ol.source.WMTS.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getUrls',
+ ol.source.WMTS.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setTileLoadFunction',
+ ol.source.WMTS.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setTileUrlFunction',
+ ol.source.WMTS.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setUrl',
+ ol.source.WMTS.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setUrls',
+ ol.source.WMTS.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getTileGrid',
+ ol.source.WMTS.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'refresh',
+ ol.source.WMTS.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getAttributions',
+ ol.source.WMTS.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getLogo',
+ ol.source.WMTS.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getProjection',
+ ol.source.WMTS.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getState',
+ ol.source.WMTS.prototype.getState);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setAttributions',
+ ol.source.WMTS.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'get',
+ ol.source.WMTS.prototype.get);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getKeys',
+ ol.source.WMTS.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getProperties',
+ ol.source.WMTS.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'set',
+ ol.source.WMTS.prototype.set);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'setProperties',
+ ol.source.WMTS.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'unset',
+ ol.source.WMTS.prototype.unset);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'changed',
+ ol.source.WMTS.prototype.changed);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'dispatchEvent',
+ ol.source.WMTS.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'getRevision',
+ ol.source.WMTS.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'on',
+ ol.source.WMTS.prototype.on);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'once',
+ ol.source.WMTS.prototype.once);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'un',
+ ol.source.WMTS.prototype.un);
+
+goog.exportProperty(
+ ol.source.WMTS.prototype,
+ 'unByKey',
+ ol.source.WMTS.prototype.unByKey);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setRenderReprojectionEdges',
+ ol.source.Zoomify.prototype.setRenderReprojectionEdges);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setTileGridForProjection',
+ ol.source.Zoomify.prototype.setTileGridForProjection);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getTileLoadFunction',
+ ol.source.Zoomify.prototype.getTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getTileUrlFunction',
+ ol.source.Zoomify.prototype.getTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getUrls',
+ ol.source.Zoomify.prototype.getUrls);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setTileLoadFunction',
+ ol.source.Zoomify.prototype.setTileLoadFunction);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setTileUrlFunction',
+ ol.source.Zoomify.prototype.setTileUrlFunction);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setUrl',
+ ol.source.Zoomify.prototype.setUrl);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setUrls',
+ ol.source.Zoomify.prototype.setUrls);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getTileGrid',
+ ol.source.Zoomify.prototype.getTileGrid);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'refresh',
+ ol.source.Zoomify.prototype.refresh);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getAttributions',
+ ol.source.Zoomify.prototype.getAttributions);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getLogo',
+ ol.source.Zoomify.prototype.getLogo);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getProjection',
+ ol.source.Zoomify.prototype.getProjection);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getState',
+ ol.source.Zoomify.prototype.getState);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setAttributions',
+ ol.source.Zoomify.prototype.setAttributions);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'get',
+ ol.source.Zoomify.prototype.get);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getKeys',
+ ol.source.Zoomify.prototype.getKeys);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getProperties',
+ ol.source.Zoomify.prototype.getProperties);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'set',
+ ol.source.Zoomify.prototype.set);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'setProperties',
+ ol.source.Zoomify.prototype.setProperties);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'unset',
+ ol.source.Zoomify.prototype.unset);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'changed',
+ ol.source.Zoomify.prototype.changed);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'dispatchEvent',
+ ol.source.Zoomify.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'getRevision',
+ ol.source.Zoomify.prototype.getRevision);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'on',
+ ol.source.Zoomify.prototype.on);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'once',
+ ol.source.Zoomify.prototype.once);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'un',
+ ol.source.Zoomify.prototype.un);
+
+goog.exportProperty(
+ ol.source.Zoomify.prototype,
+ 'unByKey',
+ ol.source.Zoomify.prototype.unByKey);
+
+goog.exportProperty(
+ ol.reproj.Tile.prototype,
+ 'getTileCoord',
+ ol.reproj.Tile.prototype.getTileCoord);
+
+goog.exportProperty(
+ ol.reproj.Tile.prototype,
+ 'load',
+ ol.reproj.Tile.prototype.load);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'changed',
+ ol.renderer.Layer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'dispatchEvent',
+ ol.renderer.Layer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'getRevision',
+ ol.renderer.Layer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'on',
+ ol.renderer.Layer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'once',
+ ol.renderer.Layer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'un',
+ ol.renderer.Layer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.Layer.prototype,
+ 'unByKey',
+ ol.renderer.Layer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'changed',
+ ol.renderer.webgl.Layer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'dispatchEvent',
+ ol.renderer.webgl.Layer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'getRevision',
+ ol.renderer.webgl.Layer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'on',
+ ol.renderer.webgl.Layer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'once',
+ ol.renderer.webgl.Layer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'un',
+ ol.renderer.webgl.Layer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.webgl.Layer.prototype,
+ 'unByKey',
+ ol.renderer.webgl.Layer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'changed',
+ ol.renderer.webgl.ImageLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.webgl.ImageLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'getRevision',
+ ol.renderer.webgl.ImageLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'on',
+ ol.renderer.webgl.ImageLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'once',
+ ol.renderer.webgl.ImageLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'un',
+ ol.renderer.webgl.ImageLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.webgl.ImageLayer.prototype,
+ 'unByKey',
+ ol.renderer.webgl.ImageLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'changed',
+ ol.renderer.webgl.TileLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.webgl.TileLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'getRevision',
+ ol.renderer.webgl.TileLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'on',
+ ol.renderer.webgl.TileLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'once',
+ ol.renderer.webgl.TileLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'un',
+ ol.renderer.webgl.TileLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.webgl.TileLayer.prototype,
+ 'unByKey',
+ ol.renderer.webgl.TileLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'changed',
+ ol.renderer.webgl.VectorLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.webgl.VectorLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'getRevision',
+ ol.renderer.webgl.VectorLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'on',
+ ol.renderer.webgl.VectorLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'once',
+ ol.renderer.webgl.VectorLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'un',
+ ol.renderer.webgl.VectorLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.webgl.VectorLayer.prototype,
+ 'unByKey',
+ ol.renderer.webgl.VectorLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'changed',
+ ol.renderer.dom.Layer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'dispatchEvent',
+ ol.renderer.dom.Layer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'getRevision',
+ ol.renderer.dom.Layer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'on',
+ ol.renderer.dom.Layer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'once',
+ ol.renderer.dom.Layer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'un',
+ ol.renderer.dom.Layer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.dom.Layer.prototype,
+ 'unByKey',
+ ol.renderer.dom.Layer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'changed',
+ ol.renderer.dom.ImageLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.dom.ImageLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'getRevision',
+ ol.renderer.dom.ImageLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'on',
+ ol.renderer.dom.ImageLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'once',
+ ol.renderer.dom.ImageLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'un',
+ ol.renderer.dom.ImageLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.dom.ImageLayer.prototype,
+ 'unByKey',
+ ol.renderer.dom.ImageLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'changed',
+ ol.renderer.dom.TileLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.dom.TileLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'getRevision',
+ ol.renderer.dom.TileLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'on',
+ ol.renderer.dom.TileLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'once',
+ ol.renderer.dom.TileLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'un',
+ ol.renderer.dom.TileLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.dom.TileLayer.prototype,
+ 'unByKey',
+ ol.renderer.dom.TileLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'changed',
+ ol.renderer.dom.VectorLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.dom.VectorLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'getRevision',
+ ol.renderer.dom.VectorLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'on',
+ ol.renderer.dom.VectorLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'once',
+ ol.renderer.dom.VectorLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'un',
+ ol.renderer.dom.VectorLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.dom.VectorLayer.prototype,
+ 'unByKey',
+ ol.renderer.dom.VectorLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'changed',
+ ol.renderer.canvas.Layer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'dispatchEvent',
+ ol.renderer.canvas.Layer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'getRevision',
+ ol.renderer.canvas.Layer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'on',
+ ol.renderer.canvas.Layer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'once',
+ ol.renderer.canvas.Layer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'un',
+ ol.renderer.canvas.Layer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.canvas.Layer.prototype,
+ 'unByKey',
+ ol.renderer.canvas.Layer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'changed',
+ ol.renderer.canvas.ImageLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.canvas.ImageLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'getRevision',
+ ol.renderer.canvas.ImageLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'on',
+ ol.renderer.canvas.ImageLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'once',
+ ol.renderer.canvas.ImageLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'un',
+ ol.renderer.canvas.ImageLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.canvas.ImageLayer.prototype,
+ 'unByKey',
+ ol.renderer.canvas.ImageLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'changed',
+ ol.renderer.canvas.TileLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.canvas.TileLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'getRevision',
+ ol.renderer.canvas.TileLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'on',
+ ol.renderer.canvas.TileLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'once',
+ ol.renderer.canvas.TileLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'un',
+ ol.renderer.canvas.TileLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.canvas.TileLayer.prototype,
+ 'unByKey',
+ ol.renderer.canvas.TileLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'changed',
+ ol.renderer.canvas.VectorLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.canvas.VectorLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'getRevision',
+ ol.renderer.canvas.VectorLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'on',
+ ol.renderer.canvas.VectorLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'once',
+ ol.renderer.canvas.VectorLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'un',
+ ol.renderer.canvas.VectorLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorLayer.prototype,
+ 'unByKey',
+ ol.renderer.canvas.VectorLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'changed',
+ ol.renderer.canvas.VectorTileLayer.prototype.changed);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'dispatchEvent',
+ ol.renderer.canvas.VectorTileLayer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'getRevision',
+ ol.renderer.canvas.VectorTileLayer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'on',
+ ol.renderer.canvas.VectorTileLayer.prototype.on);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'once',
+ ol.renderer.canvas.VectorTileLayer.prototype.once);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'un',
+ ol.renderer.canvas.VectorTileLayer.prototype.un);
+
+goog.exportProperty(
+ ol.renderer.canvas.VectorTileLayer.prototype,
+ 'unByKey',
+ ol.renderer.canvas.VectorTileLayer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'type',
+ ol.render.Event.prototype.type);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'target',
+ ol.render.Event.prototype.target);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'preventDefault',
+ ol.render.Event.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.render.Event.prototype,
+ 'stopPropagation',
+ ol.render.Event.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.pointer.PointerEvent.prototype,
+ 'type',
+ ol.pointer.PointerEvent.prototype.type);
+
+goog.exportProperty(
+ ol.pointer.PointerEvent.prototype,
+ 'target',
+ ol.pointer.PointerEvent.prototype.target);
+
+goog.exportProperty(
+ ol.pointer.PointerEvent.prototype,
+ 'preventDefault',
+ ol.pointer.PointerEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.pointer.PointerEvent.prototype,
+ 'stopPropagation',
+ ol.pointer.PointerEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'get',
+ ol.layer.Base.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getKeys',
+ ol.layer.Base.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getProperties',
+ ol.layer.Base.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'set',
+ ol.layer.Base.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'setProperties',
+ ol.layer.Base.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'unset',
+ ol.layer.Base.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'changed',
+ ol.layer.Base.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'dispatchEvent',
+ ol.layer.Base.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'getRevision',
+ ol.layer.Base.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'on',
+ ol.layer.Base.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'once',
+ ol.layer.Base.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'un',
+ ol.layer.Base.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Base.prototype,
+ 'unByKey',
+ ol.layer.Base.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getExtent',
+ ol.layer.Layer.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getMaxResolution',
+ ol.layer.Layer.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getMinResolution',
+ ol.layer.Layer.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getOpacity',
+ ol.layer.Layer.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getVisible',
+ ol.layer.Layer.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getZIndex',
+ ol.layer.Layer.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setExtent',
+ ol.layer.Layer.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setMaxResolution',
+ ol.layer.Layer.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setMinResolution',
+ ol.layer.Layer.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setOpacity',
+ ol.layer.Layer.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setVisible',
+ ol.layer.Layer.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setZIndex',
+ ol.layer.Layer.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'get',
+ ol.layer.Layer.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getKeys',
+ ol.layer.Layer.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getProperties',
+ ol.layer.Layer.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'set',
+ ol.layer.Layer.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'setProperties',
+ ol.layer.Layer.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'unset',
+ ol.layer.Layer.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'changed',
+ ol.layer.Layer.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'dispatchEvent',
+ ol.layer.Layer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'getRevision',
+ ol.layer.Layer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'on',
+ ol.layer.Layer.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'once',
+ ol.layer.Layer.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'un',
+ ol.layer.Layer.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Layer.prototype,
+ 'unByKey',
+ ol.layer.Layer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setMap',
+ ol.layer.Vector.prototype.setMap);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setSource',
+ ol.layer.Vector.prototype.setSource);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getExtent',
+ ol.layer.Vector.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getMaxResolution',
+ ol.layer.Vector.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getMinResolution',
+ ol.layer.Vector.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getOpacity',
+ ol.layer.Vector.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getVisible',
+ ol.layer.Vector.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getZIndex',
+ ol.layer.Vector.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setExtent',
+ ol.layer.Vector.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setMaxResolution',
+ ol.layer.Vector.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setMinResolution',
+ ol.layer.Vector.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setOpacity',
+ ol.layer.Vector.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setVisible',
+ ol.layer.Vector.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setZIndex',
+ ol.layer.Vector.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'get',
+ ol.layer.Vector.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getKeys',
+ ol.layer.Vector.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getProperties',
+ ol.layer.Vector.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'set',
+ ol.layer.Vector.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'setProperties',
+ ol.layer.Vector.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'unset',
+ ol.layer.Vector.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'changed',
+ ol.layer.Vector.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'dispatchEvent',
+ ol.layer.Vector.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'getRevision',
+ ol.layer.Vector.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'on',
+ ol.layer.Vector.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'once',
+ ol.layer.Vector.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'un',
+ ol.layer.Vector.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Vector.prototype,
+ 'unByKey',
+ ol.layer.Vector.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getSource',
+ ol.layer.Heatmap.prototype.getSource);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getStyle',
+ ol.layer.Heatmap.prototype.getStyle);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getStyleFunction',
+ ol.layer.Heatmap.prototype.getStyleFunction);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setStyle',
+ ol.layer.Heatmap.prototype.setStyle);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setMap',
+ ol.layer.Heatmap.prototype.setMap);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setSource',
+ ol.layer.Heatmap.prototype.setSource);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getExtent',
+ ol.layer.Heatmap.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getMaxResolution',
+ ol.layer.Heatmap.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getMinResolution',
+ ol.layer.Heatmap.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getOpacity',
+ ol.layer.Heatmap.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getVisible',
+ ol.layer.Heatmap.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getZIndex',
+ ol.layer.Heatmap.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setExtent',
+ ol.layer.Heatmap.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setMaxResolution',
+ ol.layer.Heatmap.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setMinResolution',
+ ol.layer.Heatmap.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setOpacity',
+ ol.layer.Heatmap.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setVisible',
+ ol.layer.Heatmap.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setZIndex',
+ ol.layer.Heatmap.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'get',
+ ol.layer.Heatmap.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getKeys',
+ ol.layer.Heatmap.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getProperties',
+ ol.layer.Heatmap.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'set',
+ ol.layer.Heatmap.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'setProperties',
+ ol.layer.Heatmap.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'unset',
+ ol.layer.Heatmap.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'changed',
+ ol.layer.Heatmap.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'dispatchEvent',
+ ol.layer.Heatmap.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'getRevision',
+ ol.layer.Heatmap.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'on',
+ ol.layer.Heatmap.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'once',
+ ol.layer.Heatmap.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'un',
+ ol.layer.Heatmap.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Heatmap.prototype,
+ 'unByKey',
+ ol.layer.Heatmap.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setMap',
+ ol.layer.Image.prototype.setMap);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setSource',
+ ol.layer.Image.prototype.setSource);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getExtent',
+ ol.layer.Image.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getMaxResolution',
+ ol.layer.Image.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getMinResolution',
+ ol.layer.Image.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getOpacity',
+ ol.layer.Image.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getVisible',
+ ol.layer.Image.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getZIndex',
+ ol.layer.Image.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setExtent',
+ ol.layer.Image.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setMaxResolution',
+ ol.layer.Image.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setMinResolution',
+ ol.layer.Image.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setOpacity',
+ ol.layer.Image.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setVisible',
+ ol.layer.Image.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setZIndex',
+ ol.layer.Image.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'get',
+ ol.layer.Image.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getKeys',
+ ol.layer.Image.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getProperties',
+ ol.layer.Image.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'set',
+ ol.layer.Image.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'setProperties',
+ ol.layer.Image.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'unset',
+ ol.layer.Image.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'changed',
+ ol.layer.Image.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'dispatchEvent',
+ ol.layer.Image.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'getRevision',
+ ol.layer.Image.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'on',
+ ol.layer.Image.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'once',
+ ol.layer.Image.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'un',
+ ol.layer.Image.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Image.prototype,
+ 'unByKey',
+ ol.layer.Image.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getExtent',
+ ol.layer.Group.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getMaxResolution',
+ ol.layer.Group.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getMinResolution',
+ ol.layer.Group.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getOpacity',
+ ol.layer.Group.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getVisible',
+ ol.layer.Group.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getZIndex',
+ ol.layer.Group.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setExtent',
+ ol.layer.Group.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setMaxResolution',
+ ol.layer.Group.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setMinResolution',
+ ol.layer.Group.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setOpacity',
+ ol.layer.Group.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setVisible',
+ ol.layer.Group.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setZIndex',
+ ol.layer.Group.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'get',
+ ol.layer.Group.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getKeys',
+ ol.layer.Group.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getProperties',
+ ol.layer.Group.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'set',
+ ol.layer.Group.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'setProperties',
+ ol.layer.Group.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'unset',
+ ol.layer.Group.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'changed',
+ ol.layer.Group.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'dispatchEvent',
+ ol.layer.Group.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'getRevision',
+ ol.layer.Group.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'on',
+ ol.layer.Group.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'once',
+ ol.layer.Group.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'un',
+ ol.layer.Group.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Group.prototype,
+ 'unByKey',
+ ol.layer.Group.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setMap',
+ ol.layer.Tile.prototype.setMap);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setSource',
+ ol.layer.Tile.prototype.setSource);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getExtent',
+ ol.layer.Tile.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getMaxResolution',
+ ol.layer.Tile.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getMinResolution',
+ ol.layer.Tile.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getOpacity',
+ ol.layer.Tile.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getVisible',
+ ol.layer.Tile.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getZIndex',
+ ol.layer.Tile.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setExtent',
+ ol.layer.Tile.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setMaxResolution',
+ ol.layer.Tile.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setMinResolution',
+ ol.layer.Tile.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setOpacity',
+ ol.layer.Tile.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setVisible',
+ ol.layer.Tile.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setZIndex',
+ ol.layer.Tile.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'get',
+ ol.layer.Tile.prototype.get);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getKeys',
+ ol.layer.Tile.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getProperties',
+ ol.layer.Tile.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'set',
+ ol.layer.Tile.prototype.set);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'setProperties',
+ ol.layer.Tile.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'unset',
+ ol.layer.Tile.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'changed',
+ ol.layer.Tile.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'dispatchEvent',
+ ol.layer.Tile.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'getRevision',
+ ol.layer.Tile.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'on',
+ ol.layer.Tile.prototype.on);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'once',
+ ol.layer.Tile.prototype.once);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'un',
+ ol.layer.Tile.prototype.un);
+
+goog.exportProperty(
+ ol.layer.Tile.prototype,
+ 'unByKey',
+ ol.layer.Tile.prototype.unByKey);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getSource',
+ ol.layer.VectorTile.prototype.getSource);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getStyle',
+ ol.layer.VectorTile.prototype.getStyle);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getStyleFunction',
+ ol.layer.VectorTile.prototype.getStyleFunction);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setStyle',
+ ol.layer.VectorTile.prototype.setStyle);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setMap',
+ ol.layer.VectorTile.prototype.setMap);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setSource',
+ ol.layer.VectorTile.prototype.setSource);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getExtent',
+ ol.layer.VectorTile.prototype.getExtent);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getMaxResolution',
+ ol.layer.VectorTile.prototype.getMaxResolution);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getMinResolution',
+ ol.layer.VectorTile.prototype.getMinResolution);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getOpacity',
+ ol.layer.VectorTile.prototype.getOpacity);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getVisible',
+ ol.layer.VectorTile.prototype.getVisible);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getZIndex',
+ ol.layer.VectorTile.prototype.getZIndex);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setExtent',
+ ol.layer.VectorTile.prototype.setExtent);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setMaxResolution',
+ ol.layer.VectorTile.prototype.setMaxResolution);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setMinResolution',
+ ol.layer.VectorTile.prototype.setMinResolution);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setOpacity',
+ ol.layer.VectorTile.prototype.setOpacity);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setVisible',
+ ol.layer.VectorTile.prototype.setVisible);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setZIndex',
+ ol.layer.VectorTile.prototype.setZIndex);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'get',
+ ol.layer.VectorTile.prototype.get);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getKeys',
+ ol.layer.VectorTile.prototype.getKeys);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getProperties',
+ ol.layer.VectorTile.prototype.getProperties);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'set',
+ ol.layer.VectorTile.prototype.set);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'setProperties',
+ ol.layer.VectorTile.prototype.setProperties);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'unset',
+ ol.layer.VectorTile.prototype.unset);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'changed',
+ ol.layer.VectorTile.prototype.changed);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'dispatchEvent',
+ ol.layer.VectorTile.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'getRevision',
+ ol.layer.VectorTile.prototype.getRevision);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'on',
+ ol.layer.VectorTile.prototype.on);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'once',
+ ol.layer.VectorTile.prototype.once);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'un',
+ ol.layer.VectorTile.prototype.un);
+
+goog.exportProperty(
+ ol.layer.VectorTile.prototype,
+ 'unByKey',
+ ol.layer.VectorTile.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'get',
+ ol.interaction.Interaction.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'getKeys',
+ ol.interaction.Interaction.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'getProperties',
+ ol.interaction.Interaction.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'set',
+ ol.interaction.Interaction.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'setProperties',
+ ol.interaction.Interaction.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'unset',
+ ol.interaction.Interaction.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'changed',
+ ol.interaction.Interaction.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'dispatchEvent',
+ ol.interaction.Interaction.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'getRevision',
+ ol.interaction.Interaction.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'on',
+ ol.interaction.Interaction.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'once',
+ ol.interaction.Interaction.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'un',
+ ol.interaction.Interaction.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Interaction.prototype,
+ 'unByKey',
+ ol.interaction.Interaction.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'getActive',
+ ol.interaction.DoubleClickZoom.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'getMap',
+ ol.interaction.DoubleClickZoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'setActive',
+ ol.interaction.DoubleClickZoom.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'get',
+ ol.interaction.DoubleClickZoom.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'getKeys',
+ ol.interaction.DoubleClickZoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'getProperties',
+ ol.interaction.DoubleClickZoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'set',
+ ol.interaction.DoubleClickZoom.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'setProperties',
+ ol.interaction.DoubleClickZoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'unset',
+ ol.interaction.DoubleClickZoom.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'changed',
+ ol.interaction.DoubleClickZoom.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'dispatchEvent',
+ ol.interaction.DoubleClickZoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'getRevision',
+ ol.interaction.DoubleClickZoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'on',
+ ol.interaction.DoubleClickZoom.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'once',
+ ol.interaction.DoubleClickZoom.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'un',
+ ol.interaction.DoubleClickZoom.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DoubleClickZoom.prototype,
+ 'unByKey',
+ ol.interaction.DoubleClickZoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'getActive',
+ ol.interaction.DragAndDrop.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'getMap',
+ ol.interaction.DragAndDrop.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'setActive',
+ ol.interaction.DragAndDrop.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'get',
+ ol.interaction.DragAndDrop.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'getKeys',
+ ol.interaction.DragAndDrop.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'getProperties',
+ ol.interaction.DragAndDrop.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'set',
+ ol.interaction.DragAndDrop.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'setProperties',
+ ol.interaction.DragAndDrop.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'unset',
+ ol.interaction.DragAndDrop.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'changed',
+ ol.interaction.DragAndDrop.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'dispatchEvent',
+ ol.interaction.DragAndDrop.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'getRevision',
+ ol.interaction.DragAndDrop.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'on',
+ ol.interaction.DragAndDrop.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'once',
+ ol.interaction.DragAndDrop.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'un',
+ ol.interaction.DragAndDrop.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DragAndDrop.prototype,
+ 'unByKey',
+ ol.interaction.DragAndDrop.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'type',
+ ol.interaction.DragAndDropEvent.prototype.type);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'target',
+ ol.interaction.DragAndDropEvent.prototype.target);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'preventDefault',
+ ol.interaction.DragAndDropEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.interaction.DragAndDropEvent.prototype,
+ 'stopPropagation',
+ ol.interaction.DragAndDropEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.DragBoxEvent.prototype,
+ 'type',
+ ol.DragBoxEvent.prototype.type);
+
+goog.exportProperty(
+ ol.DragBoxEvent.prototype,
+ 'target',
+ ol.DragBoxEvent.prototype.target);
+
+goog.exportProperty(
+ ol.DragBoxEvent.prototype,
+ 'preventDefault',
+ ol.DragBoxEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.DragBoxEvent.prototype,
+ 'stopPropagation',
+ ol.DragBoxEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'getActive',
+ ol.interaction.Pointer.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'getMap',
+ ol.interaction.Pointer.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'setActive',
+ ol.interaction.Pointer.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'get',
+ ol.interaction.Pointer.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'getKeys',
+ ol.interaction.Pointer.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'getProperties',
+ ol.interaction.Pointer.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'set',
+ ol.interaction.Pointer.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'setProperties',
+ ol.interaction.Pointer.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'unset',
+ ol.interaction.Pointer.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'changed',
+ ol.interaction.Pointer.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'dispatchEvent',
+ ol.interaction.Pointer.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'getRevision',
+ ol.interaction.Pointer.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'on',
+ ol.interaction.Pointer.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'once',
+ ol.interaction.Pointer.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'un',
+ ol.interaction.Pointer.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Pointer.prototype,
+ 'unByKey',
+ ol.interaction.Pointer.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'getActive',
+ ol.interaction.DragBox.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'getMap',
+ ol.interaction.DragBox.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'setActive',
+ ol.interaction.DragBox.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'get',
+ ol.interaction.DragBox.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'getKeys',
+ ol.interaction.DragBox.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'getProperties',
+ ol.interaction.DragBox.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'set',
+ ol.interaction.DragBox.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'setProperties',
+ ol.interaction.DragBox.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'unset',
+ ol.interaction.DragBox.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'changed',
+ ol.interaction.DragBox.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'dispatchEvent',
+ ol.interaction.DragBox.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'getRevision',
+ ol.interaction.DragBox.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'on',
+ ol.interaction.DragBox.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'once',
+ ol.interaction.DragBox.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'un',
+ ol.interaction.DragBox.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DragBox.prototype,
+ 'unByKey',
+ ol.interaction.DragBox.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'getActive',
+ ol.interaction.DragPan.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'getMap',
+ ol.interaction.DragPan.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'setActive',
+ ol.interaction.DragPan.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'get',
+ ol.interaction.DragPan.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'getKeys',
+ ol.interaction.DragPan.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'getProperties',
+ ol.interaction.DragPan.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'set',
+ ol.interaction.DragPan.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'setProperties',
+ ol.interaction.DragPan.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'unset',
+ ol.interaction.DragPan.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'changed',
+ ol.interaction.DragPan.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'dispatchEvent',
+ ol.interaction.DragPan.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'getRevision',
+ ol.interaction.DragPan.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'on',
+ ol.interaction.DragPan.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'once',
+ ol.interaction.DragPan.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'un',
+ ol.interaction.DragPan.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DragPan.prototype,
+ 'unByKey',
+ ol.interaction.DragPan.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'getActive',
+ ol.interaction.DragRotateAndZoom.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'getMap',
+ ol.interaction.DragRotateAndZoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'setActive',
+ ol.interaction.DragRotateAndZoom.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'get',
+ ol.interaction.DragRotateAndZoom.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'getKeys',
+ ol.interaction.DragRotateAndZoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'getProperties',
+ ol.interaction.DragRotateAndZoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'set',
+ ol.interaction.DragRotateAndZoom.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'setProperties',
+ ol.interaction.DragRotateAndZoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'unset',
+ ol.interaction.DragRotateAndZoom.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'changed',
+ ol.interaction.DragRotateAndZoom.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'dispatchEvent',
+ ol.interaction.DragRotateAndZoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'getRevision',
+ ol.interaction.DragRotateAndZoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'on',
+ ol.interaction.DragRotateAndZoom.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'once',
+ ol.interaction.DragRotateAndZoom.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'un',
+ ol.interaction.DragRotateAndZoom.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DragRotateAndZoom.prototype,
+ 'unByKey',
+ ol.interaction.DragRotateAndZoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'getActive',
+ ol.interaction.DragRotate.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'getMap',
+ ol.interaction.DragRotate.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'setActive',
+ ol.interaction.DragRotate.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'get',
+ ol.interaction.DragRotate.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'getKeys',
+ ol.interaction.DragRotate.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'getProperties',
+ ol.interaction.DragRotate.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'set',
+ ol.interaction.DragRotate.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'setProperties',
+ ol.interaction.DragRotate.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'unset',
+ ol.interaction.DragRotate.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'changed',
+ ol.interaction.DragRotate.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'dispatchEvent',
+ ol.interaction.DragRotate.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'getRevision',
+ ol.interaction.DragRotate.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'on',
+ ol.interaction.DragRotate.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'once',
+ ol.interaction.DragRotate.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'un',
+ ol.interaction.DragRotate.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DragRotate.prototype,
+ 'unByKey',
+ ol.interaction.DragRotate.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'getGeometry',
+ ol.interaction.DragZoom.prototype.getGeometry);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'getActive',
+ ol.interaction.DragZoom.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'getMap',
+ ol.interaction.DragZoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'setActive',
+ ol.interaction.DragZoom.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'get',
+ ol.interaction.DragZoom.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'getKeys',
+ ol.interaction.DragZoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'getProperties',
+ ol.interaction.DragZoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'set',
+ ol.interaction.DragZoom.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'setProperties',
+ ol.interaction.DragZoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'unset',
+ ol.interaction.DragZoom.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'changed',
+ ol.interaction.DragZoom.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'dispatchEvent',
+ ol.interaction.DragZoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'getRevision',
+ ol.interaction.DragZoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'on',
+ ol.interaction.DragZoom.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'once',
+ ol.interaction.DragZoom.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'un',
+ ol.interaction.DragZoom.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.DragZoom.prototype,
+ 'unByKey',
+ ol.interaction.DragZoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.DrawEvent.prototype,
+ 'type',
+ ol.interaction.DrawEvent.prototype.type);
+
+goog.exportProperty(
+ ol.interaction.DrawEvent.prototype,
+ 'target',
+ ol.interaction.DrawEvent.prototype.target);
+
+goog.exportProperty(
+ ol.interaction.DrawEvent.prototype,
+ 'preventDefault',
+ ol.interaction.DrawEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.interaction.DrawEvent.prototype,
+ 'stopPropagation',
+ ol.interaction.DrawEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'getActive',
+ ol.interaction.Draw.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'getMap',
+ ol.interaction.Draw.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'setActive',
+ ol.interaction.Draw.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'get',
+ ol.interaction.Draw.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'getKeys',
+ ol.interaction.Draw.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'getProperties',
+ ol.interaction.Draw.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'set',
+ ol.interaction.Draw.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'setProperties',
+ ol.interaction.Draw.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'unset',
+ ol.interaction.Draw.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'changed',
+ ol.interaction.Draw.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'dispatchEvent',
+ ol.interaction.Draw.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'getRevision',
+ ol.interaction.Draw.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'on',
+ ol.interaction.Draw.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'once',
+ ol.interaction.Draw.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'un',
+ ol.interaction.Draw.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Draw.prototype,
+ 'unByKey',
+ ol.interaction.Draw.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'getActive',
+ ol.interaction.KeyboardPan.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'getMap',
+ ol.interaction.KeyboardPan.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'setActive',
+ ol.interaction.KeyboardPan.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'get',
+ ol.interaction.KeyboardPan.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'getKeys',
+ ol.interaction.KeyboardPan.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'getProperties',
+ ol.interaction.KeyboardPan.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'set',
+ ol.interaction.KeyboardPan.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'setProperties',
+ ol.interaction.KeyboardPan.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'unset',
+ ol.interaction.KeyboardPan.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'changed',
+ ol.interaction.KeyboardPan.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'dispatchEvent',
+ ol.interaction.KeyboardPan.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'getRevision',
+ ol.interaction.KeyboardPan.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'on',
+ ol.interaction.KeyboardPan.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'once',
+ ol.interaction.KeyboardPan.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'un',
+ ol.interaction.KeyboardPan.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.KeyboardPan.prototype,
+ 'unByKey',
+ ol.interaction.KeyboardPan.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'getActive',
+ ol.interaction.KeyboardZoom.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'getMap',
+ ol.interaction.KeyboardZoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'setActive',
+ ol.interaction.KeyboardZoom.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'get',
+ ol.interaction.KeyboardZoom.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'getKeys',
+ ol.interaction.KeyboardZoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'getProperties',
+ ol.interaction.KeyboardZoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'set',
+ ol.interaction.KeyboardZoom.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'setProperties',
+ ol.interaction.KeyboardZoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'unset',
+ ol.interaction.KeyboardZoom.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'changed',
+ ol.interaction.KeyboardZoom.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'dispatchEvent',
+ ol.interaction.KeyboardZoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'getRevision',
+ ol.interaction.KeyboardZoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'on',
+ ol.interaction.KeyboardZoom.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'once',
+ ol.interaction.KeyboardZoom.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'un',
+ ol.interaction.KeyboardZoom.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.KeyboardZoom.prototype,
+ 'unByKey',
+ ol.interaction.KeyboardZoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.ModifyEvent.prototype,
+ 'type',
+ ol.interaction.ModifyEvent.prototype.type);
+
+goog.exportProperty(
+ ol.interaction.ModifyEvent.prototype,
+ 'target',
+ ol.interaction.ModifyEvent.prototype.target);
+
+goog.exportProperty(
+ ol.interaction.ModifyEvent.prototype,
+ 'preventDefault',
+ ol.interaction.ModifyEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.interaction.ModifyEvent.prototype,
+ 'stopPropagation',
+ ol.interaction.ModifyEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'getActive',
+ ol.interaction.Modify.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'getMap',
+ ol.interaction.Modify.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'setActive',
+ ol.interaction.Modify.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'get',
+ ol.interaction.Modify.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'getKeys',
+ ol.interaction.Modify.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'getProperties',
+ ol.interaction.Modify.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'set',
+ ol.interaction.Modify.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'setProperties',
+ ol.interaction.Modify.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'unset',
+ ol.interaction.Modify.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'changed',
+ ol.interaction.Modify.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'dispatchEvent',
+ ol.interaction.Modify.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'getRevision',
+ ol.interaction.Modify.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'on',
+ ol.interaction.Modify.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'once',
+ ol.interaction.Modify.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'un',
+ ol.interaction.Modify.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Modify.prototype,
+ 'unByKey',
+ ol.interaction.Modify.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'getActive',
+ ol.interaction.MouseWheelZoom.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'getMap',
+ ol.interaction.MouseWheelZoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'setActive',
+ ol.interaction.MouseWheelZoom.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'get',
+ ol.interaction.MouseWheelZoom.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'getKeys',
+ ol.interaction.MouseWheelZoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'getProperties',
+ ol.interaction.MouseWheelZoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'set',
+ ol.interaction.MouseWheelZoom.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'setProperties',
+ ol.interaction.MouseWheelZoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'unset',
+ ol.interaction.MouseWheelZoom.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'changed',
+ ol.interaction.MouseWheelZoom.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'dispatchEvent',
+ ol.interaction.MouseWheelZoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'getRevision',
+ ol.interaction.MouseWheelZoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'on',
+ ol.interaction.MouseWheelZoom.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'once',
+ ol.interaction.MouseWheelZoom.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'un',
+ ol.interaction.MouseWheelZoom.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.MouseWheelZoom.prototype,
+ 'unByKey',
+ ol.interaction.MouseWheelZoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'getActive',
+ ol.interaction.PinchRotate.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'getMap',
+ ol.interaction.PinchRotate.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'setActive',
+ ol.interaction.PinchRotate.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'get',
+ ol.interaction.PinchRotate.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'getKeys',
+ ol.interaction.PinchRotate.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'getProperties',
+ ol.interaction.PinchRotate.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'set',
+ ol.interaction.PinchRotate.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'setProperties',
+ ol.interaction.PinchRotate.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'unset',
+ ol.interaction.PinchRotate.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'changed',
+ ol.interaction.PinchRotate.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'dispatchEvent',
+ ol.interaction.PinchRotate.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'getRevision',
+ ol.interaction.PinchRotate.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'on',
+ ol.interaction.PinchRotate.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'once',
+ ol.interaction.PinchRotate.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'un',
+ ol.interaction.PinchRotate.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.PinchRotate.prototype,
+ 'unByKey',
+ ol.interaction.PinchRotate.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'getActive',
+ ol.interaction.PinchZoom.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'getMap',
+ ol.interaction.PinchZoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'setActive',
+ ol.interaction.PinchZoom.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'get',
+ ol.interaction.PinchZoom.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'getKeys',
+ ol.interaction.PinchZoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'getProperties',
+ ol.interaction.PinchZoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'set',
+ ol.interaction.PinchZoom.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'setProperties',
+ ol.interaction.PinchZoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'unset',
+ ol.interaction.PinchZoom.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'changed',
+ ol.interaction.PinchZoom.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'dispatchEvent',
+ ol.interaction.PinchZoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'getRevision',
+ ol.interaction.PinchZoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'on',
+ ol.interaction.PinchZoom.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'once',
+ ol.interaction.PinchZoom.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'un',
+ ol.interaction.PinchZoom.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.PinchZoom.prototype,
+ 'unByKey',
+ ol.interaction.PinchZoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'type',
+ ol.interaction.SelectEvent.prototype.type);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'target',
+ ol.interaction.SelectEvent.prototype.target);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'preventDefault',
+ ol.interaction.SelectEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.interaction.SelectEvent.prototype,
+ 'stopPropagation',
+ ol.interaction.SelectEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getActive',
+ ol.interaction.Select.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getMap',
+ ol.interaction.Select.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'setActive',
+ ol.interaction.Select.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'get',
+ ol.interaction.Select.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getKeys',
+ ol.interaction.Select.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getProperties',
+ ol.interaction.Select.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'set',
+ ol.interaction.Select.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'setProperties',
+ ol.interaction.Select.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'unset',
+ ol.interaction.Select.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'changed',
+ ol.interaction.Select.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'dispatchEvent',
+ ol.interaction.Select.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'getRevision',
+ ol.interaction.Select.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'on',
+ ol.interaction.Select.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'once',
+ ol.interaction.Select.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'un',
+ ol.interaction.Select.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Select.prototype,
+ 'unByKey',
+ ol.interaction.Select.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'getActive',
+ ol.interaction.Snap.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'getMap',
+ ol.interaction.Snap.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'setActive',
+ ol.interaction.Snap.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'get',
+ ol.interaction.Snap.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'getKeys',
+ ol.interaction.Snap.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'getProperties',
+ ol.interaction.Snap.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'set',
+ ol.interaction.Snap.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'setProperties',
+ ol.interaction.Snap.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'unset',
+ ol.interaction.Snap.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'changed',
+ ol.interaction.Snap.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'dispatchEvent',
+ ol.interaction.Snap.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'getRevision',
+ ol.interaction.Snap.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'on',
+ ol.interaction.Snap.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'once',
+ ol.interaction.Snap.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'un',
+ ol.interaction.Snap.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Snap.prototype,
+ 'unByKey',
+ ol.interaction.Snap.prototype.unByKey);
+
+goog.exportProperty(
+ ol.interaction.TranslateEvent.prototype,
+ 'type',
+ ol.interaction.TranslateEvent.prototype.type);
+
+goog.exportProperty(
+ ol.interaction.TranslateEvent.prototype,
+ 'target',
+ ol.interaction.TranslateEvent.prototype.target);
+
+goog.exportProperty(
+ ol.interaction.TranslateEvent.prototype,
+ 'preventDefault',
+ ol.interaction.TranslateEvent.prototype.preventDefault);
+
+goog.exportProperty(
+ ol.interaction.TranslateEvent.prototype,
+ 'stopPropagation',
+ ol.interaction.TranslateEvent.prototype.stopPropagation);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'getActive',
+ ol.interaction.Translate.prototype.getActive);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'getMap',
+ ol.interaction.Translate.prototype.getMap);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'setActive',
+ ol.interaction.Translate.prototype.setActive);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'get',
+ ol.interaction.Translate.prototype.get);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'getKeys',
+ ol.interaction.Translate.prototype.getKeys);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'getProperties',
+ ol.interaction.Translate.prototype.getProperties);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'set',
+ ol.interaction.Translate.prototype.set);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'setProperties',
+ ol.interaction.Translate.prototype.setProperties);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'unset',
+ ol.interaction.Translate.prototype.unset);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'changed',
+ ol.interaction.Translate.prototype.changed);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'dispatchEvent',
+ ol.interaction.Translate.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'getRevision',
+ ol.interaction.Translate.prototype.getRevision);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'on',
+ ol.interaction.Translate.prototype.on);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'once',
+ ol.interaction.Translate.prototype.once);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'un',
+ ol.interaction.Translate.prototype.un);
+
+goog.exportProperty(
+ ol.interaction.Translate.prototype,
+ 'unByKey',
+ ol.interaction.Translate.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'get',
+ ol.geom.Geometry.prototype.get);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'getKeys',
+ ol.geom.Geometry.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'getProperties',
+ ol.geom.Geometry.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'set',
+ ol.geom.Geometry.prototype.set);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'setProperties',
+ ol.geom.Geometry.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'unset',
+ ol.geom.Geometry.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'changed',
+ ol.geom.Geometry.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'dispatchEvent',
+ ol.geom.Geometry.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'getRevision',
+ ol.geom.Geometry.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'on',
+ ol.geom.Geometry.prototype.on);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'once',
+ ol.geom.Geometry.prototype.once);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'un',
+ ol.geom.Geometry.prototype.un);
+
+goog.exportProperty(
+ ol.geom.Geometry.prototype,
+ 'unByKey',
+ ol.geom.Geometry.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getClosestPoint',
+ ol.geom.SimpleGeometry.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getExtent',
+ ol.geom.SimpleGeometry.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'rotate',
+ ol.geom.SimpleGeometry.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'simplify',
+ ol.geom.SimpleGeometry.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'transform',
+ ol.geom.SimpleGeometry.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'get',
+ ol.geom.SimpleGeometry.prototype.get);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getKeys',
+ ol.geom.SimpleGeometry.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getProperties',
+ ol.geom.SimpleGeometry.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'set',
+ ol.geom.SimpleGeometry.prototype.set);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'setProperties',
+ ol.geom.SimpleGeometry.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'unset',
+ ol.geom.SimpleGeometry.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'changed',
+ ol.geom.SimpleGeometry.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'dispatchEvent',
+ ol.geom.SimpleGeometry.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'getRevision',
+ ol.geom.SimpleGeometry.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'on',
+ ol.geom.SimpleGeometry.prototype.on);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'once',
+ ol.geom.SimpleGeometry.prototype.once);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'un',
+ ol.geom.SimpleGeometry.prototype.un);
+
+goog.exportProperty(
+ ol.geom.SimpleGeometry.prototype,
+ 'unByKey',
+ ol.geom.SimpleGeometry.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getFirstCoordinate',
+ ol.geom.Circle.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getLastCoordinate',
+ ol.geom.Circle.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getLayout',
+ ol.geom.Circle.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'rotate',
+ ol.geom.Circle.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getClosestPoint',
+ ol.geom.Circle.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getExtent',
+ ol.geom.Circle.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'simplify',
+ ol.geom.Circle.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'get',
+ ol.geom.Circle.prototype.get);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getKeys',
+ ol.geom.Circle.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getProperties',
+ ol.geom.Circle.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'set',
+ ol.geom.Circle.prototype.set);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'setProperties',
+ ol.geom.Circle.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'unset',
+ ol.geom.Circle.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'changed',
+ ol.geom.Circle.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'dispatchEvent',
+ ol.geom.Circle.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'getRevision',
+ ol.geom.Circle.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'on',
+ ol.geom.Circle.prototype.on);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'once',
+ ol.geom.Circle.prototype.once);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'un',
+ ol.geom.Circle.prototype.un);
+
+goog.exportProperty(
+ ol.geom.Circle.prototype,
+ 'unByKey',
+ ol.geom.Circle.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getClosestPoint',
+ ol.geom.GeometryCollection.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getExtent',
+ ol.geom.GeometryCollection.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'rotate',
+ ol.geom.GeometryCollection.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'simplify',
+ ol.geom.GeometryCollection.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'transform',
+ ol.geom.GeometryCollection.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'get',
+ ol.geom.GeometryCollection.prototype.get);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getKeys',
+ ol.geom.GeometryCollection.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getProperties',
+ ol.geom.GeometryCollection.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'set',
+ ol.geom.GeometryCollection.prototype.set);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'setProperties',
+ ol.geom.GeometryCollection.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'unset',
+ ol.geom.GeometryCollection.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'changed',
+ ol.geom.GeometryCollection.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'dispatchEvent',
+ ol.geom.GeometryCollection.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'getRevision',
+ ol.geom.GeometryCollection.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'on',
+ ol.geom.GeometryCollection.prototype.on);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'once',
+ ol.geom.GeometryCollection.prototype.once);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'un',
+ ol.geom.GeometryCollection.prototype.un);
+
+goog.exportProperty(
+ ol.geom.GeometryCollection.prototype,
+ 'unByKey',
+ ol.geom.GeometryCollection.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getFirstCoordinate',
+ ol.geom.LinearRing.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getLastCoordinate',
+ ol.geom.LinearRing.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getLayout',
+ ol.geom.LinearRing.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'rotate',
+ ol.geom.LinearRing.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getClosestPoint',
+ ol.geom.LinearRing.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getExtent',
+ ol.geom.LinearRing.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'simplify',
+ ol.geom.LinearRing.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'transform',
+ ol.geom.LinearRing.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'get',
+ ol.geom.LinearRing.prototype.get);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getKeys',
+ ol.geom.LinearRing.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getProperties',
+ ol.geom.LinearRing.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'set',
+ ol.geom.LinearRing.prototype.set);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'setProperties',
+ ol.geom.LinearRing.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'unset',
+ ol.geom.LinearRing.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'changed',
+ ol.geom.LinearRing.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'dispatchEvent',
+ ol.geom.LinearRing.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'getRevision',
+ ol.geom.LinearRing.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'on',
+ ol.geom.LinearRing.prototype.on);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'once',
+ ol.geom.LinearRing.prototype.once);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'un',
+ ol.geom.LinearRing.prototype.un);
+
+goog.exportProperty(
+ ol.geom.LinearRing.prototype,
+ 'unByKey',
+ ol.geom.LinearRing.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getFirstCoordinate',
+ ol.geom.LineString.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getLastCoordinate',
+ ol.geom.LineString.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getLayout',
+ ol.geom.LineString.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'rotate',
+ ol.geom.LineString.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getClosestPoint',
+ ol.geom.LineString.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getExtent',
+ ol.geom.LineString.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'simplify',
+ ol.geom.LineString.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'transform',
+ ol.geom.LineString.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'get',
+ ol.geom.LineString.prototype.get);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getKeys',
+ ol.geom.LineString.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getProperties',
+ ol.geom.LineString.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'set',
+ ol.geom.LineString.prototype.set);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'setProperties',
+ ol.geom.LineString.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'unset',
+ ol.geom.LineString.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'changed',
+ ol.geom.LineString.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'dispatchEvent',
+ ol.geom.LineString.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'getRevision',
+ ol.geom.LineString.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'on',
+ ol.geom.LineString.prototype.on);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'once',
+ ol.geom.LineString.prototype.once);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'un',
+ ol.geom.LineString.prototype.un);
+
+goog.exportProperty(
+ ol.geom.LineString.prototype,
+ 'unByKey',
+ ol.geom.LineString.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getFirstCoordinate',
+ ol.geom.MultiLineString.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getLastCoordinate',
+ ol.geom.MultiLineString.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getLayout',
+ ol.geom.MultiLineString.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'rotate',
+ ol.geom.MultiLineString.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getClosestPoint',
+ ol.geom.MultiLineString.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getExtent',
+ ol.geom.MultiLineString.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'simplify',
+ ol.geom.MultiLineString.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'transform',
+ ol.geom.MultiLineString.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'get',
+ ol.geom.MultiLineString.prototype.get);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getKeys',
+ ol.geom.MultiLineString.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getProperties',
+ ol.geom.MultiLineString.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'set',
+ ol.geom.MultiLineString.prototype.set);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'setProperties',
+ ol.geom.MultiLineString.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'unset',
+ ol.geom.MultiLineString.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'changed',
+ ol.geom.MultiLineString.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'dispatchEvent',
+ ol.geom.MultiLineString.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'getRevision',
+ ol.geom.MultiLineString.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'on',
+ ol.geom.MultiLineString.prototype.on);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'once',
+ ol.geom.MultiLineString.prototype.once);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'un',
+ ol.geom.MultiLineString.prototype.un);
+
+goog.exportProperty(
+ ol.geom.MultiLineString.prototype,
+ 'unByKey',
+ ol.geom.MultiLineString.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getFirstCoordinate',
+ ol.geom.MultiPoint.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getLastCoordinate',
+ ol.geom.MultiPoint.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getLayout',
+ ol.geom.MultiPoint.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'rotate',
+ ol.geom.MultiPoint.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getClosestPoint',
+ ol.geom.MultiPoint.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getExtent',
+ ol.geom.MultiPoint.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'simplify',
+ ol.geom.MultiPoint.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'transform',
+ ol.geom.MultiPoint.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'get',
+ ol.geom.MultiPoint.prototype.get);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getKeys',
+ ol.geom.MultiPoint.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getProperties',
+ ol.geom.MultiPoint.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'set',
+ ol.geom.MultiPoint.prototype.set);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'setProperties',
+ ol.geom.MultiPoint.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'unset',
+ ol.geom.MultiPoint.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'changed',
+ ol.geom.MultiPoint.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'dispatchEvent',
+ ol.geom.MultiPoint.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'getRevision',
+ ol.geom.MultiPoint.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'on',
+ ol.geom.MultiPoint.prototype.on);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'once',
+ ol.geom.MultiPoint.prototype.once);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'un',
+ ol.geom.MultiPoint.prototype.un);
+
+goog.exportProperty(
+ ol.geom.MultiPoint.prototype,
+ 'unByKey',
+ ol.geom.MultiPoint.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getFirstCoordinate',
+ ol.geom.MultiPolygon.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getLastCoordinate',
+ ol.geom.MultiPolygon.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getLayout',
+ ol.geom.MultiPolygon.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'rotate',
+ ol.geom.MultiPolygon.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getClosestPoint',
+ ol.geom.MultiPolygon.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getExtent',
+ ol.geom.MultiPolygon.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'simplify',
+ ol.geom.MultiPolygon.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'transform',
+ ol.geom.MultiPolygon.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'get',
+ ol.geom.MultiPolygon.prototype.get);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getKeys',
+ ol.geom.MultiPolygon.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getProperties',
+ ol.geom.MultiPolygon.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'set',
+ ol.geom.MultiPolygon.prototype.set);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'setProperties',
+ ol.geom.MultiPolygon.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'unset',
+ ol.geom.MultiPolygon.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'changed',
+ ol.geom.MultiPolygon.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'dispatchEvent',
+ ol.geom.MultiPolygon.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'getRevision',
+ ol.geom.MultiPolygon.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'on',
+ ol.geom.MultiPolygon.prototype.on);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'once',
+ ol.geom.MultiPolygon.prototype.once);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'un',
+ ol.geom.MultiPolygon.prototype.un);
+
+goog.exportProperty(
+ ol.geom.MultiPolygon.prototype,
+ 'unByKey',
+ ol.geom.MultiPolygon.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getFirstCoordinate',
+ ol.geom.Point.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getLastCoordinate',
+ ol.geom.Point.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getLayout',
+ ol.geom.Point.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'rotate',
+ ol.geom.Point.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getClosestPoint',
+ ol.geom.Point.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getExtent',
+ ol.geom.Point.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'simplify',
+ ol.geom.Point.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'transform',
+ ol.geom.Point.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'get',
+ ol.geom.Point.prototype.get);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getKeys',
+ ol.geom.Point.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getProperties',
+ ol.geom.Point.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'set',
+ ol.geom.Point.prototype.set);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'setProperties',
+ ol.geom.Point.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'unset',
+ ol.geom.Point.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'changed',
+ ol.geom.Point.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'dispatchEvent',
+ ol.geom.Point.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'getRevision',
+ ol.geom.Point.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'on',
+ ol.geom.Point.prototype.on);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'once',
+ ol.geom.Point.prototype.once);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'un',
+ ol.geom.Point.prototype.un);
+
+goog.exportProperty(
+ ol.geom.Point.prototype,
+ 'unByKey',
+ ol.geom.Point.prototype.unByKey);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getFirstCoordinate',
+ ol.geom.Polygon.prototype.getFirstCoordinate);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getLastCoordinate',
+ ol.geom.Polygon.prototype.getLastCoordinate);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getLayout',
+ ol.geom.Polygon.prototype.getLayout);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'rotate',
+ ol.geom.Polygon.prototype.rotate);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getClosestPoint',
+ ol.geom.Polygon.prototype.getClosestPoint);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getExtent',
+ ol.geom.Polygon.prototype.getExtent);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'simplify',
+ ol.geom.Polygon.prototype.simplify);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'transform',
+ ol.geom.Polygon.prototype.transform);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'get',
+ ol.geom.Polygon.prototype.get);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getKeys',
+ ol.geom.Polygon.prototype.getKeys);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getProperties',
+ ol.geom.Polygon.prototype.getProperties);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'set',
+ ol.geom.Polygon.prototype.set);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'setProperties',
+ ol.geom.Polygon.prototype.setProperties);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'unset',
+ ol.geom.Polygon.prototype.unset);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'changed',
+ ol.geom.Polygon.prototype.changed);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'dispatchEvent',
+ ol.geom.Polygon.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'getRevision',
+ ol.geom.Polygon.prototype.getRevision);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'on',
+ ol.geom.Polygon.prototype.on);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'once',
+ ol.geom.Polygon.prototype.once);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'un',
+ ol.geom.Polygon.prototype.un);
+
+goog.exportProperty(
+ ol.geom.Polygon.prototype,
+ 'unByKey',
+ ol.geom.Polygon.prototype.unByKey);
+
+goog.exportProperty(
+ ol.format.GML2.prototype,
+ 'readFeatures',
+ ol.format.GML2.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.GML3.prototype,
+ 'readFeatures',
+ ol.format.GML3.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.format.GML.prototype,
+ 'readFeatures',
+ ol.format.GML.prototype.readFeatures);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'get',
+ ol.control.Control.prototype.get);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'getKeys',
+ ol.control.Control.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'getProperties',
+ ol.control.Control.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'set',
+ ol.control.Control.prototype.set);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'setProperties',
+ ol.control.Control.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'unset',
+ ol.control.Control.prototype.unset);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'changed',
+ ol.control.Control.prototype.changed);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'dispatchEvent',
+ ol.control.Control.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'getRevision',
+ ol.control.Control.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'on',
+ ol.control.Control.prototype.on);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'once',
+ ol.control.Control.prototype.once);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'un',
+ ol.control.Control.prototype.un);
+
+goog.exportProperty(
+ ol.control.Control.prototype,
+ 'unByKey',
+ ol.control.Control.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'getMap',
+ ol.control.Attribution.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'setMap',
+ ol.control.Attribution.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'setTarget',
+ ol.control.Attribution.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'get',
+ ol.control.Attribution.prototype.get);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'getKeys',
+ ol.control.Attribution.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'getProperties',
+ ol.control.Attribution.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'set',
+ ol.control.Attribution.prototype.set);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'setProperties',
+ ol.control.Attribution.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'unset',
+ ol.control.Attribution.prototype.unset);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'changed',
+ ol.control.Attribution.prototype.changed);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'dispatchEvent',
+ ol.control.Attribution.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'getRevision',
+ ol.control.Attribution.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'on',
+ ol.control.Attribution.prototype.on);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'once',
+ ol.control.Attribution.prototype.once);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'un',
+ ol.control.Attribution.prototype.un);
+
+goog.exportProperty(
+ ol.control.Attribution.prototype,
+ 'unByKey',
+ ol.control.Attribution.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'getMap',
+ ol.control.FullScreen.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'setMap',
+ ol.control.FullScreen.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'setTarget',
+ ol.control.FullScreen.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'get',
+ ol.control.FullScreen.prototype.get);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'getKeys',
+ ol.control.FullScreen.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'getProperties',
+ ol.control.FullScreen.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'set',
+ ol.control.FullScreen.prototype.set);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'setProperties',
+ ol.control.FullScreen.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'unset',
+ ol.control.FullScreen.prototype.unset);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'changed',
+ ol.control.FullScreen.prototype.changed);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'dispatchEvent',
+ ol.control.FullScreen.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'getRevision',
+ ol.control.FullScreen.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'on',
+ ol.control.FullScreen.prototype.on);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'once',
+ ol.control.FullScreen.prototype.once);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'un',
+ ol.control.FullScreen.prototype.un);
+
+goog.exportProperty(
+ ol.control.FullScreen.prototype,
+ 'unByKey',
+ ol.control.FullScreen.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'getMap',
+ ol.control.MousePosition.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'setMap',
+ ol.control.MousePosition.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'setTarget',
+ ol.control.MousePosition.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'get',
+ ol.control.MousePosition.prototype.get);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'getKeys',
+ ol.control.MousePosition.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'getProperties',
+ ol.control.MousePosition.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'set',
+ ol.control.MousePosition.prototype.set);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'setProperties',
+ ol.control.MousePosition.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'unset',
+ ol.control.MousePosition.prototype.unset);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'changed',
+ ol.control.MousePosition.prototype.changed);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'dispatchEvent',
+ ol.control.MousePosition.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'getRevision',
+ ol.control.MousePosition.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'on',
+ ol.control.MousePosition.prototype.on);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'once',
+ ol.control.MousePosition.prototype.once);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'un',
+ ol.control.MousePosition.prototype.un);
+
+goog.exportProperty(
+ ol.control.MousePosition.prototype,
+ 'unByKey',
+ ol.control.MousePosition.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getMap',
+ ol.control.OverviewMap.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'setMap',
+ ol.control.OverviewMap.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'setTarget',
+ ol.control.OverviewMap.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'get',
+ ol.control.OverviewMap.prototype.get);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getKeys',
+ ol.control.OverviewMap.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getProperties',
+ ol.control.OverviewMap.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'set',
+ ol.control.OverviewMap.prototype.set);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'setProperties',
+ ol.control.OverviewMap.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'unset',
+ ol.control.OverviewMap.prototype.unset);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'changed',
+ ol.control.OverviewMap.prototype.changed);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'dispatchEvent',
+ ol.control.OverviewMap.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'getRevision',
+ ol.control.OverviewMap.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'on',
+ ol.control.OverviewMap.prototype.on);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'once',
+ ol.control.OverviewMap.prototype.once);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'un',
+ ol.control.OverviewMap.prototype.un);
+
+goog.exportProperty(
+ ol.control.OverviewMap.prototype,
+ 'unByKey',
+ ol.control.OverviewMap.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'getMap',
+ ol.control.Rotate.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'setMap',
+ ol.control.Rotate.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'setTarget',
+ ol.control.Rotate.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'get',
+ ol.control.Rotate.prototype.get);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'getKeys',
+ ol.control.Rotate.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'getProperties',
+ ol.control.Rotate.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'set',
+ ol.control.Rotate.prototype.set);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'setProperties',
+ ol.control.Rotate.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'unset',
+ ol.control.Rotate.prototype.unset);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'changed',
+ ol.control.Rotate.prototype.changed);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'dispatchEvent',
+ ol.control.Rotate.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'getRevision',
+ ol.control.Rotate.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'on',
+ ol.control.Rotate.prototype.on);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'once',
+ ol.control.Rotate.prototype.once);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'un',
+ ol.control.Rotate.prototype.un);
+
+goog.exportProperty(
+ ol.control.Rotate.prototype,
+ 'unByKey',
+ ol.control.Rotate.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'getMap',
+ ol.control.ScaleLine.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'setMap',
+ ol.control.ScaleLine.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'setTarget',
+ ol.control.ScaleLine.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'get',
+ ol.control.ScaleLine.prototype.get);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'getKeys',
+ ol.control.ScaleLine.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'getProperties',
+ ol.control.ScaleLine.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'set',
+ ol.control.ScaleLine.prototype.set);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'setProperties',
+ ol.control.ScaleLine.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'unset',
+ ol.control.ScaleLine.prototype.unset);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'changed',
+ ol.control.ScaleLine.prototype.changed);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'dispatchEvent',
+ ol.control.ScaleLine.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'getRevision',
+ ol.control.ScaleLine.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'on',
+ ol.control.ScaleLine.prototype.on);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'once',
+ ol.control.ScaleLine.prototype.once);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'un',
+ ol.control.ScaleLine.prototype.un);
+
+goog.exportProperty(
+ ol.control.ScaleLine.prototype,
+ 'unByKey',
+ ol.control.ScaleLine.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'getMap',
+ ol.control.Zoom.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'setMap',
+ ol.control.Zoom.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'setTarget',
+ ol.control.Zoom.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'get',
+ ol.control.Zoom.prototype.get);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'getKeys',
+ ol.control.Zoom.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'getProperties',
+ ol.control.Zoom.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'set',
+ ol.control.Zoom.prototype.set);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'setProperties',
+ ol.control.Zoom.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'unset',
+ ol.control.Zoom.prototype.unset);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'changed',
+ ol.control.Zoom.prototype.changed);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'dispatchEvent',
+ ol.control.Zoom.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'getRevision',
+ ol.control.Zoom.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'on',
+ ol.control.Zoom.prototype.on);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'once',
+ ol.control.Zoom.prototype.once);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'un',
+ ol.control.Zoom.prototype.un);
+
+goog.exportProperty(
+ ol.control.Zoom.prototype,
+ 'unByKey',
+ ol.control.Zoom.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'getMap',
+ ol.control.ZoomSlider.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'setMap',
+ ol.control.ZoomSlider.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'setTarget',
+ ol.control.ZoomSlider.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'get',
+ ol.control.ZoomSlider.prototype.get);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'getKeys',
+ ol.control.ZoomSlider.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'getProperties',
+ ol.control.ZoomSlider.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'set',
+ ol.control.ZoomSlider.prototype.set);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'setProperties',
+ ol.control.ZoomSlider.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'unset',
+ ol.control.ZoomSlider.prototype.unset);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'changed',
+ ol.control.ZoomSlider.prototype.changed);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'dispatchEvent',
+ ol.control.ZoomSlider.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'getRevision',
+ ol.control.ZoomSlider.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'on',
+ ol.control.ZoomSlider.prototype.on);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'once',
+ ol.control.ZoomSlider.prototype.once);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'un',
+ ol.control.ZoomSlider.prototype.un);
+
+goog.exportProperty(
+ ol.control.ZoomSlider.prototype,
+ 'unByKey',
+ ol.control.ZoomSlider.prototype.unByKey);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'getMap',
+ ol.control.ZoomToExtent.prototype.getMap);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'setMap',
+ ol.control.ZoomToExtent.prototype.setMap);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'setTarget',
+ ol.control.ZoomToExtent.prototype.setTarget);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'get',
+ ol.control.ZoomToExtent.prototype.get);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'getKeys',
+ ol.control.ZoomToExtent.prototype.getKeys);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'getProperties',
+ ol.control.ZoomToExtent.prototype.getProperties);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'set',
+ ol.control.ZoomToExtent.prototype.set);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'setProperties',
+ ol.control.ZoomToExtent.prototype.setProperties);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'unset',
+ ol.control.ZoomToExtent.prototype.unset);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'changed',
+ ol.control.ZoomToExtent.prototype.changed);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'dispatchEvent',
+ ol.control.ZoomToExtent.prototype.dispatchEvent);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'getRevision',
+ ol.control.ZoomToExtent.prototype.getRevision);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'on',
+ ol.control.ZoomToExtent.prototype.on);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'once',
+ ol.control.ZoomToExtent.prototype.once);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'un',
+ ol.control.ZoomToExtent.prototype.un);
+
+goog.exportProperty(
+ ol.control.ZoomToExtent.prototype,
+ 'unByKey',
+ ol.control.ZoomToExtent.prototype.unByKey);
+OPENLAYERS.ol = ol;
+
+ return OPENLAYERS.ol;
+}));
diff --git a/chimere/static/ol3/ol.css b/chimere/static/ol3/ol.css
new file mode 100644
index 0000000..ea50e7e
--- /dev/null
+++ b/chimere/static/ol3/ol.css
@@ -0,0 +1 @@
+.ol-control,.ol-scale-line{position:absolute;padding:2px}.ol-box{box-sizing:border-box;border-radius:2px;border:2px solid #00f}.ol-mouse-position{top:8px;right:8px;position:absolute}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width}.ol-overlay-container{will-change:left,right,top,bottom}.ol-unsupported{display:none}.ol-viewport .ol-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.ol-control{background-color:rgba(255,255,255,.4);border-radius:4px}.ol-control:hover{background-color:rgba(255,255,255,.6)}.ol-zoom{top:.5em;left:.5em}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s}.ol-zoom-extent{top:4.643em;left:.5em}.ol-full-screen{right:.5em;top:.5em}@media print{.ol-control{display:none}}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-size:1.14em;font-weight:700;text-decoration:none;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:rgba(0,60,136,.5);border:none;border-radius:2px}.ol-control button::-moz-focus-inner{border:none;padding:0}.ol-zoom-extent button{line-height:1.4em}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform}.ol-touch .ol-control button{font-size:1.5em}.ol-touch .ol-zoom-extent{top:5.5em}.ol-control button:focus,.ol-control button:hover{text-decoration:none;background-color:rgba(0,60,136,.7)}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em)}.ol-attribution ul{margin:0;padding:0 .5em;font-size:.7rem;line-height:1.375em;color:#000;text-shadow:0 0 2px #fff}.ol-attribution li{display:inline;list-style:none;line-height:inherit}.ol-attribution li:not(:last-child):after{content:" "}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle}.ol-attribution button,.ol-attribution ul{display:inline-block}.ol-attribution.ol-collapsed ul{display:none}.ol-attribution.ol-logo-only ul{display:block}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0;height:1.1em;line-height:1em}.ol-attribution.ol-logo-only{background:0 0;bottom:.4em;height:1.1em;line-height:1em}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em}.ol-attribution.ol-logo-only button,.ol-attribution.ol-uncollapsible button{display:none}.ol-zoomslider{top:4.5em;left:.5em;height:200px}.ol-zoomslider button{position:relative;height:10px}.ol-touch .ol-zoomslider{top:5.5em}.ol-overviewmap{left:.5em;bottom:.5em}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0}.ol-overviewmap .ol-overviewmap-map,.ol-overviewmap button{display:inline-block}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px}.ol-overviewmap:not(.ol-collapsed) button{bottom:1px;left:2px;position:absolute}.ol-overviewmap.ol-collapsed .ol-overviewmap-map,.ol-overviewmap.ol-uncollapsible button{display:none}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7)} \ No newline at end of file
diff --git a/chimere/static/ol3/ol.js b/chimere/static/ol3/ol.js
new file mode 100644
index 0000000..6cc1289
--- /dev/null
+++ b/chimere/static/ol3/ol.js
@@ -0,0 +1,998 @@
+// OpenLayers 3. See http://openlayers.org/
+// License: https://raw.githubusercontent.com/openlayers/ol3/master/LICENSE.md
+// Version: v3.17.1
+
+(function (root, factory) {
+ if (typeof exports === "object") {
+ module.exports = factory();
+ } else if (typeof define === "function" && define.amd) {
+ define([], factory);
+ } else {
+ root.ol = factory();
+ }
+}(this, function () {
+ var OPENLAYERS = {};
+ var k,aa=this;function t(a,b,c){a=a.split(".");c=c||aa;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)a.length||void 0===b?c[d]?c=c[d]:c=c[d]={}:c[d]=b}function ba(a){a.Zb=function(){return a.Tg?a.Tg:a.Tg=new a}}
+function ca(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function da(a){return"string"==typeof a}function ea(a){return"number"==typeof a}function fa(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function w(a){return a[ga]||(a[ga]=++ha)}var ga="closure_uid_"+(1E9*Math.random()>>>0),ha=0;function ia(a,b,c){return a.call.apply(a.bind,arguments)}
+function ja(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function ka(a,b,c){ka=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?ia:ja;return ka.apply(null,arguments)};var la,ma;function y(a,b){a.prototype=Object.create(b.prototype);a.prototype.constructor=a}function na(){}var pa=Function("return this")();var qa=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")};function ra(a,b){return a<b?-1:a>b?1:0};function sa(a,b,c){return Math.min(Math.max(a,b),c)}var ta=function(){var a;"cosh"in Math?a=Math.cosh:a=function(a){a=Math.exp(a);return(a+1/a)/2};return a}();function ua(a,b,c,d,e,f){var g=e-c,h=f-d;if(0!==g||0!==h){var l=((a-c)*g+(b-d)*h)/(g*g+h*h);1<l?(c=e,d=f):0<l&&(c+=g*l,d+=h*l)}return va(a,b,c,d)}function va(a,b,c,d){a=c-a;b=d-b;return a*a+b*b}function wa(a){return a*Math.PI/180}function xa(a,b){var c=a%b;return 0>c*b?c+b:c}function za(a,b,c){return a+c*(b-a)};function Ba(a){return function(b){if(b)return[sa(b[0],a[0],a[2]),sa(b[1],a[1],a[3])]}}function Ca(a){return a};function Da(a,b,c){this.center=a;this.resolution=b;this.rotation=c};var Ea="function"===typeof Object.assign?Object.assign:function(a,b){if(!a||!a)throw new TypeError("Cannot convert undefined or null to object");for(var c=Object(a),d=1,e=arguments.length;d<e;++d){var f=arguments[d];if(void 0!==f&&null!==f)for(var g in f)f.hasOwnProperty(g)&&(c[g]=f[g])}return c};function Fa(a){for(var b in a)delete a[b]}function Ga(a){var b=[],c;for(c in a)b.push(a[c]);return b}function Ha(a){for(var b in a)return!1;return!b};var Ia="olm_"+(1E4*Math.random()|0);function Ja(a){function b(b){var d=a.listener,e=a.ng||a.target;a.pg&&Ka(a);return d.call(e,b)}return a.og=b}function La(a,b,c,d){for(var e,f=0,g=a.length;f<g;++f)if(e=a[f],e.listener===b&&e.ng===c)return d&&(e.deleteIndex=f),e}function Ma(a,b){var c=a[Ia];return c?c[b]:void 0}function Na(a){var b=a[Ia];b||(b=a[Ia]={});return b}
+function Oa(a,b){var c=Ma(a,b);if(c){for(var d=0,e=c.length;d<e;++d)a.removeEventListener(b,c[d].og),Fa(c[d]);c.length=0;if(c=a[Ia])delete c[b],0===Object.keys(c).length&&delete a[Ia]}}function B(a,b,c,d,e){var f=Na(a),g=f[b];g||(g=f[b]=[]);(f=La(g,c,d,!1))?e||(f.pg=!1):(f={ng:d,pg:!!e,listener:c,target:a,type:b},a.addEventListener(b,Ja(f)),g.push(f));return f}function Pa(a,b,c,d){return B(a,b,c,d,!0)}function Qa(a,b,c,d){(a=Ma(a,b))&&(c=La(a,c,d,!0))&&Ka(c)}
+function Ka(a){if(a&&a.target){a.target.removeEventListener(a.type,a.og);var b=Ma(a.target,a.type);if(b){var c="deleteIndex"in a?a.deleteIndex:b.indexOf(a);-1!==c&&b.splice(c,1);0===b.length&&Oa(a.target,a.type)}Fa(a)}}function Ra(a){var b=Na(a),c;for(c in b)Oa(a,c)};function Sa(){}Sa.prototype.Gb=!1;function Ta(a){a.Gb||(a.Gb=!0,a.ka())}Sa.prototype.ka=na;function Wa(a,b){this.type=a;this.target=b||null}Wa.prototype.preventDefault=Wa.prototype.stopPropagation=function(){this.to=!0};function Ya(a){a.stopPropagation()}function Za(a){a.preventDefault()};function $a(){this.Ra={};this.Ba={};this.ya={}}y($a,Sa);$a.prototype.addEventListener=function(a,b){var c=this.ya[a];c||(c=this.ya[a]=[]);-1===c.indexOf(b)&&c.push(b)};
+$a.prototype.b=function(a){var b="string"===typeof a?new Wa(a):a;a=b.type;b.target=this;var c=this.ya[a],d;if(c){a in this.Ba||(this.Ba[a]=0,this.Ra[a]=0);++this.Ba[a];for(var e=0,f=c.length;e<f;++e)if(!1===c[e].call(this,b)||b.to){d=!1;break}--this.Ba[a];if(0===this.Ba[a]){b=this.Ra[a];for(delete this.Ra[a];b--;)this.removeEventListener(a,na);delete this.Ba[a]}return d}};$a.prototype.ka=function(){Ra(this)};function ab(a,b){return b?b in a.ya:0<Object.keys(a.ya).length}
+$a.prototype.removeEventListener=function(a,b){var c=this.ya[a];if(c){var d=c.indexOf(b);a in this.Ra?(c[d]=na,++this.Ra[a]):(c.splice(d,1),0===c.length&&delete this.ya[a])}};function bb(){$a.call(this);this.g=0}y(bb,$a);function cb(a){if(Array.isArray(a))for(var b=0,c=a.length;b<c;++b)Ka(a[b]);else Ka(a)}k=bb.prototype;k.u=function(){++this.g;this.b("change")};k.K=function(){return this.g};k.I=function(a,b,c){if(Array.isArray(a)){for(var d=a.length,e=Array(d),f=0;f<d;++f)e[f]=B(this,a[f],b,c);return e}return B(this,a,b,c)};k.L=function(a,b,c){if(Array.isArray(a)){for(var d=a.length,e=Array(d),f=0;f<d;++f)e[f]=Pa(this,a[f],b,c);return e}return Pa(this,a,b,c)};
+k.J=function(a,b,c){if(Array.isArray(a))for(var d=0,e=a.length;d<e;++d)Qa(this,a[d],b,c);else Qa(this,a,b,c)};k.M=cb;function db(a,b,c){Wa.call(this,a);this.key=b;this.oldValue=c}y(db,Wa);function eb(a){bb.call(this);w(this);this.U={};void 0!==a&&this.G(a)}y(eb,bb);var fb={};function gb(a){return fb.hasOwnProperty(a)?fb[a]:fb[a]="change:"+a}k=eb.prototype;k.get=function(a){var b;this.U.hasOwnProperty(a)&&(b=this.U[a]);return b};k.N=function(){return Object.keys(this.U)};k.O=function(){return Ea({},this.U)};function hb(a,b,c){var d;d=gb(b);a.b(new db(d,b,c));a.b(new db("propertychange",b,c))}
+k.set=function(a,b,c){c?this.U[a]=b:(c=this.U[a],this.U[a]=b,c!==b&&hb(this,a,c))};k.G=function(a,b){for(var c in a)this.set(c,a[c],b)};k.P=function(a,b){if(a in this.U){var c=this.U[a];delete this.U[a];b||hb(this,a,c)}};function ib(a,b){return a>b?1:a<b?-1:0}function jb(a,b){return 0<=a.indexOf(b)}function kb(a,b,c){var d=a.length;if(a[0]<=b)return 0;if(!(b<=a[d-1]))if(0<c)for(c=1;c<d;++c){if(a[c]<b)return c-1}else if(0>c)for(c=1;c<d;++c){if(a[c]<=b)return c}else for(c=1;c<d;++c){if(a[c]==b)return c;if(a[c]<b)return a[c-1]-b<b-a[c]?c-1:c}return d-1}function lb(a){return a.reduce(function(a,c){return Array.isArray(c)?a.concat(lb(c)):a.concat(c)},[])}
+function mb(a,b){var c;c=ca(b);var d="array"==c||"object"==c&&"number"==typeof b.length?b:[b],e=d.length;for(c=0;c<e;c++)a[a.length]=d[c]}function nb(a,b){var c=a.indexOf(b),d=-1<c;d&&a.splice(c,1);return d}function ob(a,b){for(var c=a.length>>>0,d,e=0;e<c;e++)if(d=a[e],b(d,e,a))return d;return null}function pb(a,b){var c=a.length;if(c!==b.length)return!1;for(var d=0;d<c;d++)if(a[d]!==b[d])return!1;return!0}
+function qb(a){var b=rb,c=a.length,d=Array(a.length),e;for(e=0;e<c;e++)d[e]={index:e,value:a[e]};d.sort(function(a,c){return b(a.value,c.value)||a.index-c.index});for(e=0;e<a.length;e++)a[e]=d[e].value}function sb(a,b){var c;return a.every(function(d,e){c=e;return!b(d,e,a)})?-1:c};function tb(a){return function(b,c,d){if(void 0!==b)return b=kb(a,b,d),b=sa(b+c,0,a.length-1),a[b]}}function ub(a,b,c){return function(d,e,f){if(void 0!==d)return d=Math.max(Math.floor(Math.log(b/d)/Math.log(a)+(0<f?0:0>f?1:.5))+e,0),void 0!==c&&(d=Math.min(d,c)),b/Math.pow(a,d)}};function vb(a){if(void 0!==a)return 0}function wb(a,b){if(void 0!==a)return a+b}function xb(a){var b=2*Math.PI/a;return function(a,d){if(void 0!==a)return a=Math.floor((a+d)/b+.5)*b}}function yb(){var a=wa(5);return function(b,c){if(void 0!==b)return Math.abs(b+c)<=a?0:b+c}};function zb(a,b){var c=void 0!==b?a.toFixed(b):""+a,d=c.indexOf("."),d=-1===d?c.length:d;return 2<d?c:Array(3-d).join("0")+c}function Ab(a){a=(""+a).split(".");for(var b=["1","3"],c=0;c<Math.max(a.length,b.length);c++){var d=parseInt(a[c]||"0",10),e=parseInt(b[c]||"0",10);if(d>e)return 1;if(e>d)return-1}return 0};function Bb(a,b){a[0]+=b[0];a[1]+=b[1];return a}function Cb(a,b){var c=a[0],d=a[1],e=b[0],f=b[1],g=e[0],e=e[1],h=f[0],f=f[1],l=h-g,m=f-e,c=0===l&&0===m?0:(l*(c-g)+m*(d-e))/(l*l+m*m||0);0>=c||(1<=c?(g=h,e=f):(g+=c*l,e+=c*m));return[g,e]}function Db(a,b,c){a=xa(a+180,360)-180;var d=Math.abs(3600*a);return Math.floor(d/3600)+"\u00b0 "+zb(Math.floor(d/60%60))+"\u2032 "+zb(d%60,c||0)+"\u2033 "+b.charAt(0>a?1:0)}
+function Eb(a,b,c){return a?b.replace("{x}",a[0].toFixed(c)).replace("{y}",a[1].toFixed(c)):""}function Fb(a,b){for(var c=!0,d=a.length-1;0<=d;--d)if(a[d]!=b[d]){c=!1;break}return c}function Gb(a,b){var c=Math.cos(b),d=Math.sin(b),e=a[1]*c+a[0]*d;a[0]=a[0]*c-a[1]*d;a[1]=e;return a}function Hb(a,b){var c=a[0]-b[0],d=a[1]-b[1];return c*c+d*d}function Ib(a,b){return Hb(a,Cb(a,b))}function Jb(a,b){return Eb(a,"{x}, {y}",b)};function Kb(a){for(var b=Lb(),c=0,d=a.length;c<d;++c)Mb(b,a[c]);return b}function Ob(a,b,c){return c?(c[0]=a[0]-b,c[1]=a[1]-b,c[2]=a[2]+b,c[3]=a[3]+b,c):[a[0]-b,a[1]-b,a[2]+b,a[3]+b]}function Pb(a,b){return b?(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b):a.slice()}function Rb(a,b,c){b=b<a[0]?a[0]-b:a[2]<b?b-a[2]:0;a=c<a[1]?a[1]-c:a[3]<c?c-a[3]:0;return b*b+a*a}function Sb(a,b){return Tb(a,b[0],b[1])}function Ub(a,b){return a[0]<=b[0]&&b[2]<=a[2]&&a[1]<=b[1]&&b[3]<=a[3]}
+function Tb(a,b,c){return a[0]<=b&&b<=a[2]&&a[1]<=c&&c<=a[3]}function Vb(a,b){var c=a[1],d=a[2],e=a[3],f=b[0],g=b[1],h=0;f<a[0]?h|=16:f>d&&(h|=4);g<c?h|=8:g>e&&(h|=2);0===h&&(h=1);return h}function Lb(){return[Infinity,Infinity,-Infinity,-Infinity]}function Wb(a,b,c,d,e){return e?(e[0]=a,e[1]=b,e[2]=c,e[3]=d,e):[a,b,c,d]}function Xb(a,b){var c=a[0],d=a[1];return Wb(c,d,c,d,b)}function Yb(a,b,c,d,e){e=Wb(Infinity,Infinity,-Infinity,-Infinity,e);return Zb(e,a,b,c,d)}
+function $b(a,b){return a[0]==b[0]&&a[2]==b[2]&&a[1]==b[1]&&a[3]==b[3]}function ac(a,b){b[0]<a[0]&&(a[0]=b[0]);b[2]>a[2]&&(a[2]=b[2]);b[1]<a[1]&&(a[1]=b[1]);b[3]>a[3]&&(a[3]=b[3]);return a}function Mb(a,b){b[0]<a[0]&&(a[0]=b[0]);b[0]>a[2]&&(a[2]=b[0]);b[1]<a[1]&&(a[1]=b[1]);b[1]>a[3]&&(a[3]=b[1])}function Zb(a,b,c,d,e){for(;c<d;c+=e){var f=a,g=b[c],h=b[c+1];f[0]=Math.min(f[0],g);f[1]=Math.min(f[1],h);f[2]=Math.max(f[2],g);f[3]=Math.max(f[3],h)}return a}
+function bc(a,b,c){var d;return(d=b.call(c,cc(a)))||(d=b.call(c,dc(a)))||(d=b.call(c,ec(a)))?d:(d=b.call(c,fc(a)))?d:!1}function gc(a){var b=0;hc(a)||(b=ic(a)*jc(a));return b}function cc(a){return[a[0],a[1]]}function dc(a){return[a[2],a[1]]}function kc(a){return[(a[0]+a[2])/2,(a[1]+a[3])/2]}
+function lc(a,b,c,d,e){var f=b*d[0]/2;d=b*d[1]/2;b=Math.cos(c);var g=Math.sin(c);c=f*b;f*=g;b*=d;var h=d*g,l=a[0],m=a[1];a=l-c+h;d=l-c-h;g=l+c-h;c=l+c+h;var h=m-f-b,l=m-f+b,n=m+f+b,f=m+f-b;return Wb(Math.min(a,d,g,c),Math.min(h,l,n,f),Math.max(a,d,g,c),Math.max(h,l,n,f),e)}function jc(a){return a[3]-a[1]}function mc(a,b,c){c=c?c:Lb();nc(a,b)&&(c[0]=a[0]>b[0]?a[0]:b[0],c[1]=a[1]>b[1]?a[1]:b[1],c[2]=a[2]<b[2]?a[2]:b[2],c[3]=a[3]<b[3]?a[3]:b[3]);return c}function fc(a){return[a[0],a[3]]}
+function ec(a){return[a[2],a[3]]}function ic(a){return a[2]-a[0]}function nc(a,b){return a[0]<=b[2]&&a[2]>=b[0]&&a[1]<=b[3]&&a[3]>=b[1]}function hc(a){return a[2]<a[0]||a[3]<a[1]}function oc(a,b){var c=(a[2]-a[0])/2*(b-1),d=(a[3]-a[1])/2*(b-1);a[0]-=c;a[2]+=c;a[1]-=d;a[3]+=d}
+function pc(a,b,c){a=[a[0],a[1],a[0],a[3],a[2],a[1],a[2],a[3]];b(a,a,2);var d=[a[0],a[2],a[4],a[6]],e=[a[1],a[3],a[5],a[7]];b=Math.min.apply(null,d);a=Math.min.apply(null,e);d=Math.max.apply(null,d);e=Math.max.apply(null,e);return Wb(b,a,d,e,c)};function qc(){return!0}function rc(){return!1};/*
+
+ Latitude/longitude spherical geodesy formulae taken from
+ http://www.movable-type.co.uk/scripts/latlong.html
+ Licensed under CC-BY-3.0.
+*/
+function sc(a){this.radius=a}sc.prototype.a=function(a){for(var b=0,c=a.length,d=a[c-1][0],e=a[c-1][1],f=0;f<c;f++)var g=a[f][0],h=a[f][1],b=b+wa(g-d)*(2+Math.sin(wa(e))+Math.sin(wa(h))),d=g,e=h;return b*this.radius*this.radius/2};sc.prototype.b=function(a,b){var c=wa(a[1]),d=wa(b[1]),e=(d-c)/2,f=wa(b[0]-a[0])/2,c=Math.sin(e)*Math.sin(e)+Math.sin(f)*Math.sin(f)*Math.cos(c)*Math.cos(d);return 2*this.radius*Math.atan2(Math.sqrt(c),Math.sqrt(1-c))};
+sc.prototype.offset=function(a,b,c){var d=wa(a[1]);b/=this.radius;var e=Math.asin(Math.sin(d)*Math.cos(b)+Math.cos(d)*Math.sin(b)*Math.cos(c));return[180*(wa(a[0])+Math.atan2(Math.sin(c)*Math.sin(b)*Math.cos(d),Math.cos(b)-Math.sin(d)*Math.sin(e)))/Math.PI,180*e/Math.PI]};var tc=new sc(6370997);var uc={};uc.degrees=2*Math.PI*tc.radius/360;uc.ft=.3048;uc.m=1;uc["us-ft"]=1200/3937;
+function vc(a){this.cb=a.code;this.c=a.units;this.f=void 0!==a.extent?a.extent:null;this.i=void 0!==a.worldExtent?a.worldExtent:null;this.b=void 0!==a.axisOrientation?a.axisOrientation:"enu";this.g=void 0!==a.global?a.global:!1;this.a=!(!this.g||!this.f);this.o=void 0!==a.getPointResolution?a.getPointResolution:this.sk;this.l=null;this.j=a.metersPerUnit;var b=wc,c=a.code,d=xc||pa.proj4;if("function"==typeof d&&void 0===b[c]){var e=d.defs(c);if(void 0!==e){void 0!==e.axis&&void 0===a.axisOrientation&&
+(this.b=e.axis);void 0===a.metersPerUnit&&(this.j=e.to_meter);void 0===a.units&&(this.c=e.units);for(var f in b)b=d.defs(f),void 0!==b&&(a=yc(f),b===e?zc([a,this]):(b=d(f,c),Ac(a,this,b.forward,b.inverse)))}}}k=vc.prototype;k.Sj=function(){return this.cb};k.H=function(){return this.f};k.wb=function(){return this.c};k.$b=function(){return this.j||uc[this.c]};k.Ek=function(){return this.i};k.pl=function(){return this.g};k.ep=function(a){this.g=a;this.a=!(!a||!this.f)};
+k.Mm=function(a){this.f=a;this.a=!(!this.g||!a)};k.mp=function(a){this.i=a};k.cp=function(a){this.o=a};k.sk=function(a,b){if("degrees"==this.wb())return a;var c=Bc(this,yc("EPSG:4326")),d=[b[0]-a/2,b[1],b[0]+a/2,b[1],b[0],b[1]-a/2,b[0],b[1]+a/2],d=c(d,d,2),c=tc.b(d.slice(0,2),d.slice(2,4)),d=tc.b(d.slice(4,6),d.slice(6,8)),d=(c+d)/2,c=this.$b();void 0!==c&&(d/=c);return d};k.getPointResolution=function(a,b){return this.o(a,b)};var wc={},Cc={},xc=null;
+function zc(a){Dc(a);a.forEach(function(b){a.forEach(function(a){b!==a&&Ec(b,a,Fc)})})}function Gc(){var a=Hc,b=Ic,c=Jc;Kc.forEach(function(d){a.forEach(function(a){Ec(d,a,b);Ec(a,d,c)})})}function Lc(a){wc[a.cb]=a;Ec(a,a,Fc)}function Dc(a){var b=[];a.forEach(function(a){b.push(Lc(a))})}function Mc(a){return a?"string"===typeof a?yc(a):a:yc("EPSG:3857")}function Ec(a,b,c){a=a.cb;b=b.cb;a in Cc||(Cc[a]={});Cc[a][b]=c}function Ac(a,b,c,d){a=yc(a);b=yc(b);Ec(a,b,Nc(c));Ec(b,a,Nc(d))}
+function Nc(a){return function(b,c,d){var e=b.length;d=void 0!==d?d:2;c=void 0!==c?c:Array(e);var f,g;for(g=0;g<e;g+=d)for(f=a([b[g],b[g+1]]),c[g]=f[0],c[g+1]=f[1],f=d-1;2<=f;--f)c[g+f]=b[g+f];return c}}function yc(a){var b;if(a instanceof vc)b=a;else if("string"===typeof a){b=wc[a];var c=xc||pa.proj4;void 0===b&&"function"==typeof c&&void 0!==c.defs(a)&&(b=new vc({code:a}),Lc(b))}else b=null;return b}function Oc(a,b){if(a===b)return!0;var c=a.wb()===b.wb();return a.cb===b.cb?c:Bc(a,b)===Fc&&c}
+function Pc(a,b){var c=yc(a),d=yc(b);return Bc(c,d)}function Bc(a,b){var c=a.cb,d=b.cb,e;c in Cc&&d in Cc[c]&&(e=Cc[c][d]);void 0===e&&(e=Qc);return e}function Qc(a,b){if(void 0!==b&&a!==b){for(var c=0,d=a.length;c<d;++c)b[c]=a[c];a=b}return a}function Fc(a,b){var c;if(void 0!==b){c=0;for(var d=a.length;c<d;++c)b[c]=a[c];c=b}else c=a.slice();return c}function Rc(a,b,c){return Pc(b,c)(a,void 0,a.length)}function Sc(a,b,c){b=Pc(b,c);return pc(a,b)};function Tc(){eb.call(this);this.v=Lb();this.A=-1;this.l={};this.s=this.o=0}y(Tc,eb);k=Tc.prototype;k.vb=function(a,b){var c=b?b:[NaN,NaN];this.sb(a[0],a[1],c,Infinity);return c};k.sg=function(a){return this.Bc(a[0],a[1])};k.Bc=rc;k.H=function(a){this.A!=this.g&&(this.v=this.Od(this.v),this.A=this.g);var b=this.v;a?(a[0]=b[0],a[1]=b[1],a[2]=b[2],a[3]=b[3]):a=b;return a};k.Bb=function(a){return this.od(a*a)};k.jb=function(a,b){this.rc(Pc(a,b));return this};function Uc(a){this.length=a.length||a;for(var b=0;b<this.length;b++)this[b]=a[b]||0}Uc.prototype.BYTES_PER_ELEMENT=4;Uc.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length&&b+c<this.length;c++)this[b+c]=a[c]};Uc.prototype.toString=Array.prototype.join;"undefined"==typeof Float32Array&&(Uc.BYTES_PER_ELEMENT=4,Uc.prototype.BYTES_PER_ELEMENT=Uc.prototype.BYTES_PER_ELEMENT,Uc.prototype.set=Uc.prototype.set,Uc.prototype.toString=Uc.prototype.toString,t("Float32Array",Uc,void 0));function Vc(a){this.length=a.length||a;for(var b=0;b<this.length;b++)this[b]=a[b]||0}Vc.prototype.BYTES_PER_ELEMENT=8;Vc.prototype.set=function(a,b){b=b||0;for(var c=0;c<a.length&&b+c<this.length;c++)this[b+c]=a[c]};Vc.prototype.toString=Array.prototype.join;if("undefined"==typeof Float64Array){try{Vc.BYTES_PER_ELEMENT=8}catch(a){}Vc.prototype.BYTES_PER_ELEMENT=Vc.prototype.BYTES_PER_ELEMENT;Vc.prototype.set=Vc.prototype.set;Vc.prototype.toString=Vc.prototype.toString;t("Float64Array",Vc,void 0)};function Wc(a,b,c,d,e){a[0]=b;a[1]=c;a[2]=d;a[3]=e};function Xc(){var a=Array(16);Yc(a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);return a}function Zc(){var a=Array(16);Yc(a,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return a}function Yc(a,b,c,d,e,f,g,h,l,m,n,p,q,r,u,x,v){a[0]=b;a[1]=c;a[2]=d;a[3]=e;a[4]=f;a[5]=g;a[6]=h;a[7]=l;a[8]=m;a[9]=n;a[10]=p;a[11]=q;a[12]=r;a[13]=u;a[14]=x;a[15]=v}
+function $c(a,b){a[0]=b[0];a[1]=b[1];a[2]=b[2];a[3]=b[3];a[4]=b[4];a[5]=b[5];a[6]=b[6];a[7]=b[7];a[8]=b[8];a[9]=b[9];a[10]=b[10];a[11]=b[11];a[12]=b[12];a[13]=b[13];a[14]=b[14];a[15]=b[15]}function ad(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1}
+function bd(a,b,c){var d=a[0],e=a[1],f=a[2],g=a[3],h=a[4],l=a[5],m=a[6],n=a[7],p=a[8],q=a[9],r=a[10],u=a[11],x=a[12],v=a[13],D=a[14];a=a[15];var A=b[0],z=b[1],F=b[2],N=b[3],K=b[4],X=b[5],oa=b[6],H=b[7],ya=b[8],Ua=b[9],Xa=b[10],Va=b[11],Aa=b[12],Qb=b[13],Nb=b[14];b=b[15];c[0]=d*A+h*z+p*F+x*N;c[1]=e*A+l*z+q*F+v*N;c[2]=f*A+m*z+r*F+D*N;c[3]=g*A+n*z+u*F+a*N;c[4]=d*K+h*X+p*oa+x*H;c[5]=e*K+l*X+q*oa+v*H;c[6]=f*K+m*X+r*oa+D*H;c[7]=g*K+n*X+u*oa+a*H;c[8]=d*ya+h*Ua+p*Xa+x*Va;c[9]=e*ya+l*Ua+q*Xa+v*Va;c[10]=f*
+ya+m*Ua+r*Xa+D*Va;c[11]=g*ya+n*Ua+u*Xa+a*Va;c[12]=d*Aa+h*Qb+p*Nb+x*b;c[13]=e*Aa+l*Qb+q*Nb+v*b;c[14]=f*Aa+m*Qb+r*Nb+D*b;c[15]=g*Aa+n*Qb+u*Nb+a*b}
+function cd(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],l=a[6],m=a[7],n=a[8],p=a[9],q=a[10],r=a[11],u=a[12],x=a[13],v=a[14],D=a[15],A=c*h-d*g,z=c*l-e*g,F=c*m-f*g,N=d*l-e*h,K=d*m-f*h,X=e*m-f*l,oa=n*x-p*u,H=n*v-q*u,ya=n*D-r*u,Ua=p*v-q*x,Xa=p*D-r*x,Va=q*D-r*v,Aa=A*Va-z*Xa+F*Ua+N*ya-K*H+X*oa;0!=Aa&&(Aa=1/Aa,b[0]=(h*Va-l*Xa+m*Ua)*Aa,b[1]=(-d*Va+e*Xa-f*Ua)*Aa,b[2]=(x*X-v*K+D*N)*Aa,b[3]=(-p*X+q*K-r*N)*Aa,b[4]=(-g*Va+l*ya-m*H)*Aa,b[5]=(c*Va-e*ya+f*H)*Aa,b[6]=(-u*X+v*F-D*z)*Aa,b[7]=(n*X-q*F+r*z)*Aa,
+b[8]=(g*Xa-h*ya+m*oa)*Aa,b[9]=(-c*Xa+d*ya-f*oa)*Aa,b[10]=(u*K-x*F+D*A)*Aa,b[11]=(-n*K+p*F-r*A)*Aa,b[12]=(-g*Ua+h*H-l*oa)*Aa,b[13]=(c*Ua-d*H+e*oa)*Aa,b[14]=(-u*N+x*z-v*A)*Aa,b[15]=(n*N-p*z+q*A)*Aa)}function dd(a,b,c){var d=a[1]*b+a[5]*c+0*a[9]+a[13],e=a[2]*b+a[6]*c+0*a[10]+a[14],f=a[3]*b+a[7]*c+0*a[11]+a[15];a[12]=a[0]*b+a[4]*c+0*a[8]+a[12];a[13]=d;a[14]=e;a[15]=f}
+function ed(a,b,c){Yc(a,a[0]*b,a[1]*b,a[2]*b,a[3]*b,a[4]*c,a[5]*c,a[6]*c,a[7]*c,1*a[8],1*a[9],1*a[10],1*a[11],a[12],a[13],a[14],a[15])}function fd(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=a[4],h=a[5],l=a[6],m=a[7],n=Math.cos(b),p=Math.sin(b);a[0]=c*n+g*p;a[1]=d*n+h*p;a[2]=e*n+l*p;a[3]=f*n+m*p;a[4]=c*-p+g*n;a[5]=d*-p+h*n;a[6]=e*-p+l*n;a[7]=f*-p+m*n}new Float64Array(3);new Float64Array(3);new Float64Array(4);new Float64Array(4);new Float64Array(4);new Float64Array(16);function gd(a,b,c,d,e,f){var g=e[0],h=e[1],l=e[4],m=e[5],n=e[12];e=e[13];for(var p=f?f:[],q=0;b<c;b+=d){var r=a[b],u=a[b+1];p[q++]=g*r+l*u+n;p[q++]=h*r+m*u+e}f&&p.length!=q&&(p.length=q);return p};function hd(){Tc.call(this);this.f="XY";this.a=2;this.B=null}y(hd,Tc);function id(a){if("XY"==a)return 2;if("XYZ"==a||"XYM"==a)return 3;if("XYZM"==a)return 4}k=hd.prototype;k.Bc=rc;k.Od=function(a){return Yb(this.B,0,this.B.length,this.a,a)};k.Ib=function(){return this.B.slice(0,this.a)};k.la=function(){return this.B};k.Jb=function(){return this.B.slice(this.B.length-this.a)};k.Kb=function(){return this.f};
+k.od=function(a){this.s!=this.g&&(Fa(this.l),this.o=0,this.s=this.g);if(0>a||0!==this.o&&a<=this.o)return this;var b=a.toString();if(this.l.hasOwnProperty(b))return this.l[b];var c=this.Nc(a);if(c.la().length<this.B.length)return this.l[b]=c;this.o=a;return this};k.Nc=function(){return this};k.va=function(){return this.a};function jd(a,b,c){a.a=id(b);a.f=b;a.B=c}
+function kd(a,b,c,d){if(b)c=id(b);else{for(b=0;b<d;++b){if(0===c.length){a.f="XY";a.a=2;return}c=c[0]}c=c.length;b=2==c?"XY":3==c?"XYZ":4==c?"XYZM":void 0}a.f=b;a.a=c}k.rc=function(a){this.B&&(a(this.B,this.B,this.a),this.u())};k.rotate=function(a,b){var c=this.la();if(c){for(var d=c.length,e=this.va(),f=c?c:[],g=Math.cos(a),h=Math.sin(a),l=b[0],m=b[1],n=0,p=0;p<d;p+=e){var q=c[p]-l,r=c[p+1]-m;f[n++]=l+q*g-r*h;f[n++]=m+q*h+r*g;for(q=p+2;q<p+e;++q)f[n++]=c[q]}c&&f.length!=n&&(f.length=n);this.u()}};
+k.Sc=function(a,b){var c=this.la();if(c){var d=c.length,e=this.va(),f=c?c:[],g=0,h,l;for(h=0;h<d;h+=e)for(f[g++]=c[h]+a,f[g++]=c[h+1]+b,l=h+2;l<h+e;++l)f[g++]=c[l];c&&f.length!=g&&(f.length=g);this.u()}};function ld(a,b,c,d){for(var e=0,f=a[c-d],g=a[c-d+1];b<c;b+=d)var h=a[b],l=a[b+1],e=e+(g*h-f*l),f=h,g=l;return e/2}function md(a,b,c,d){var e=0,f,g;f=0;for(g=c.length;f<g;++f){var h=c[f],e=e+ld(a,b,h,d);b=h}return e};function nd(a,b,c,d,e,f,g){var h=a[b],l=a[b+1],m=a[c]-h,n=a[c+1]-l;if(0!==m||0!==n)if(f=((e-h)*m+(f-l)*n)/(m*m+n*n),1<f)b=c;else if(0<f){for(e=0;e<d;++e)g[e]=za(a[b+e],a[c+e],f);g.length=d;return}for(e=0;e<d;++e)g[e]=a[b+e];g.length=d}function od(a,b,c,d,e){var f=a[b],g=a[b+1];for(b+=d;b<c;b+=d){var h=a[b],l=a[b+1],f=va(f,g,h,l);f>e&&(e=f);f=h;g=l}return e}function pd(a,b,c,d,e){var f,g;f=0;for(g=c.length;f<g;++f){var h=c[f];e=od(a,b,h,d,e);b=h}return e}
+function qd(a,b,c,d,e,f,g,h,l,m,n){if(b==c)return m;var p;if(0===e){p=va(g,h,a[b],a[b+1]);if(p<m){for(n=0;n<d;++n)l[n]=a[b+n];l.length=d;return p}return m}for(var q=n?n:[NaN,NaN],r=b+d;r<c;)if(nd(a,r-d,r,d,g,h,q),p=va(g,h,q[0],q[1]),p<m){m=p;for(n=0;n<d;++n)l[n]=q[n];l.length=d;r+=d}else r+=d*Math.max((Math.sqrt(p)-Math.sqrt(m))/e|0,1);if(f&&(nd(a,c-d,b,d,g,h,q),p=va(g,h,q[0],q[1]),p<m)){m=p;for(n=0;n<d;++n)l[n]=q[n];l.length=d}return m}
+function rd(a,b,c,d,e,f,g,h,l,m,n){n=n?n:[NaN,NaN];var p,q;p=0;for(q=c.length;p<q;++p){var r=c[p];m=qd(a,b,r,d,e,f,g,h,l,m,n);b=r}return m};function sd(a,b){var c=0,d,e;d=0;for(e=b.length;d<e;++d)a[c++]=b[d];return c}function td(a,b,c,d){var e,f;e=0;for(f=c.length;e<f;++e){var g=c[e],h;for(h=0;h<d;++h)a[b++]=g[h]}return b}function ud(a,b,c,d,e){e=e?e:[];var f=0,g,h;g=0;for(h=c.length;g<h;++g)b=td(a,b,c[g],d),e[f++]=b;e.length=f;return e};function vd(a,b,c,d,e){e=void 0!==e?e:[];for(var f=0;b<c;b+=d)e[f++]=a.slice(b,b+d);e.length=f;return e}function wd(a,b,c,d,e){e=void 0!==e?e:[];var f=0,g,h;g=0;for(h=c.length;g<h;++g){var l=c[g];e[f++]=vd(a,b,l,d,e[f]);b=l}e.length=f;return e};function xd(a,b,c,d,e,f,g){var h=(c-b)/d;if(3>h){for(;b<c;b+=d)f[g++]=a[b],f[g++]=a[b+1];return g}var l=Array(h);l[0]=1;l[h-1]=1;c=[b,c-d];for(var m=0,n;0<c.length;){var p=c.pop(),q=c.pop(),r=0,u=a[q],x=a[q+1],v=a[p],D=a[p+1];for(n=q+d;n<p;n+=d){var A=ua(a[n],a[n+1],u,x,v,D);A>r&&(m=n,r=A)}r>e&&(l[(m-b)/d]=1,q+d<m&&c.push(q,m),m+d<p&&c.push(m,p))}for(n=0;n<h;++n)l[n]&&(f[g++]=a[b+n*d],f[g++]=a[b+n*d+1]);return g}
+function yd(a,b,c,d,e,f,g,h){var l,m;l=0;for(m=c.length;l<m;++l){var n=c[l];a:{var p=a,q=n,r=d,u=e,x=f;if(b!=q){var v=u*Math.round(p[b]/u),D=u*Math.round(p[b+1]/u);b+=r;x[g++]=v;x[g++]=D;var A,z;do if(A=u*Math.round(p[b]/u),z=u*Math.round(p[b+1]/u),b+=r,b==q){x[g++]=A;x[g++]=z;break a}while(A==v&&z==D);for(;b<q;){var F,N;F=u*Math.round(p[b]/u);N=u*Math.round(p[b+1]/u);b+=r;if(F!=A||N!=z){var K=A-v,X=z-D,oa=F-v,H=N-D;K*H==X*oa&&(0>K&&oa<K||K==oa||0<K&&oa>K)&&(0>X&&H<X||X==H||0<X&&H>X)||(x[g++]=A,x[g++]=
+z,v=A,D=z);A=F;z=N}}x[g++]=A;x[g++]=z}}h.push(g);b=n}return g};function zd(a,b){hd.call(this);this.i=this.j=-1;this.pa(a,b)}y(zd,hd);k=zd.prototype;k.clone=function(){var a=new zd(null);Ad(a,this.f,this.B.slice());return a};k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;this.i!=this.g&&(this.j=Math.sqrt(od(this.B,0,this.B.length,this.a,0)),this.i=this.g);return qd(this.B,0,this.B.length,this.a,this.j,!0,a,b,c,d)};k.nm=function(){return ld(this.B,0,this.B.length,this.a)};k.Z=function(){return vd(this.B,0,this.B.length,this.a)};
+k.Nc=function(a){var b=[];b.length=xd(this.B,0,this.B.length,this.a,a,b,0);a=new zd(null);Ad(a,"XY",b);return a};k.X=function(){return"LinearRing"};k.pa=function(a,b){a?(kd(this,b,a,1),this.B||(this.B=[]),this.B.length=td(this.B,0,a,this.a),this.u()):Ad(this,"XY",null)};function Ad(a,b,c){jd(a,b,c);a.u()};function C(a,b){hd.call(this);this.pa(a,b)}y(C,hd);k=C.prototype;k.clone=function(){var a=new C(null);a.ba(this.f,this.B.slice());return a};k.sb=function(a,b,c,d){var e=this.B;a=va(a,b,e[0],e[1]);if(a<d){d=this.a;for(b=0;b<d;++b)c[b]=e[b];c.length=d;return a}return d};k.Z=function(){return this.B?this.B.slice():[]};k.Od=function(a){return Xb(this.B,a)};k.X=function(){return"Point"};k.Ka=function(a){return Tb(a,this.B[0],this.B[1])};
+k.pa=function(a,b){a?(kd(this,b,a,0),this.B||(this.B=[]),this.B.length=sd(this.B,a),this.u()):this.ba("XY",null)};k.ba=function(a,b){jd(this,a,b);this.u()};function Bd(a,b,c,d,e){return!bc(e,function(e){return!Cd(a,b,c,d,e[0],e[1])})}function Cd(a,b,c,d,e,f){for(var g=!1,h=a[c-d],l=a[c-d+1];b<c;b+=d){var m=a[b],n=a[b+1];l>f!=n>f&&e<(m-h)*(f-l)/(n-l)+h&&(g=!g);h=m;l=n}return g}function Dd(a,b,c,d,e,f){if(0===c.length||!Cd(a,b,c[0],d,e,f))return!1;var g;b=1;for(g=c.length;b<g;++b)if(Cd(a,c[b-1],c[b],d,e,f))return!1;return!0};function Ed(a,b,c,d,e,f,g){var h,l,m,n,p,q=e[f+1],r=[],u=c[0];m=a[u-d];p=a[u-d+1];for(h=b;h<u;h+=d){n=a[h];l=a[h+1];if(q<=p&&l<=q||p<=q&&q<=l)m=(q-p)/(l-p)*(n-m)+m,r.push(m);m=n;p=l}u=NaN;p=-Infinity;r.sort(ib);m=r[0];h=1;for(l=r.length;h<l;++h){n=r[h];var x=Math.abs(n-m);x>p&&(m=(m+n)/2,Dd(a,b,c,d,m,q)&&(u=m,p=x));m=n}isNaN(u)&&(u=e[f]);return g?(g.push(u,q),g):[u,q]};function Fd(a,b,c,d,e,f){for(var g=[a[b],a[b+1]],h=[],l;b+d<c;b+=d){h[0]=a[b+d];h[1]=a[b+d+1];if(l=e.call(f,g,h))return l;g[0]=h[0];g[1]=h[1]}return!1};function Gd(a,b,c,d,e){var f=Zb(Lb(),a,b,c,d);return nc(e,f)?Ub(e,f)||f[0]>=e[0]&&f[2]<=e[2]||f[1]>=e[1]&&f[3]<=e[3]?!0:Fd(a,b,c,d,function(a,b){var c=!1,d=Vb(e,a),f=Vb(e,b);if(1===d||1===f)c=!0;else{var p=e[0],q=e[1],r=e[2],u=e[3],x=b[0],v=b[1],D=(v-a[1])/(x-a[0]);f&2&&!(d&2)&&(c=x-(v-u)/D,c=c>=p&&c<=r);c||!(f&4)||d&4||(c=v-(x-r)*D,c=c>=q&&c<=u);c||!(f&8)||d&8||(c=x-(v-q)/D,c=c>=p&&c<=r);c||!(f&16)||d&16||(c=v-(x-p)*D,c=c>=q&&c<=u)}return c}):!1}
+function Hd(a,b,c,d,e){var f=c[0];if(!(Gd(a,b,f,d,e)||Cd(a,b,f,d,e[0],e[1])||Cd(a,b,f,d,e[0],e[3])||Cd(a,b,f,d,e[2],e[1])||Cd(a,b,f,d,e[2],e[3])))return!1;if(1===c.length)return!0;b=1;for(f=c.length;b<f;++b)if(Bd(a,c[b-1],c[b],d,e))return!1;return!0};function Id(a,b,c,d){for(var e=0,f=a[c-d],g=a[c-d+1];b<c;b+=d)var h=a[b],l=a[b+1],e=e+(h-f)*(l+g),f=h,g=l;return 0<e}function Jd(a,b,c,d){var e=0;d=void 0!==d?d:!1;var f,g;f=0;for(g=b.length;f<g;++f){var h=b[f],e=Id(a,e,h,c);if(0===f){if(d&&e||!d&&!e)return!1}else if(d&&!e||!d&&e)return!1;e=h}return!0}
+function Kd(a,b,c,d,e){e=void 0!==e?e:!1;var f,g;f=0;for(g=c.length;f<g;++f){var h=c[f],l=Id(a,b,h,d);if(0===f?e&&l||!e&&!l:e&&!l||!e&&l)for(var l=a,m=h,n=d;b<m-n;){var p;for(p=0;p<n;++p){var q=l[b+p];l[b+p]=l[m-n+p];l[m-n+p]=q}b+=n;m-=n}b=h}return b}function Ld(a,b,c,d){var e=0,f,g;f=0;for(g=b.length;f<g;++f)e=Kd(a,e,b[f],c,d);return e};function E(a,b){hd.call(this);this.i=[];this.C=-1;this.D=null;this.T=this.R=this.S=-1;this.j=null;this.pa(a,b)}y(E,hd);k=E.prototype;k.yj=function(a){this.B?mb(this.B,a.la()):this.B=a.la().slice();this.i.push(this.B.length);this.u()};k.clone=function(){var a=new E(null);a.ba(this.f,this.B.slice(),this.i.slice());return a};
+k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;this.R!=this.g&&(this.S=Math.sqrt(pd(this.B,0,this.i,this.a,0)),this.R=this.g);return rd(this.B,0,this.i,this.a,this.S,!0,a,b,c,d)};k.Bc=function(a,b){return Dd(this.Mb(),0,this.i,this.a,a,b)};k.qm=function(){return md(this.Mb(),0,this.i,this.a)};k.Z=function(a){var b;void 0!==a?(b=this.Mb().slice(),Kd(b,0,this.i,this.a,a)):b=this.B;return wd(b,0,this.i,this.a)};k.Db=function(){return this.i};
+function Md(a){if(a.C!=a.g){var b=kc(a.H());a.D=Ed(a.Mb(),0,a.i,a.a,b,0);a.C=a.g}return a.D}k.bk=function(){return new C(Md(this))};k.gk=function(){return this.i.length};k.Hg=function(a){if(0>a||this.i.length<=a)return null;var b=new zd(null);Ad(b,this.f,this.B.slice(0===a?0:this.i[a-1],this.i[a]));return b};k.Vd=function(){var a=this.f,b=this.B,c=this.i,d=[],e=0,f,g;f=0;for(g=c.length;f<g;++f){var h=c[f],l=new zd(null);Ad(l,a,b.slice(e,h));d.push(l);e=h}return d};
+k.Mb=function(){if(this.T!=this.g){var a=this.B;Jd(a,this.i,this.a)?this.j=a:(this.j=a.slice(),this.j.length=Kd(this.j,0,this.i,this.a));this.T=this.g}return this.j};k.Nc=function(a){var b=[],c=[];b.length=yd(this.B,0,this.i,this.a,Math.sqrt(a),b,0,c);a=new E(null);a.ba("XY",b,c);return a};k.X=function(){return"Polygon"};k.Ka=function(a){return Hd(this.Mb(),0,this.i,this.a,a)};
+k.pa=function(a,b){if(a){kd(this,b,a,2);this.B||(this.B=[]);var c=ud(this.B,0,a,this.a,this.i);this.B.length=0===c.length?0:c[c.length-1];this.u()}else this.ba("XY",null,this.i)};k.ba=function(a,b,c){jd(this,a,b);this.i=c;this.u()};function Nd(a,b,c,d){var e=d?d:32;d=[];var f;for(f=0;f<e;++f)mb(d,a.offset(b,c,2*Math.PI*f/e));d.push(d[0],d[1]);a=new E(null);a.ba("XY",d,[d.length]);return a}
+function Od(a){var b=a[0],c=a[1],d=a[2];a=a[3];b=[b,c,b,a,d,a,d,c,b,c];c=new E(null);c.ba("XY",b,[b.length]);return c}function Pd(a,b,c){var d=b?b:32,e=a.va();b=a.f;for(var f=new E(null,b),d=e*(d+1),e=Array(d),g=0;g<d;g++)e[g]=0;f.ba(b,e,[e.length]);Qd(f,a.rd(),a.wf(),c);return f}function Qd(a,b,c,d){var e=a.la(),f=a.f,g=a.va(),h=a.Db(),l=e.length/g-1;d=d?d:0;for(var m,n,p=0;p<=l;++p)n=p*g,m=d+2*xa(p,l)*Math.PI/l,e[n]=b[0]+c*Math.cos(m),e[n+1]=b[1]+c*Math.sin(m);a.ba(f,e,h)};function Rd(a){eb.call(this);a=a||{};this.f=[0,0];var b={};b.center=void 0!==a.center?a.center:null;this.l=Mc(a.projection);var c,d,e,f=void 0!==a.minZoom?a.minZoom:0;c=void 0!==a.maxZoom?a.maxZoom:28;var g=void 0!==a.zoomFactor?a.zoomFactor:2;if(void 0!==a.resolutions)c=a.resolutions,d=c[0],e=c[c.length-1],c=tb(c);else{d=Mc(a.projection);e=d.H();var h=(e?Math.max(ic(e),jc(e)):360*uc.degrees/d.$b())/256/Math.pow(2,0),l=h/Math.pow(2,28);d=a.maxResolution;void 0!==d?f=0:d=h/Math.pow(g,f);e=a.minResolution;
+void 0===e&&(e=void 0!==a.maxZoom?void 0!==a.maxResolution?d/Math.pow(g,c):h/Math.pow(g,c):l);c=f+Math.floor(Math.log(d/e)/Math.log(g));e=d/Math.pow(g,c-f);c=ub(g,d,c-f)}this.a=d;this.c=e;this.j=a.resolutions;this.i=f;f=void 0!==a.extent?Ba(a.extent):Ca;(void 0!==a.enableRotation?a.enableRotation:1)?(d=a.constrainRotation,d=void 0===d||!0===d?yb():!1===d?wb:ea(d)?xb(d):wb):d=vb;this.o=new Da(f,c,d);void 0!==a.resolution?b.resolution=a.resolution:void 0!==a.zoom&&(b.resolution=this.constrainResolution(this.a,
+a.zoom-this.i));b.rotation=void 0!==a.rotation?a.rotation:0;this.G(b)}y(Rd,eb);k=Rd.prototype;k.Pd=function(a){return this.o.center(a)};k.constrainResolution=function(a,b,c){return this.o.resolution(a,b||0,c||0)};k.constrainRotation=function(a,b){return this.o.rotation(a,b||0)};k.ab=function(){return this.get("center")};function Sd(a,b){return void 0!==b?(b[0]=a.f[0],b[1]=a.f[1],b):a.f.slice()}k.Kc=function(a){var b=this.ab(),c=this.$(),d=this.La();return lc(b,c,d,a)};k.Vl=function(){return this.a};
+k.Wl=function(){return this.c};k.Xl=function(){return this.l};k.$=function(){return this.get("resolution")};k.Yl=function(){return this.j};function Td(a,b){return Math.max(ic(a)/b[0],jc(a)/b[1])}function Ud(a){var b=a.a,c=Math.log(b/a.c)/Math.log(2);return function(a){return b/Math.pow(2,a*c)}}k.La=function(){return this.get("rotation")};function Vd(a){var b=a.a,c=Math.log(b/a.c)/Math.log(2);return function(a){return Math.log(b/a)/Math.log(2)/c}}
+k.V=function(){var a=this.ab(),b=this.l,c=this.$(),d=this.La();return{center:[Math.round(a[0]/c)*c,Math.round(a[1]/c)*c],projection:void 0!==b?b:null,resolution:c,rotation:d}};k.Fk=function(){var a,b=this.$();if(void 0!==b){var c,d=0;do{c=this.constrainResolution(this.a,d);if(c==b){a=d;break}++d}while(c>this.c)}return void 0!==a?this.i+a:a};
+k.cf=function(a,b,c){a instanceof hd||(a=Od(a));var d=c||{};c=void 0!==d.padding?d.padding:[0,0,0,0];var e=void 0!==d.constrainResolution?d.constrainResolution:!0,f=void 0!==d.nearest?d.nearest:!1,g;void 0!==d.minResolution?g=d.minResolution:void 0!==d.maxZoom?g=this.constrainResolution(this.a,d.maxZoom-this.i,0):g=0;var h=a.la(),l=this.La(),d=Math.cos(-l),l=Math.sin(-l),m=Infinity,n=Infinity,p=-Infinity,q=-Infinity;a=a.va();for(var r=0,u=h.length;r<u;r+=a)var x=h[r]*d-h[r+1]*l,v=h[r]*l+h[r+1]*d,
+m=Math.min(m,x),n=Math.min(n,v),p=Math.max(p,x),q=Math.max(q,v);b=Td([m,n,p,q],[b[0]-c[1]-c[3],b[1]-c[0]-c[2]]);b=isNaN(b)?g:Math.max(b,g);e&&(g=this.constrainResolution(b,0,0),!f&&g<b&&(g=this.constrainResolution(g,-1,0)),b=g);this.Ub(b);l=-l;f=(m+p)/2+(c[1]-c[3])/2*b;c=(n+q)/2+(c[0]-c[2])/2*b;this.mb([f*d-c*l,c*d+f*l])};
+k.Ej=function(a,b,c){var d=this.La(),e=Math.cos(-d),d=Math.sin(-d),f=a[0]*e-a[1]*d;a=a[1]*e+a[0]*d;var g=this.$(),f=f+(b[0]/2-c[0])*g;a+=(c[1]-b[1]/2)*g;d=-d;this.mb([f*e-a*d,a*e+f*d])};function Wd(a){return!!a.ab()&&void 0!==a.$()}k.rotate=function(a,b){if(void 0!==b){var c,d=this.ab();void 0!==d&&(c=[d[0]-b[0],d[1]-b[1]],Gb(c,a-this.La()),Bb(c,b));this.mb(c)}this.ie(a)};k.mb=function(a){this.set("center",a)};function Xd(a,b){a.f[1]+=b}k.Ub=function(a){this.set("resolution",a)};
+k.ie=function(a){this.set("rotation",a)};k.np=function(a){a=this.constrainResolution(this.a,a-this.i,0);this.Ub(a)};function Yd(a){return Math.pow(a,3)}function Zd(a){return 1-Yd(1-a)}function $d(a){return 3*a*a-2*a*a*a}function ae(a){return a}function be(a){return.5>a?$d(2*a):1-$d(2*(a-.5))};function ce(a){var b=a.source,c=a.start?a.start:Date.now(),d=b[0],e=b[1],f=void 0!==a.duration?a.duration:1E3,g=a.easing?a.easing:$d;return function(a,b){if(b.time<c)return b.animate=!0,b.viewHints[0]+=1,!0;if(b.time<c+f){var m=1-g((b.time-c)/f),n=d-b.viewState.center[0],p=e-b.viewState.center[1];b.animate=!0;b.viewState.center[0]+=m*n;b.viewState.center[1]+=m*p;b.viewHints[0]+=1;return!0}return!1}}
+function de(a){var b=a.rotation?a.rotation:0,c=a.start?a.start:Date.now(),d=void 0!==a.duration?a.duration:1E3,e=a.easing?a.easing:$d,f=a.anchor?a.anchor:null;return function(a,h){if(h.time<c)return h.animate=!0,h.viewHints[0]+=1,!0;if(h.time<c+d){var l=1-e((h.time-c)/d),l=(b-h.viewState.rotation)*l;h.animate=!0;h.viewState.rotation+=l;if(f){var m=h.viewState.center;m[0]-=f[0];m[1]-=f[1];Gb(m,l);Bb(m,f)}h.viewHints[0]+=1;return!0}return!1}}
+function ee(a){var b=a.resolution,c=a.start?a.start:Date.now(),d=void 0!==a.duration?a.duration:1E3,e=a.easing?a.easing:$d;return function(a,g){if(g.time<c)return g.animate=!0,g.viewHints[0]+=1,!0;if(g.time<c+d){var h=1-e((g.time-c)/d),l=b-g.viewState.resolution;g.animate=!0;g.viewState.resolution+=h*l;g.viewHints[0]+=1;return!0}return!1}};function fe(a,b,c,d){this.ca=a;this.ea=b;this.fa=c;this.ga=d}fe.prototype.contains=function(a){return ge(this,a[1],a[2])};function ge(a,b,c){return a.ca<=b&&b<=a.ea&&a.fa<=c&&c<=a.ga}function he(a,b){return a.ca==b.ca&&a.fa==b.fa&&a.ea==b.ea&&a.ga==b.ga}function ie(a,b){return a.ca<=b.ea&&a.ea>=b.ca&&a.fa<=b.ga&&a.ga>=b.fa};function je(a){this.a=a.html;this.b=a.tileRanges?a.tileRanges:null}je.prototype.g=function(){return this.a};function ke(a,b,c){Wa.call(this,a,c);this.element=b}y(ke,Wa);function le(a){eb.call(this);this.a=a?a:[];me(this)}y(le,eb);k=le.prototype;k.clear=function(){for(;0<this.dc();)this.pop()};k.qf=function(a){var b,c;b=0;for(c=a.length;b<c;++b)this.push(a[b]);return this};k.forEach=function(a,b){this.a.forEach(a,b)};k.Gl=function(){return this.a};k.item=function(a){return this.a[a]};k.dc=function(){return this.get("length")};k.ee=function(a,b){this.a.splice(a,0,b);me(this);this.b(new ke("add",b,this))};
+k.pop=function(){return this.Rf(this.dc()-1)};k.push=function(a){var b=this.a.length;this.ee(b,a);return b};k.remove=function(a){var b=this.a,c,d;c=0;for(d=b.length;c<d;++c)if(b[c]===a)return this.Rf(c)};k.Rf=function(a){var b=this.a[a];this.a.splice(a,1);me(this);this.b(new ke("remove",b,this));return b};k.Zo=function(a,b){var c=this.dc();if(a<c)c=this.a[a],this.a[a]=b,this.b(new ke("remove",c,this)),this.b(new ke("add",b,this));else{for(;c<a;++c)this.ee(c,void 0);this.ee(a,b)}};
+function me(a){a.set("length",a.a.length)};function ne(a){return Array.prototype.concat.apply(Array.prototype,arguments)}function oe(a){var b=a.length;if(0<b){for(var c=Array(b),d=0;d<b;d++)c[d]=a[d];return c}return[]}function pe(a,b,c){return 2>=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.slice.call(a,b,c)};var qe=/^#(?:[0-9a-f]{3}){1,2}$/i,re=/^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i,se=/^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;function te(a){return Array.isArray(a)?a:ue(a)}function ve(a){if("string"!==typeof a){var b=a[0];b!=(b|0)&&(b=b+.5|0);var c=a[1];c!=(c|0)&&(c=c+.5|0);var d=a[2];d!=(d|0)&&(d=d+.5|0);a="rgba("+b+","+c+","+d+","+(void 0===a[3]?1:a[3])+")"}return a}
+var ue=function(){var a={},b=0;return function(c){var d;if(a.hasOwnProperty(c))d=a[c];else{if(1024<=b){d=0;for(var e in a)0===(d++&3)&&(delete a[e],--b)}var f,g;qe.exec(c)?(g=3==c.length-1?1:2,d=parseInt(c.substr(1+0*g,g),16),e=parseInt(c.substr(1+1*g,g),16),f=parseInt(c.substr(1+2*g,g),16),1==g&&(d=(d<<4)+d,e=(e<<4)+e,f=(f<<4)+f),d=[d,e,f,1]):(g=se.exec(c))?(d=Number(g[1]),e=Number(g[2]),f=Number(g[3]),g=Number(g[4]),d=[d,e,f,g],d=we(d,d)):(g=re.exec(c))?(d=Number(g[1]),e=Number(g[2]),f=Number(g[3]),
+d=[d,e,f,1],d=we(d,d)):d=void 0;a[c]=d;++b}return d}}();function we(a,b){var c=b||[];c[0]=sa(a[0]+.5|0,0,255);c[1]=sa(a[1]+.5|0,0,255);c[2]=sa(a[2]+.5|0,0,255);c[3]=sa(a[3],0,1);return c};function xe(a){return"string"===typeof a||a instanceof CanvasPattern||a instanceof CanvasGradient?a:ve(a)};var ye;a:{var ze=aa.navigator;if(ze){var Ae=ze.userAgent;if(Ae){ye=Ae;break a}}ye=""}function Be(a){return-1!=ye.indexOf(a)};var Ce=Be("Opera"),Ee=Be("Trident")||Be("MSIE"),Fe=Be("Edge"),Ge=Be("Gecko")&&!(-1!=ye.toLowerCase().indexOf("webkit")&&!Be("Edge"))&&!(Be("Trident")||Be("MSIE"))&&!Be("Edge"),He=-1!=ye.toLowerCase().indexOf("webkit")&&!Be("Edge"),Ie;
+a:{var Je="",Ke=function(){var a=ye;if(Ge)return/rv\:([^\);]+)(\)|;)/.exec(a);if(Fe)return/Edge\/([\d\.]+)/.exec(a);if(Ee)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(He)return/WebKit\/(\S+)/.exec(a);if(Ce)return/(?:Version)[ \/]?(\S+)/.exec(a)}();Ke&&(Je=Ke?Ke[1]:"");if(Ee){var Le,Me=aa.document;Le=Me?Me.documentMode:void 0;if(null!=Le&&Le>parseFloat(Je)){Ie=String(Le);break a}}Ie=Je}var Ne={};function Oe(a,b){var c=document.createElement("CANVAS");a&&(c.width=a);b&&(c.height=b);return c.getContext("2d")}
+var Pe=function(){var a;return function(){if(void 0===a){var b=document.createElement("P"),c,d={webkitTransform:"-webkit-transform",OTransform:"-o-transform",msTransform:"-ms-transform",MozTransform:"-moz-transform",transform:"transform"};document.body.appendChild(b);for(var e in d)e in b.style&&(b.style[e]="translate(1px,1px)",c=pa.getComputedStyle(b).getPropertyValue(d[e]));document.body.removeChild(b);a=c&&"none"!==c}return a}}(),Qe=function(){var a;return function(){if(void 0===a){var b=document.createElement("P"),
+c,d={webkitTransform:"-webkit-transform",OTransform:"-o-transform",msTransform:"-ms-transform",MozTransform:"-moz-transform",transform:"transform"};document.body.appendChild(b);for(var e in d)e in b.style&&(b.style[e]="translate3d(1px,1px,1px)",c=pa.getComputedStyle(b).getPropertyValue(d[e]));document.body.removeChild(b);a=c&&"none"!==c}return a}}();
+function Re(a,b){var c=a.style;c.WebkitTransform=b;c.MozTransform=b;c.b=b;c.msTransform=b;c.transform=b;if((c=Ee)&&!(c=Ne["9.0"])){for(var c=0,d=qa(String(Ie)).split("."),e=qa("9.0").split("."),f=Math.max(d.length,e.length),g=0;0==c&&g<f;g++){var h=d[g]||"",l=e[g]||"",m=RegExp("(\\d*)(\\D*)","g"),n=RegExp("(\\d*)(\\D*)","g");do{var p=m.exec(h)||["","",""],q=n.exec(l)||["","",""];if(0==p[0].length&&0==q[0].length)break;c=ra(0==p[1].length?0:parseInt(p[1],10),0==q[1].length?0:parseInt(q[1],10))||ra(0==
+p[2].length,0==q[2].length)||ra(p[2],q[2])}while(0==c)}c=Ne["9.0"]=0<=c}c&&(a.style.transformOrigin="0 0")}function Se(a,b){var c;if(Qe()){var d=Array(16);for(c=0;16>c;++c)d[c]=b[c].toFixed(6);Re(a,"matrix3d("+d.join(",")+")")}else if(Pe()){var d=[b[0],b[1],b[4],b[5],b[12],b[13]],e=Array(6);for(c=0;6>c;++c)e[c]=d[c].toFixed(6);Re(a,"matrix("+e.join(",")+")")}else a.style.left=Math.round(b[12])+"px",a.style.top=Math.round(b[13])+"px"}function Te(a,b){var c=b.parentNode;c&&c.replaceChild(a,b)}
+function Ue(a){a&&a.parentNode&&a.parentNode.removeChild(a)}function Ve(a){for(;a.lastChild;)a.removeChild(a.lastChild)};function We(a,b,c){Wa.call(this,a);this.map=b;this.frameState=void 0!==c?c:null}y(We,Wa);function Xe(a){eb.call(this);this.element=a.element?a.element:null;this.a=this.S=null;this.s=[];this.render=a.render?a.render:na;a.target&&this.c(a.target)}y(Xe,eb);Xe.prototype.ka=function(){Ue(this.element);eb.prototype.ka.call(this)};Xe.prototype.i=function(){return this.a};
+Xe.prototype.setMap=function(a){this.a&&Ue(this.element);for(var b=0,c=this.s.length;b<c;++b)Ka(this.s[b]);this.s.length=0;if(this.a=a)(this.S?this.S:a.v).appendChild(this.element),this.render!==na&&this.s.push(B(a,"postrender",this.render,this)),a.render()};Xe.prototype.c=function(a){this.S="string"===typeof a?document.getElementById(a):a};function Ye(){this.g=0;this.f={};this.a=this.b=null}k=Ye.prototype;k.clear=function(){this.g=0;this.f={};this.a=this.b=null};function Ze(a,b){return a.f.hasOwnProperty(b)}k.forEach=function(a,b){for(var c=this.b;c;)a.call(b,c.pc,c.cc,this),c=c.yb};k.get=function(a){a=this.f[a];if(a===this.a)return a.pc;a===this.b?(this.b=this.b.yb,this.b.kc=null):(a.yb.kc=a.kc,a.kc.yb=a.yb);a.yb=null;a.kc=this.a;this.a=this.a.yb=a;return a.pc};k.wc=function(){return this.g};
+k.N=function(){var a=Array(this.g),b=0,c;for(c=this.a;c;c=c.kc)a[b++]=c.cc;return a};k.zc=function(){var a=Array(this.g),b=0,c;for(c=this.a;c;c=c.kc)a[b++]=c.pc;return a};k.pop=function(){var a=this.b;delete this.f[a.cc];a.yb&&(a.yb.kc=null);this.b=a.yb;this.b||(this.a=null);--this.g;return a.pc};k.replace=function(a,b){this.get(a);this.f[a].pc=b};k.set=function(a,b){var c={cc:a,yb:null,kc:this.a,pc:b};this.a?this.a.yb=c:this.b=c;this.a=c;this.f[a]=c;++this.g};function $e(a,b,c,d){return void 0!==d?(d[0]=a,d[1]=b,d[2]=c,d):[a,b,c]}function af(a){var b=a[0],c=Array(b),d=1<<b-1,e,f;for(e=0;e<b;++e)f=48,a[1]&d&&(f+=1),a[2]&d&&(f+=2),c[e]=String.fromCharCode(f),d>>=1;return c.join("")};function bf(a){Ye.call(this);this.c=void 0!==a?a:2048}y(bf,Ye);function cf(a){return a.wc()>a.c}bf.prototype.Lc=function(a){for(var b,c;cf(this)&&!(b=this.b.pc,c=b.ma[0].toString(),c in a&&a[c].contains(b.ma));)Ta(this.pop())};function df(a,b){$a.call(this);this.ma=a;this.state=b;this.a=null;this.key=""}y(df,$a);function ef(a){a.b("change")}df.prototype.ib=function(){return w(this).toString()};df.prototype.i=function(){return this.ma};df.prototype.V=function(){return this.state};function ff(a,b,c){void 0===c&&(c=[0,0]);c[0]=a[0]+2*b;c[1]=a[1]+2*b;return c}function gf(a,b,c){void 0===c&&(c=[0,0]);c[0]=a[0]*b+.5|0;c[1]=a[1]*b+.5|0;return c}function hf(a,b){if(Array.isArray(a))return a;void 0===b?b=[a,a]:(b[0]=a,b[1]=a);return b};function jf(a){eb.call(this);this.f=yc(a.projection);this.l=kf(a.attributions);this.R=a.logo;this.za=void 0!==a.state?a.state:"ready";this.D=void 0!==a.wrapX?a.wrapX:!1}y(jf,eb);function kf(a){if("string"===typeof a)return[new je({html:a})];if(a instanceof je)return[a];if(Array.isArray(a)){for(var b=a.length,c=Array(b),d=0;d<b;d++){var e=a[d];c[d]="string"===typeof e?new je({html:e}):e}return c}return null}k=jf.prototype;k.ra=na;k.wa=function(){return this.l};k.ua=function(){return this.R};k.xa=function(){return this.f};
+k.V=function(){return this.za};k.sa=function(){this.u()};k.oa=function(a){this.l=kf(a);this.u()};function lf(a,b){a.za=b;a.u()};function mf(a){this.minZoom=void 0!==a.minZoom?a.minZoom:0;this.b=a.resolutions;this.maxZoom=this.b.length-1;this.g=void 0!==a.origin?a.origin:null;this.c=null;void 0!==a.origins&&(this.c=a.origins);var b=a.extent;void 0===b||this.g||this.c||(this.g=fc(b));this.i=null;void 0!==a.tileSizes&&(this.i=a.tileSizes);this.o=void 0!==a.tileSize?a.tileSize:this.i?null:256;this.s=void 0!==b?b:null;this.a=null;this.f=[0,0];void 0!==a.sizes?this.a=a.sizes.map(function(a){return new fe(Math.min(0,a[0]),Math.max(a[0]-
+1,-1),Math.min(0,a[1]),Math.max(a[1]-1,-1))},this):b&&nf(this,b)}var of=[0,0,0];k=mf.prototype;k.yg=function(a,b,c){a=pf(this,a,b);for(var d=a.ca,e=a.ea;d<=e;++d)for(var f=a.fa,g=a.ga;f<=g;++f)c([b,d,f])};function qf(a,b,c,d,e){e=a.Ea(b,e);for(b=b[0]-1;b>=a.minZoom;){if(c.call(null,b,pf(a,e,b,d)))return!0;--b}return!1}k.H=function(){return this.s};k.Ig=function(){return this.maxZoom};k.Jg=function(){return this.minZoom};k.Ia=function(a){return this.g?this.g:this.c[a]};k.$=function(a){return this.b[a]};
+k.Kh=function(){return this.b};function rf(a,b,c,d){return b[0]<a.maxZoom?(d=a.Ea(b,d),pf(a,d,b[0]+1,c)):null}function sf(a,b,c,d){tf(a,b[0],b[1],c,!1,of);var e=of[1],f=of[2];tf(a,b[2],b[3],c,!0,of);a=of[1];b=of[2];void 0!==d?(d.ca=e,d.ea=a,d.fa=f,d.ga=b):d=new fe(e,a,f,b);return d}function pf(a,b,c,d){c=a.$(c);return sf(a,b,c,d)}function uf(a,b){var c=a.Ia(b[0]),d=a.$(b[0]),e=hf(a.Ja(b[0]),a.f);return[c[0]+(b[1]+.5)*e[0]*d,c[1]+(b[2]+.5)*e[1]*d]}
+k.Ea=function(a,b){var c=this.Ia(a[0]),d=this.$(a[0]),e=hf(this.Ja(a[0]),this.f),f=c[0]+a[1]*e[0]*d,c=c[1]+a[2]*e[1]*d;return Wb(f,c,f+e[0]*d,c+e[1]*d,b)};k.Zd=function(a,b,c){return tf(this,a[0],a[1],b,!1,c)};function tf(a,b,c,d,e,f){var g=a.Lb(d),h=d/a.$(g),l=a.Ia(g);a=hf(a.Ja(g),a.f);b=h*Math.floor((b-l[0])/d+(e?.5:0))/a[0];c=h*Math.floor((c-l[1])/d+(e?0:.5))/a[1];e?(b=Math.ceil(b)-1,c=Math.ceil(c)-1):(b=Math.floor(b),c=Math.floor(c));return $e(g,b,c,f)}
+k.qd=function(a,b,c){b=this.$(b);return tf(this,a[0],a[1],b,!1,c)};k.Ja=function(a){return this.o?this.o:this.i[a]};k.Lb=function(a,b){var c=kb(this.b,a,b||0);return sa(c,this.minZoom,this.maxZoom)};function nf(a,b){for(var c=a.b.length,d=Array(c),e=a.minZoom;e<c;++e)d[e]=pf(a,b,e);a.a=d}function vf(a){var b=a.l;if(!b){var b=wf(a),c=xf(b,void 0,void 0),b=new mf({extent:b,origin:fc(b),resolutions:c,tileSize:void 0});a.l=b}return b}
+function yf(a){var b={};Ea(b,void 0!==a?a:{});void 0===b.extent&&(b.extent=yc("EPSG:3857").H());b.resolutions=xf(b.extent,b.maxZoom,b.tileSize);delete b.maxZoom;return new mf(b)}function xf(a,b,c){b=void 0!==b?b:42;var d=jc(a);a=ic(a);c=hf(void 0!==c?c:256);c=Math.max(a/c[0],d/c[1]);b+=1;d=Array(b);for(a=0;a<b;++a)d[a]=c/Math.pow(2,a);return d}function wf(a){a=yc(a);var b=a.H();b||(a=180*uc.degrees/a.$b(),b=Wb(-a,-a,a,a));return b};function zf(a){jf.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,state:a.state,wrapX:a.wrapX});this.ia=void 0!==a.opaque?a.opaque:!1;this.ta=void 0!==a.tilePixelRatio?a.tilePixelRatio:1;this.tileGrid=void 0!==a.tileGrid?a.tileGrid:null;this.a=new bf(a.cacheSize);this.o=[0,0];this.cc=""}y(zf,jf);k=zf.prototype;k.Ah=function(){return cf(this.a)};k.Lc=function(a,b){var c=this.pd(a);c&&c.Lc(b)};
+function Af(a,b,c,d,e){b=a.pd(b);if(!b)return!1;for(var f=!0,g,h,l=d.ca;l<=d.ea;++l)for(var m=d.fa;m<=d.ga;++m)g=a.Eb(c,l,m),h=!1,Ze(b,g)&&(g=b.get(g),(h=2===g.V())&&(h=!1!==e(g))),h||(f=!1);return f}k.Ud=function(){return 0};function Bf(a,b){a.cc!==b&&(a.cc=b,a.u())}k.Eb=function(a,b,c){return a+"/"+b+"/"+c};k.jf=function(){return this.ia};k.Na=function(){return this.tileGrid};k.eb=function(a){return this.tileGrid?this.tileGrid:vf(a)};k.pd=function(a){var b=this.f;return b&&!Oc(b,a)?null:this.a};
+k.bc=function(){return this.ta};k.$d=function(a,b,c){c=this.eb(c);b=this.bc(b);a=hf(c.Ja(a),this.o);return 1==b?a:gf(a,b,this.o)};function Cf(a,b,c){var d=void 0!==c?c:a.f;c=a.eb(d);if(a.D&&d.g){var e=b;b=e[0];a=uf(c,e);d=wf(d);Sb(d,a)?b=e:(e=ic(d),a[0]+=e*Math.ceil((d[0]-a[0])/e),b=c.qd(a,b))}e=b[0];d=b[1];a=b[2];if(c.minZoom>e||e>c.maxZoom)c=!1;else{var f=c.H();c=(c=f?pf(c,f,e):c.a?c.a[e]:null)?ge(c,d,a):!0}return c?b:null}k.sa=function(){this.a.clear();this.u()};k.Yf=na;
+function Df(a,b){Wa.call(this,a);this.tile=b}y(Df,Wa);function Ef(a){a=a?a:{};this.R=document.createElement("UL");this.v=document.createElement("LI");this.R.appendChild(this.v);this.v.style.display="none";this.f=void 0!==a.collapsed?a.collapsed:!0;this.o=void 0!==a.collapsible?a.collapsible:!0;this.o||(this.f=!1);var b=void 0!==a.className?a.className:"ol-attribution",c=void 0!==a.tipLabel?a.tipLabel:"Attributions",d=void 0!==a.collapseLabel?a.collapseLabel:"\u00bb";"string"===typeof d?(this.A=document.createElement("span"),this.A.textContent=d):this.A=
+d;d=void 0!==a.label?a.label:"i";"string"===typeof d?(this.C=document.createElement("span"),this.C.textContent=d):this.C=d;var e=this.o&&!this.f?this.A:this.C,d=document.createElement("button");d.setAttribute("type","button");d.title=c;d.appendChild(e);B(d,"click",this.am,this);c=document.createElement("div");c.className=b+" ol-unselectable ol-control"+(this.f&&this.o?" ol-collapsed":"")+(this.o?"":" ol-uncollapsible");c.appendChild(this.R);c.appendChild(d);Xe.call(this,{element:c,render:a.render?
+a.render:Ff,target:a.target});this.D=!0;this.j={};this.l={};this.T={}}y(Ef,Xe);
+function Ff(a){if(a=a.frameState){var b,c,d,e,f,g,h,l,m,n,p,q=a.layerStatesArray,r=Ea({},a.attributions),u={},x=a.viewState.projection;c=0;for(b=q.length;c<b;c++)if(g=q[c].layer.ha())if(n=w(g).toString(),m=g.l)for(d=0,e=m.length;d<e;d++)if(h=m[d],l=w(h).toString(),!(l in r)){if(f=a.usedTiles[n]){var v=g.eb(x);a:{p=h;var D=x;if(p.b){var A,z,F,N=void 0;for(N in f)if(N in p.b){F=f[N];var K;A=0;for(z=p.b[N].length;A<z;++A){K=p.b[N][A];if(ie(K,F)){p=!0;break a}var X=pf(v,wf(D),parseInt(N,10)),oa=X.ea-
+X.ca+1;if(F.ca<X.ca||F.ea>X.ea)if(ie(K,new fe(xa(F.ca,oa),xa(F.ea,oa),F.fa,F.ga))||F.ea-F.ca+1>oa&&ie(K,X)){p=!0;break a}}}p=!1}else p=!0}}else p=!1;p?(l in u&&delete u[l],r[l]=h):u[l]=h}b=[r,u];c=b[0];b=b[1];for(var H in this.j)H in c?(this.l[H]||(this.j[H].style.display="",this.l[H]=!0),delete c[H]):H in b?(this.l[H]&&(this.j[H].style.display="none",delete this.l[H]),delete b[H]):(Ue(this.j[H]),delete this.j[H],delete this.l[H]);for(H in c)d=document.createElement("LI"),d.innerHTML=c[H].a,this.R.appendChild(d),
+this.j[H]=d,this.l[H]=!0;for(H in b)d=document.createElement("LI"),d.innerHTML=b[H].a,d.style.display="none",this.R.appendChild(d),this.j[H]=d;H=!Ha(this.l)||!Ha(a.logos);this.D!=H&&(this.element.style.display=H?"":"none",this.D=H);H&&Ha(this.l)?this.element.classList.add("ol-logo-only"):this.element.classList.remove("ol-logo-only");var ya;a=a.logos;H=this.T;for(ya in H)ya in a||(Ue(H[ya]),delete H[ya]);for(var Ua in a)b=a[Ua],b instanceof HTMLElement&&(this.v.appendChild(b),H[Ua]=b),Ua in H||(ya=
+new Image,ya.src=Ua,""===b?c=ya:(c=document.createElement("a"),c.href=b,c.appendChild(ya)),this.v.appendChild(c),H[Ua]=c);this.v.style.display=Ha(a)?"none":""}else this.D&&(this.element.style.display="none",this.D=!1)}k=Ef.prototype;k.am=function(a){a.preventDefault();Gf(this)};function Gf(a){a.element.classList.toggle("ol-collapsed");a.f?Te(a.A,a.C):Te(a.C,a.A);a.f=!a.f}k.$l=function(){return this.o};
+k.cm=function(a){this.o!==a&&(this.o=a,this.element.classList.toggle("ol-uncollapsible"),!a&&this.f&&Gf(this))};k.bm=function(a){this.o&&this.f!==a&&Gf(this)};k.Zl=function(){return this.f};function Hf(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-rotate",c=void 0!==a.label?a.label:"\u21e7";this.f=null;"string"===typeof c?(this.f=document.createElement("span"),this.f.className="ol-compass",this.f.textContent=c):(this.f=c,this.f.classList.add("ol-compass"));var d=a.tipLabel?a.tipLabel:"Reset rotation",c=document.createElement("button");c.className=b+"-reset";c.setAttribute("type","button");c.title=d;c.appendChild(this.f);B(c,"click",Hf.prototype.A,this);d=document.createElement("div");
+d.className=b+" ol-unselectable ol-control";d.appendChild(c);b=a.render?a.render:If;this.o=a.resetNorth?a.resetNorth:void 0;Xe.call(this,{element:d,render:b,target:a.target});this.j=void 0!==a.duration?a.duration:250;this.l=void 0!==a.autoHide?a.autoHide:!0;this.v=void 0;this.l&&this.element.classList.add("ol-hidden")}y(Hf,Xe);
+Hf.prototype.A=function(a){a.preventDefault();if(void 0!==this.o)this.o();else{a=this.a;var b=a.aa();if(b){var c=b.La();void 0!==c&&(0<this.j&&(c%=2*Math.PI,c<-Math.PI&&(c+=2*Math.PI),c>Math.PI&&(c-=2*Math.PI),a.Wa(de({rotation:c,duration:this.j,easing:Zd}))),b.ie(0))}}};
+function If(a){if(a=a.frameState){a=a.viewState.rotation;if(a!=this.v){var b="rotate("+a+"rad)";if(this.l){var c=this.element.classList.contains("ol-hidden");c||0!==a?c&&0!==a&&this.element.classList.remove("ol-hidden"):this.element.classList.add("ol-hidden")}this.f.style.msTransform=b;this.f.style.webkitTransform=b;this.f.style.transform=b}this.v=a}};function Jf(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-zoom",c=void 0!==a.delta?a.delta:1,d=void 0!==a.zoomInLabel?a.zoomInLabel:"+",e=void 0!==a.zoomOutLabel?a.zoomOutLabel:"\u2212",f=void 0!==a.zoomInTipLabel?a.zoomInTipLabel:"Zoom in",g=void 0!==a.zoomOutTipLabel?a.zoomOutTipLabel:"Zoom out",h=document.createElement("button");h.className=b+"-in";h.setAttribute("type","button");h.title=f;h.appendChild("string"===typeof d?document.createTextNode(d):d);B(h,"click",Jf.prototype.l.bind(this,
+c));d=document.createElement("button");d.className=b+"-out";d.setAttribute("type","button");d.title=g;d.appendChild("string"===typeof e?document.createTextNode(e):e);B(d,"click",Jf.prototype.l.bind(this,-c));c=document.createElement("div");c.className=b+" ol-unselectable ol-control";c.appendChild(h);c.appendChild(d);Xe.call(this,{element:c,target:a.target});this.f=void 0!==a.duration?a.duration:250}y(Jf,Xe);
+Jf.prototype.l=function(a,b){b.preventDefault();var c=this.a,d=c.aa();if(d){var e=d.$();e&&(0<this.f&&c.Wa(ee({resolution:e,duration:this.f,easing:Zd})),c=d.constrainResolution(e,a),d.Ub(c))}};function Kf(a){a=a?a:{};var b=new le;(void 0!==a.zoom?a.zoom:1)&&b.push(new Jf(a.zoomOptions));(void 0!==a.rotate?a.rotate:1)&&b.push(new Hf(a.rotateOptions));(void 0!==a.attribution?a.attribution:1)&&b.push(new Ef(a.attributionOptions));return b};function Lf(a){a=a?a:{};this.f=void 0!==a.className?a.className:"ol-full-screen";var b=void 0!==a.label?a.label:"\u2922";this.o="string"===typeof b?document.createTextNode(b):b;b=void 0!==a.labelActive?a.labelActive:"\u00d7";this.j="string"===typeof b?document.createTextNode(b):b;var c=a.tipLabel?a.tipLabel:"Toggle full-screen",b=document.createElement("button");b.className=this.f+"-"+Mf();b.setAttribute("type","button");b.title=c;b.appendChild(this.o);B(b,"click",this.C,this);c=document.createElement("div");
+c.className=this.f+" ol-unselectable ol-control "+(Nf()?"":"ol-unsupported");c.appendChild(b);Xe.call(this,{element:c,target:a.target});this.A=void 0!==a.keys?a.keys:!1;this.l=a.source}y(Lf,Xe);
+Lf.prototype.C=function(a){a.preventDefault();Nf()&&(a=this.a)&&(Mf()?document.exitFullscreen?document.exitFullscreen():document.msExitFullscreen?document.msExitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.webkitExitFullscreen&&document.webkitExitFullscreen():(a=this.l?"string"===typeof this.l?document.getElementById(this.l):this.l:a.yc(),this.A?a.mozRequestFullScreenWithKeys?a.mozRequestFullScreenWithKeys():a.webkitRequestFullscreen?a.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT):
+Of(a):Of(a)))};Lf.prototype.v=function(){var a=this.element.firstElementChild,b=this.a;Mf()?(a.className=this.f+"-true",Te(this.j,this.o)):(a.className=this.f+"-false",Te(this.o,this.j));b&&b.Xc()};Lf.prototype.setMap=function(a){Xe.prototype.setMap.call(this,a);a&&this.s.push(B(pa.document,Pf(),this.v,this))};
+function Nf(){var a=document.body;return!!(a.webkitRequestFullscreen||a.mozRequestFullScreen&&document.mozFullScreenEnabled||a.msRequestFullscreen&&document.msFullscreenEnabled||a.requestFullscreen&&document.fullscreenEnabled)}function Mf(){return!!(document.webkitIsFullScreen||document.mozFullScreen||document.msFullscreenElement||document.fullscreenElement)}
+function Of(a){a.requestFullscreen?a.requestFullscreen():a.msRequestFullscreen?a.msRequestFullscreen():a.mozRequestFullScreen?a.mozRequestFullScreen():a.webkitRequestFullscreen&&a.webkitRequestFullscreen()}var Pf=function(){var a;return function(){if(!a){var b=document.body;b.webkitRequestFullscreen?a="webkitfullscreenchange":b.mozRequestFullScreen?a="mozfullscreenchange":b.msRequestFullscreen?a="MSFullscreenChange":b.requestFullscreen&&(a="fullscreenchange")}return a}}();function Qf(a){a=a?a:{};var b=document.createElement("DIV");b.className=void 0!==a.className?a.className:"ol-mouse-position";Xe.call(this,{element:b,render:a.render?a.render:Rf,target:a.target});B(this,gb("projection"),this.dm,this);a.coordinateFormat&&this.ei(a.coordinateFormat);a.projection&&this.ih(yc(a.projection));this.v=void 0!==a.undefinedHTML?a.undefinedHTML:"";this.j=b.innerHTML;this.o=this.l=this.f=null}y(Qf,Xe);
+function Rf(a){a=a.frameState;a?this.f!=a.viewState.projection&&(this.f=a.viewState.projection,this.l=null):this.f=null;Sf(this,this.o)}k=Qf.prototype;k.dm=function(){this.l=null};k.Cg=function(){return this.get("coordinateFormat")};k.hh=function(){return this.get("projection")};k.Xk=function(a){this.o=this.a.Td(a);Sf(this,this.o)};k.Yk=function(){Sf(this,null);this.o=null};
+k.setMap=function(a){Xe.prototype.setMap.call(this,a);a&&(a=a.a,this.s.push(B(a,"mousemove",this.Xk,this),B(a,"mouseout",this.Yk,this)))};k.ei=function(a){this.set("coordinateFormat",a)};k.ih=function(a){this.set("projection",a)};function Sf(a,b){var c=a.v;if(b&&a.f){if(!a.l){var d=a.hh();a.l=d?Bc(a.f,d):Qc}if(d=a.a.Ma(b))a.l(d,d),c=(c=a.Cg())?c(d):d.toString()}a.j&&c==a.j||(a.element.innerHTML=c,a.j=c)};function Tf(a,b){var c=a;b&&(c=ka(a,b));"function"!=ca(aa.setImmediate)||aa.Window&&aa.Window.prototype&&!Be("Edge")&&aa.Window.prototype.setImmediate==aa.setImmediate?(Uf||(Uf=Vf()),Uf(c)):aa.setImmediate(c)}var Uf;
+function Vf(){var a=aa.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!Be("Presto")&&(a=function(){var a=document.createElement("IFRAME");a.style.display="none";a.src="";document.documentElement.appendChild(a);var b=a.contentWindow,a=b.document;a.open();a.write("");a.close();var c="callImmediate"+Math.random(),d="file:"==b.location.protocol?"*":b.location.protocol+"//"+b.location.host,a=ka(function(a){if(("*"==d||a.origin==d)&&a.data==
+c)this.port1.onmessage()},this);b.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){b.postMessage(c,d)}}});if("undefined"!==typeof a&&!Be("Trident")&&!Be("MSIE")){var b=new a,c={},d=c;b.port1.onmessage=function(){if(void 0!==c.next){c=c.next;var a=c.rg;c.rg=null;a()}};return function(a){d.next={rg:a};d=d.next;b.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?function(a){var b=document.createElement("SCRIPT");
+b.onreadystatechange=function(){b.onreadystatechange=null;b.parentNode.removeChild(b);b=null;a();a=null};document.documentElement.appendChild(b)}:function(a){aa.setTimeout(a,0)}};function Wf(a,b,c){Wa.call(this,a);this.b=b;a=c?c:{};this.buttons=Xf(a);this.pressure=Yf(a,this.buttons);this.bubbles="bubbles"in a?a.bubbles:!1;this.cancelable="cancelable"in a?a.cancelable:!1;this.view="view"in a?a.view:null;this.detail="detail"in a?a.detail:null;this.screenX="screenX"in a?a.screenX:0;this.screenY="screenY"in a?a.screenY:0;this.clientX="clientX"in a?a.clientX:0;this.clientY="clientY"in a?a.clientY:0;this.button="button"in a?a.button:0;this.relatedTarget="relatedTarget"in a?a.relatedTarget:
+null;this.pointerId="pointerId"in a?a.pointerId:0;this.width="width"in a?a.width:0;this.height="height"in a?a.height:0;this.pointerType="pointerType"in a?a.pointerType:"";this.isPrimary="isPrimary"in a?a.isPrimary:!1;b.preventDefault&&(this.preventDefault=function(){b.preventDefault()})}y(Wf,Wa);function Xf(a){if(a.buttons||Zf)a=a.buttons;else switch(a.which){case 1:a=1;break;case 2:a=4;break;case 3:a=2;break;default:a=0}return a}
+function Yf(a,b){var c=0;a.pressure?c=a.pressure:c=b?.5:0;return c}var Zf=!1;try{Zf=1===(new MouseEvent("click",{buttons:1})).buttons}catch(a){};var $f=["experimental-webgl","webgl","webkit-3d","moz-webgl"];function ag(a,b){var c,d,e=$f.length;for(d=0;d<e;++d)try{if(c=a.getContext($f[d],b))return c}catch(f){}return null};var bg,cg="undefined"!==typeof navigator?navigator.userAgent.toLowerCase():"",dg=-1!==cg.indexOf("firefox"),eg=-1!==cg.indexOf("safari")&&-1===cg.indexOf("chrom"),fg=-1!==cg.indexOf("macintosh"),gg=pa.devicePixelRatio||1,hg=!1,ig=function(){if(!("HTMLCanvasElement"in pa))return!1;try{var a=Oe();return a?(a.setLineDash&&(hg=!0),!0):!1}catch(b){return!1}}(),jg="DeviceOrientationEvent"in pa,kg="geolocation"in pa.navigator,lg="ontouchstart"in pa,mg="PointerEvent"in pa,ng=!!pa.navigator.msPointerEnabled,
+og=!1,pg,qg=[];if("WebGLRenderingContext"in pa)try{var rg=ag(document.createElement("CANVAS"),{failIfMajorPerformanceCaveat:!0});rg&&(og=!0,pg=rg.getParameter(rg.MAX_TEXTURE_SIZE),qg=rg.getSupportedExtensions())}catch(a){}bg=og;ma=qg;la=pg;function sg(a,b){this.b=a;this.c=b};function tg(a){sg.call(this,a,{mousedown:this.rl,mousemove:this.sl,mouseup:this.vl,mouseover:this.ul,mouseout:this.tl});this.a=a.g;this.g=[]}y(tg,sg);function ug(a,b){for(var c=a.g,d=b.clientX,e=b.clientY,f=0,g=c.length,h;f<g&&(h=c[f]);f++){var l=Math.abs(e-h[1]);if(25>=Math.abs(d-h[0])&&25>=l)return!0}return!1}function vg(a){var b=wg(a,a),c=b.preventDefault;b.preventDefault=function(){a.preventDefault();c()};b.pointerId=1;b.isPrimary=!0;b.pointerType="mouse";return b}k=tg.prototype;
+k.rl=function(a){if(!ug(this,a)){if((1).toString()in this.a){var b=vg(a);xg(this.b,yg,b,a);delete this.a[(1).toString()]}b=vg(a);this.a[(1).toString()]=a;xg(this.b,zg,b,a)}};k.sl=function(a){if(!ug(this,a)){var b=vg(a);xg(this.b,Ag,b,a)}};k.vl=function(a){if(!ug(this,a)){var b=this.a[(1).toString()];b&&b.button===a.button&&(b=vg(a),xg(this.b,Bg,b,a),delete this.a[(1).toString()])}};k.ul=function(a){if(!ug(this,a)){var b=vg(a);Cg(this.b,b,a)}};
+k.tl=function(a){if(!ug(this,a)){var b=vg(a);Dg(this.b,b,a)}};function Eg(a){sg.call(this,a,{MSPointerDown:this.Al,MSPointerMove:this.Bl,MSPointerUp:this.El,MSPointerOut:this.Cl,MSPointerOver:this.Dl,MSPointerCancel:this.zl,MSGotPointerCapture:this.xl,MSLostPointerCapture:this.yl});this.a=a.g;this.g=["","unavailable","touch","pen","mouse"]}y(Eg,sg);function Fg(a,b){var c=b;ea(b.pointerType)&&(c=wg(b,b),c.pointerType=a.g[b.pointerType]);return c}k=Eg.prototype;k.Al=function(a){this.a[a.pointerId.toString()]=a;var b=Fg(this,a);xg(this.b,zg,b,a)};
+k.Bl=function(a){var b=Fg(this,a);xg(this.b,Ag,b,a)};k.El=function(a){var b=Fg(this,a);xg(this.b,Bg,b,a);delete this.a[a.pointerId.toString()]};k.Cl=function(a){var b=Fg(this,a);Dg(this.b,b,a)};k.Dl=function(a){var b=Fg(this,a);Cg(this.b,b,a)};k.zl=function(a){var b=Fg(this,a);xg(this.b,yg,b,a);delete this.a[a.pointerId.toString()]};k.yl=function(a){this.b.b(new Wf("lostpointercapture",a,a))};k.xl=function(a){this.b.b(new Wf("gotpointercapture",a,a))};function Gg(a){sg.call(this,a,{pointerdown:this.lo,pointermove:this.mo,pointerup:this.po,pointerout:this.no,pointerover:this.oo,pointercancel:this.ko,gotpointercapture:this.Gk,lostpointercapture:this.ql})}y(Gg,sg);k=Gg.prototype;k.lo=function(a){Hg(this.b,a)};k.mo=function(a){Hg(this.b,a)};k.po=function(a){Hg(this.b,a)};k.no=function(a){Hg(this.b,a)};k.oo=function(a){Hg(this.b,a)};k.ko=function(a){Hg(this.b,a)};k.ql=function(a){Hg(this.b,a)};k.Gk=function(a){Hg(this.b,a)};function Ig(a,b){sg.call(this,a,{touchstart:this.sp,touchmove:this.rp,touchend:this.qp,touchcancel:this.pp});this.a=a.g;this.l=b;this.g=void 0;this.i=0;this.f=void 0}y(Ig,sg);k=Ig.prototype;k.ci=function(){this.i=0;this.f=void 0};
+function Jg(a,b,c){b=wg(b,c);b.pointerId=c.identifier+2;b.bubbles=!0;b.cancelable=!0;b.detail=a.i;b.button=0;b.buttons=1;b.width=c.webkitRadiusX||c.radiusX||0;b.height=c.webkitRadiusY||c.radiusY||0;b.pressure=c.webkitForce||c.force||.5;b.isPrimary=a.g===c.identifier;b.pointerType="touch";b.clientX=c.clientX;b.clientY=c.clientY;b.screenX=c.screenX;b.screenY=c.screenY;return b}
+function Kg(a,b,c){function d(){b.preventDefault()}var e=Array.prototype.slice.call(b.changedTouches),f=e.length,g,h;for(g=0;g<f;++g)h=Jg(a,b,e[g]),h.preventDefault=d,c.call(a,b,h)}
+k.sp=function(a){var b=a.touches,c=Object.keys(this.a),d=c.length;if(d>=b.length){var e=[],f,g,h;for(f=0;f<d;++f){g=c[f];h=this.a[g];var l;if(!(l=1==g))a:{l=b.length;for(var m,n=0;n<l;n++)if(m=b[n],m.identifier===g-2){l=!0;break a}l=!1}l||e.push(h.out)}for(f=0;f<e.length;++f)this.Ue(a,e[f])}b=a.changedTouches[0];c=Object.keys(this.a).length;if(0===c||1===c&&(1).toString()in this.a)this.g=b.identifier,void 0!==this.f&&pa.clearTimeout(this.f);Lg(this,a);this.i++;Kg(this,a,this.fo)};
+k.fo=function(a,b){this.a[b.pointerId]={target:b.target,out:b,Lh:b.target};var c=this.b;b.bubbles=!0;xg(c,Mg,b,a);c=this.b;b.bubbles=!1;xg(c,Ng,b,a);xg(this.b,zg,b,a)};k.rp=function(a){a.preventDefault();Kg(this,a,this.wl)};k.wl=function(a,b){var c=this.a[b.pointerId];if(c){var d=c.out,e=c.Lh;xg(this.b,Ag,b,a);d&&e!==b.target&&(d.relatedTarget=b.target,b.relatedTarget=e,d.target=e,b.target?(Dg(this.b,d,a),Cg(this.b,b,a)):(b.target=e,b.relatedTarget=null,this.Ue(a,b)));c.out=b;c.Lh=b.target}};
+k.qp=function(a){Lg(this,a);Kg(this,a,this.tp)};k.tp=function(a,b){xg(this.b,Bg,b,a);this.b.out(b,a);var c=this.b;b.bubbles=!1;xg(c,Og,b,a);delete this.a[b.pointerId];b.isPrimary&&(this.g=void 0,this.f=pa.setTimeout(this.ci.bind(this),200))};k.pp=function(a){Kg(this,a,this.Ue)};k.Ue=function(a,b){xg(this.b,yg,b,a);this.b.out(b,a);var c=this.b;b.bubbles=!1;xg(c,Og,b,a);delete this.a[b.pointerId];b.isPrimary&&(this.g=void 0,this.f=pa.setTimeout(this.ci.bind(this),200))};
+function Lg(a,b){var c=a.l.g,d=b.changedTouches[0];if(a.g===d.identifier){var e=[d.clientX,d.clientY];c.push(e);pa.setTimeout(function(){nb(c,e)},2500)}};function Pg(a){$a.call(this);this.i=a;this.g={};this.c={};this.a=[];mg?Qg(this,new Gg(this)):ng?Qg(this,new Eg(this)):(a=new tg(this),Qg(this,a),lg&&Qg(this,new Ig(this,a)));a=this.a.length;for(var b,c=0;c<a;c++)b=this.a[c],Rg(this,Object.keys(b.c))}y(Pg,$a);function Qg(a,b){var c=Object.keys(b.c);c&&(c.forEach(function(a){var c=b.c[a];c&&(this.c[a]=c.bind(b))},a),a.a.push(b))}Pg.prototype.f=function(a){var b=this.c[a.type];b&&b(a)};
+function Rg(a,b){b.forEach(function(a){B(this.i,a,this.f,this)},a)}function Sg(a,b){b.forEach(function(a){Qa(this.i,a,this.f,this)},a)}function wg(a,b){for(var c={},d,e=0,f=Tg.length;e<f;e++)d=Tg[e][0],c[d]=a[d]||b[d]||Tg[e][1];return c}Pg.prototype.out=function(a,b){a.bubbles=!0;xg(this,Ug,a,b)};function Dg(a,b,c){a.out(b,c);var d=b.target,e=b.relatedTarget;d&&e&&d.contains(e)||(b.bubbles=!1,xg(a,Og,b,c))}
+function Cg(a,b,c){b.bubbles=!0;xg(a,Mg,b,c);var d=b.target,e=b.relatedTarget;d&&e&&d.contains(e)||(b.bubbles=!1,xg(a,Ng,b,c))}function xg(a,b,c,d){a.b(new Wf(b,d,c))}function Hg(a,b){a.b(new Wf(b.type,b,b))}Pg.prototype.ka=function(){for(var a=this.a.length,b,c=0;c<a;c++)b=this.a[c],Sg(this,Object.keys(b.c));$a.prototype.ka.call(this)};
+var Ag="pointermove",zg="pointerdown",Bg="pointerup",Mg="pointerover",Ug="pointerout",Ng="pointerenter",Og="pointerleave",yg="pointercancel",Tg=[["bubbles",!1],["cancelable",!1],["view",null],["detail",null],["screenX",0],["screenY",0],["clientX",0],["clientY",0],["ctrlKey",!1],["altKey",!1],["shiftKey",!1],["metaKey",!1],["button",0],["relatedTarget",null],["buttons",0],["pointerId",0],["width",0],["height",0],["pressure",0],["tiltX",0],["tiltY",0],["pointerType",""],["hwTimestamp",0],["isPrimary",
+!1],["type",""],["target",null],["currentTarget",null],["which",0]];function Vg(a,b,c,d,e){We.call(this,a,b,e);this.originalEvent=c;this.pixel=b.Td(c);this.coordinate=b.Ma(this.pixel);this.dragging=void 0!==d?d:!1}y(Vg,We);Vg.prototype.preventDefault=function(){We.prototype.preventDefault.call(this);this.originalEvent.preventDefault()};Vg.prototype.stopPropagation=function(){We.prototype.stopPropagation.call(this);this.originalEvent.stopPropagation()};function Wg(a,b,c,d,e){Vg.call(this,a,b,c.b,d,e);this.b=c}y(Wg,Vg);
+function Xg(a){$a.call(this);this.f=a;this.l=0;this.o=!1;this.c=[];this.g=null;a=this.f.a;this.U=0;this.v={};this.i=new Pg(a);this.a=null;this.j=B(this.i,zg,this.$k,this);this.s=B(this.i,Ag,this.No,this)}y(Xg,$a);function Yg(a,b){var c;c=new Wg(Zg,a.f,b);a.b(c);0!==a.l?(pa.clearTimeout(a.l),a.l=0,c=new Wg($g,a.f,b),a.b(c)):a.l=pa.setTimeout(function(){this.l=0;var a=new Wg(ah,this.f,b);this.b(a)}.bind(a),250)}
+function bh(a,b){b.type==ch||b.type==dh?delete a.v[b.pointerId]:b.type==eh&&(a.v[b.pointerId]=!0);a.U=Object.keys(a.v).length}k=Xg.prototype;k.Qg=function(a){bh(this,a);var b=new Wg(ch,this.f,a);this.b(b);!this.o&&0===a.button&&Yg(this,this.g);0===this.U&&(this.c.forEach(Ka),this.c.length=0,this.o=!1,this.g=null,Ta(this.a),this.a=null)};
+k.$k=function(a){bh(this,a);var b=new Wg(eh,this.f,a);this.b(b);this.g=a;0===this.c.length&&(this.a=new Pg(document),this.c.push(B(this.a,fh,this.Sl,this),B(this.a,ch,this.Qg,this),B(this.i,dh,this.Qg,this)))};k.Sl=function(a){if(a.clientX!=this.g.clientX||a.clientY!=this.g.clientY){this.o=!0;var b=new Wg(gh,this.f,a,this.o);this.b(b)}a.preventDefault()};k.No=function(a){this.b(new Wg(a.type,this.f,a,!(!this.g||a.clientX==this.g.clientX&&a.clientY==this.g.clientY)))};
+k.ka=function(){this.s&&(Ka(this.s),this.s=null);this.j&&(Ka(this.j),this.j=null);this.c.forEach(Ka);this.c.length=0;this.a&&(Ta(this.a),this.a=null);this.i&&(Ta(this.i),this.i=null);$a.prototype.ka.call(this)};var ah="singleclick",Zg="click",$g="dblclick",gh="pointerdrag",fh="pointermove",eh="pointerdown",ch="pointerup",dh="pointercancel",hh={Mp:ah,Bp:Zg,Cp:$g,Fp:gh,Ip:fh,Ep:eh,Lp:ch,Kp:"pointerover",Jp:"pointerout",Gp:"pointerenter",Hp:"pointerleave",Dp:dh};function ih(a){eb.call(this);var b=Ea({},a);b.opacity=void 0!==a.opacity?a.opacity:1;b.visible=void 0!==a.visible?a.visible:!0;b.zIndex=void 0!==a.zIndex?a.zIndex:0;b.maxResolution=void 0!==a.maxResolution?a.maxResolution:Infinity;b.minResolution=void 0!==a.minResolution?a.minResolution:0;this.G(b)}y(ih,eb);
+function jh(a){var b=a.Pb(),c=a.kf(),d=a.xb(),e=a.H(),f=a.Qb(),g=a.Nb(),h=a.Ob();return{layer:a,opacity:sa(b,0,1),R:c,visible:d,Qc:!0,extent:e,zIndex:f,maxResolution:g,minResolution:Math.max(h,0)}}k=ih.prototype;k.H=function(){return this.get("extent")};k.Nb=function(){return this.get("maxResolution")};k.Ob=function(){return this.get("minResolution")};k.Pb=function(){return this.get("opacity")};k.xb=function(){return this.get("visible")};k.Qb=function(){return this.get("zIndex")};
+k.fc=function(a){this.set("extent",a)};k.nc=function(a){this.set("maxResolution",a)};k.oc=function(a){this.set("minResolution",a)};k.gc=function(a){this.set("opacity",a)};k.hc=function(a){this.set("visible",a)};k.ic=function(a){this.set("zIndex",a)};function kh(){};function lh(a,b,c,d,e,f){Wa.call(this,a,b);this.vectorContext=c;this.frameState=d;this.context=e;this.glContext=f}y(lh,Wa);function mh(a){var b=Ea({},a);delete b.source;ih.call(this,b);this.v=this.j=this.o=null;a.map&&this.setMap(a.map);B(this,gb("source"),this.fl,this);this.Fc(a.source?a.source:null)}y(mh,ih);function nh(a,b){return a.visible&&b>=a.minResolution&&b<a.maxResolution}k=mh.prototype;k.hf=function(a){a=a?a:[];a.push(jh(this));return a};k.ha=function(){return this.get("source")||null};k.kf=function(){var a=this.ha();return a?a.V():"undefined"};k.Lm=function(){this.u()};
+k.fl=function(){this.v&&(Ka(this.v),this.v=null);var a=this.ha();a&&(this.v=B(a,"change",this.Lm,this));this.u()};k.setMap=function(a){this.o&&(Ka(this.o),this.o=null);a||this.u();this.j&&(Ka(this.j),this.j=null);a&&(this.o=B(a,"precompose",function(a){var c=jh(this);c.Qc=!1;c.zIndex=Infinity;a.frameState.layerStatesArray.push(c);a.frameState.layerStates[w(this)]=c},this),this.j=B(this,"change",a.render,a),this.u())};k.Fc=function(a){this.set("source",a)};function oh(a,b,c,d,e){$a.call(this);this.l=e;this.extent=a;this.f=c;this.resolution=b;this.state=d}y(oh,$a);function ph(a){a.b("change")}oh.prototype.H=function(){return this.extent};oh.prototype.$=function(){return this.resolution};oh.prototype.V=function(){return this.state};function qh(a,b,c,d,e,f,g,h){ad(a);0===b&&0===c||dd(a,b,c);1==d&&1==e||ed(a,d,e);0!==f&&fd(a,f);0===g&&0===h||dd(a,g,h);return a}function rh(a,b){return a[0]==b[0]&&a[1]==b[1]&&a[4]==b[4]&&a[5]==b[5]&&a[12]==b[12]&&a[13]==b[13]}function sh(a,b,c){var d=a[1],e=a[5],f=a[13],g=b[0];b=b[1];c[0]=a[0]*g+a[4]*b+a[12];c[1]=d*g+e*b+f;return c};function th(a){bb.call(this);this.a=a}y(th,bb);k=th.prototype;k.ra=na;k.Cc=function(a,b,c,d){a=a.slice();sh(b.pixelToCoordinateMatrix,a,a);if(this.ra(a,b,qc,this))return c.call(d,this.a)};k.le=rc;k.Qd=function(a,b,c){return function(d,e){return Af(a,b,d,e,function(a){c[d]||(c[d]={});c[d][a.ma.toString()]=a})}};k.Om=function(a){2===a.target.V()&&uh(this)};function vh(a,b){var c=b.V();2!=c&&3!=c&&B(b,"change",a.Om,a);0==c&&(b.load(),c=b.V());return 2==c}
+function uh(a){var b=a.a;b.xb()&&"ready"==b.kf()&&a.u()}function wh(a,b){b.Ah()&&a.postRenderFunctions.push(function(a,b,e){b=w(a).toString();a.Lc(e.viewState.projection,e.usedTiles[b])}.bind(null,b))}function xh(a,b){if(b){var c,d,e;d=0;for(e=b.length;d<e;++d)c=b[d],a[w(c).toString()]=c}}function yh(a,b){var c=b.R;void 0!==c&&("string"===typeof c?a.logos[c]="":fa(c)&&(a.logos[c.src]=c.href))}
+function zh(a,b,c,d){b=w(b).toString();c=c.toString();b in a?c in a[b]?(a=a[b][c],d.ca<a.ca&&(a.ca=d.ca),d.ea>a.ea&&(a.ea=d.ea),d.fa<a.fa&&(a.fa=d.fa),d.ga>a.ga&&(a.ga=d.ga)):a[b][c]=d:(a[b]={},a[b][c]=d)}function Ah(a,b,c){return[b*(Math.round(a[0]/b)+c[0]%2/2),b*(Math.round(a[1]/b)+c[1]%2/2)]}
+function Bh(a,b,c,d,e,f,g,h,l,m){var n=w(b).toString();n in a.wantedTiles||(a.wantedTiles[n]={});var p=a.wantedTiles[n];a=a.tileQueue;var q=c.minZoom,r,u,x,v,D,A;for(A=g;A>=q;--A)for(u=pf(c,f,A,u),x=c.$(A),v=u.ca;v<=u.ea;++v)for(D=u.fa;D<=u.ga;++D)g-A<=h?(r=b.ac(A,v,D,d,e),0==r.V()&&(p[r.ma.toString()]=!0,r.ib()in a.g||a.f([r,n,uf(c,r.ma),x])),void 0!==l&&l.call(m,r)):b.Yf(A,v,D,e)};function Ch(a){this.v=a.opacity;this.U=a.rotateWithView;this.j=a.rotation;this.i=a.scale;this.C=a.snapToPixel}k=Ch.prototype;k.qe=function(){return this.v};k.Xd=function(){return this.U};k.re=function(){return this.j};k.se=function(){return this.i};k.Yd=function(){return this.C};k.te=function(a){this.v=a};k.ue=function(a){this.j=a};k.ve=function(a){this.i=a};function Dh(a){a=a||{};this.c=void 0!==a.anchor?a.anchor:[.5,.5];this.f=null;this.a=void 0!==a.anchorOrigin?a.anchorOrigin:"top-left";this.o=void 0!==a.anchorXUnits?a.anchorXUnits:"fraction";this.s=void 0!==a.anchorYUnits?a.anchorYUnits:"fraction";var b=void 0!==a.crossOrigin?a.crossOrigin:null,c=void 0!==a.img?a.img:null,d=void 0!==a.imgSize?a.imgSize:null,e=a.src;void 0!==e&&0!==e.length||!c||(e=c.src||w(c).toString());var f=void 0!==a.src?0:2,g=void 0!==a.color?te(a.color):null,h=Eh.Zb(),l=h.get(e,
+b,g);l||(l=new Fh(c,e,d,b,f,g),h.set(e,b,g,l));this.b=l;this.D=void 0!==a.offset?a.offset:[0,0];this.g=void 0!==a.offsetOrigin?a.offsetOrigin:"top-left";this.l=null;this.A=void 0!==a.size?a.size:null;Ch.call(this,{opacity:void 0!==a.opacity?a.opacity:1,rotation:void 0!==a.rotation?a.rotation:0,scale:void 0!==a.scale?a.scale:1,snapToPixel:void 0!==a.snapToPixel?a.snapToPixel:!0,rotateWithView:void 0!==a.rotateWithView?a.rotateWithView:!1})}y(Dh,Ch);k=Dh.prototype;
+k.Yb=function(){if(this.f)return this.f;var a=this.c,b=this.Fb();if("fraction"==this.o||"fraction"==this.s){if(!b)return null;a=this.c.slice();"fraction"==this.o&&(a[0]*=b[0]);"fraction"==this.s&&(a[1]*=b[1])}if("top-left"!=this.a){if(!b)return null;a===this.c&&(a=this.c.slice());if("top-right"==this.a||"bottom-right"==this.a)a[0]=-a[0]+b[0];if("bottom-left"==this.a||"bottom-right"==this.a)a[1]=-a[1]+b[1]}return this.f=a};k.jc=function(){var a=this.b;return a.c?a.c:a.a};k.ld=function(){return this.b.g};
+k.td=function(){return this.b.f};k.pe=function(){var a=this.b;if(!a.o)if(a.s){var b=a.g[0],c=a.g[1],d=Oe(b,c);d.fillRect(0,0,b,c);a.o=d.canvas}else a.o=a.a;return a.o};k.Ia=function(){if(this.l)return this.l;var a=this.D;if("top-left"!=this.g){var b=this.Fb(),c=this.b.g;if(!b||!c)return null;a=a.slice();if("top-right"==this.g||"bottom-right"==this.g)a[0]=c[0]-b[0]-a[0];if("bottom-left"==this.g||"bottom-right"==this.g)a[1]=c[1]-b[1]-a[1]}return this.l=a};k.En=function(){return this.b.j};
+k.Fb=function(){return this.A?this.A:this.b.g};k.pf=function(a,b){return B(this.b,"change",a,b)};k.load=function(){this.b.load()};k.Xf=function(a,b){Qa(this.b,"change",a,b)};function Fh(a,b,c,d,e,f){$a.call(this);this.o=null;this.a=a?a:new Image;null!==d&&(this.a.crossOrigin=d);this.c=f?document.createElement("CANVAS"):null;this.l=f;this.i=null;this.f=e;this.g=c;this.j=b;this.s=!1;2==this.f&&Gh(this)}y(Fh,$a);
+function Gh(a){var b=Oe(1,1);try{b.drawImage(a.a,0,0),b.getImageData(0,0,1,1)}catch(c){a.s=!0}}Fh.prototype.v=function(){this.f=3;this.i.forEach(Ka);this.i=null;this.b("change")};
+Fh.prototype.U=function(){this.f=2;this.g&&(this.a.width=this.g[0],this.a.height=this.g[1]);this.g=[this.a.width,this.a.height];this.i.forEach(Ka);this.i=null;Gh(this);if(!this.s&&null!==this.l){this.c.width=this.a.width;this.c.height=this.a.height;var a=this.c.getContext("2d");a.drawImage(this.a,0,0);for(var b=a.getImageData(0,0,this.a.width,this.a.height),c=b.data,d=this.l[0]/255,e=this.l[1]/255,f=this.l[2]/255,g=0,h=c.length;g<h;g+=4)c[g]*=d,c[g+1]*=e,c[g+2]*=f;a.putImageData(b,0,0)}this.b("change")};
+Fh.prototype.load=function(){if(0==this.f){this.f=1;this.i=[Pa(this.a,"error",this.v,this),Pa(this.a,"load",this.U,this)];try{this.a.src=this.j}catch(a){this.v()}}};function Eh(){this.b={};this.a=0}ba(Eh);Eh.prototype.clear=function(){this.b={};this.a=0};Eh.prototype.get=function(a,b,c){a=b+":"+a+":"+(c?ve(c):"null");return a in this.b?this.b[a]:null};Eh.prototype.set=function(a,b,c,d){this.b[b+":"+a+":"+(c?ve(c):"null")]=d;++this.a};function Hh(a,b){this.i=b;this.g={};this.s={}}y(Hh,Sa);function Ih(a){var b=a.viewState,c=a.coordinateToPixelMatrix;qh(c,a.size[0]/2,a.size[1]/2,1/b.resolution,-1/b.resolution,-b.rotation,-b.center[0],-b.center[1]);cd(c,a.pixelToCoordinateMatrix)}k=Hh.prototype;k.ka=function(){for(var a in this.g)Ta(this.g[a])};function Jh(){var a=Eh.Zb();if(32<a.a){var b=0,c,d;for(c in a.b)d=a.b[c],0!==(b++&3)||ab(d)||(delete a.b[c],--a.a)}}
+k.ra=function(a,b,c,d,e,f){function g(a,e){var f=w(a).toString(),g=b.layerStates[w(e)].Qc;if(!(f in b.skippedFeatureUids)||g)return c.call(d,a,g?e:null)}var h,l=b.viewState,m=l.resolution,n=l.projection,l=a;if(n.a){var n=n.H(),p=ic(n),q=a[0];if(q<n[0]||q>n[2])l=[q+p*Math.ceil((n[0]-q)/p),a[1]]}n=b.layerStatesArray;for(p=n.length-1;0<=p;--p){var r=n[p],q=r.layer;if(nh(r,m)&&e.call(f,q)&&(r=Kh(this,q),q.ha()&&(h=r.ra(q.ha().D?l:a,b,g,d)),h))return h}};
+k.rh=function(a,b,c,d,e,f){var g,h=b.viewState.resolution,l=b.layerStatesArray,m;for(m=l.length-1;0<=m;--m){g=l[m];var n=g.layer;if(nh(g,h)&&e.call(f,n)&&(g=Kh(this,n).Cc(a,b,c,d)))return g}};k.sh=function(a,b,c,d){return void 0!==this.ra(a,b,qc,this,c,d)};function Kh(a,b){var c=w(b).toString();if(c in a.g)return a.g[c];var d=a.Xe(b);a.g[c]=d;a.s[c]=B(d,"change",a.Rk,a);return d}k.Rk=function(){this.i.render()};k.Ce=na;
+k.To=function(a,b){for(var c in this.g)if(!(b&&c in b.layerStates)){var d=c,e=this.g[d];delete this.g[d];Ka(this.s[d]);delete this.s[d];Ta(e)}};function Lh(a,b){for(var c in a.g)if(!(c in b.layerStates)){b.postRenderFunctions.push(a.To.bind(a));break}}function rb(a,b){return a.zIndex-b.zIndex};function Mh(a,b){this.j=a;this.l=b;this.b=[];this.a=[];this.g={}}Mh.prototype.clear=function(){this.b.length=0;this.a.length=0;Fa(this.g)};function Nh(a){var b=a.b,c=a.a,d=b[0];1==b.length?(b.length=0,c.length=0):(b[0]=b.pop(),c[0]=c.pop(),Oh(a,0));b=a.l(d);delete a.g[b];return d}Mh.prototype.f=function(a){var b=this.j(a);return Infinity!=b?(this.b.push(a),this.a.push(b),this.g[this.l(a)]=!0,Ph(this,0,this.b.length-1),!0):!1};Mh.prototype.wc=function(){return this.b.length};
+Mh.prototype.Ya=function(){return 0===this.b.length};function Oh(a,b){for(var c=a.b,d=a.a,e=c.length,f=c[b],g=d[b],h=b;b<e>>1;){var l=2*b+1,m=2*b+2,l=m<e&&d[m]<d[l]?m:l;c[b]=c[l];d[b]=d[l];b=l}c[b]=f;d[b]=g;Ph(a,h,b)}function Ph(a,b,c){var d=a.b;a=a.a;for(var e=d[c],f=a[c];c>b;){var g=c-1>>1;if(a[g]>f)d[c]=d[g],a[c]=a[g],c=g;else break}d[c]=e;a[c]=f}
+function Qh(a){var b=a.j,c=a.b,d=a.a,e=0,f=c.length,g,h,l;for(h=0;h<f;++h)g=c[h],l=b(g),Infinity==l?delete a.g[a.l(g)]:(d[e]=l,c[e++]=g);c.length=e;d.length=e;for(b=(a.b.length>>1)-1;0<=b;b--)Oh(a,b)};function Rh(a,b){Mh.call(this,function(b){return a.apply(null,b)},function(a){return a[0].ib()});this.s=b;this.i=0;this.c={}}y(Rh,Mh);Rh.prototype.f=function(a){var b=Mh.prototype.f.call(this,a);b&&B(a[0],"change",this.o,this);return b};Rh.prototype.o=function(a){a=a.target;var b=a.V();if(2===b||3===b||4===b||5===b)Qa(a,"change",this.o,this),a=a.ib(),a in this.c&&(delete this.c[a],--this.i),this.s()};
+function Sh(a,b,c){for(var d=0,e,f;a.i<b&&d<c&&0<a.wc();)e=Nh(a)[0],f=e.ib(),0!==e.V()||f in a.c||(a.c[f]=!0,++a.i,++d,e.load())};function Th(a,b,c){this.f=a;this.g=b;this.i=c;this.b=[];this.a=this.c=0}function Uh(a,b){var c=a.f,d=a.a,e=a.g-d,f=Math.log(a.g/a.a)/a.f;return ce({source:b,duration:f,easing:function(a){return d*(Math.exp(c*a*f)-1)/e}})};function Vh(a){eb.call(this);this.v=null;this.i(!0);this.handleEvent=a.handleEvent}y(Vh,eb);Vh.prototype.f=function(){return this.get("active")};Vh.prototype.l=function(){return this.v};Vh.prototype.i=function(a){this.set("active",a)};Vh.prototype.setMap=function(a){this.v=a};function Wh(a,b,c,d,e){if(void 0!==c){var f=b.La(),g=b.ab();void 0!==f&&g&&e&&0<e&&(a.Wa(de({rotation:f,duration:e,easing:Zd})),d&&a.Wa(ce({source:g,duration:e,easing:Zd})));b.rotate(c,d)}}
+function Xh(a,b,c,d,e){var f=b.$();c=b.constrainResolution(f,c,0);Yh(a,b,c,d,e)}function Yh(a,b,c,d,e){if(c){var f=b.$(),g=b.ab();void 0!==f&&g&&c!==f&&e&&0<e&&(a.Wa(ee({resolution:f,duration:e,easing:Zd})),d&&a.Wa(ce({source:g,duration:e,easing:Zd})));if(d){var h;a=b.ab();e=b.$();void 0!==a&&void 0!==e&&(h=[d[0]-c*(d[0]-a[0])/e,d[1]-c*(d[1]-a[1])/e]);b.mb(h)}b.Ub(c)}};function Zh(a){a=a?a:{};this.a=a.delta?a.delta:1;Vh.call(this,{handleEvent:$h});this.c=void 0!==a.duration?a.duration:250}y(Zh,Vh);function $h(a){var b=!1,c=a.originalEvent;if(a.type==$g){var b=a.map,d=a.coordinate,c=c.shiftKey?-this.a:this.a,e=b.aa();Xh(b,e,c,d,this.c);a.preventDefault();b=!0}return!b};function ai(a){a=a.originalEvent;return a.altKey&&!(a.metaKey||a.ctrlKey)&&a.shiftKey}function bi(a){a=a.originalEvent;return 0==a.button&&!(He&&fg&&a.ctrlKey)}function ci(a){return"pointermove"==a.type}function di(a){return a.type==ah}function ei(a){a=a.originalEvent;return!a.altKey&&!(a.metaKey||a.ctrlKey)&&!a.shiftKey}function fi(a){a=a.originalEvent;return!a.altKey&&!(a.metaKey||a.ctrlKey)&&a.shiftKey}
+function gi(a){a=a.originalEvent.target.tagName;return"INPUT"!==a&&"SELECT"!==a&&"TEXTAREA"!==a}function hi(a){return"mouse"==a.b.pointerType}function ii(a){a=a.b;return a.isPrimary&&0===a.button};function ji(a){a=a?a:{};Vh.call(this,{handleEvent:a.handleEvent?a.handleEvent:ki});this.Oe=a.handleDownEvent?a.handleDownEvent:rc;this.Pe=a.handleDragEvent?a.handleDragEvent:na;this.Mi=a.handleMoveEvent?a.handleMoveEvent:na;this.tj=a.handleUpEvent?a.handleUpEvent:rc;this.C=!1;this.ia={};this.o=[]}y(ji,Vh);function li(a){for(var b=a.length,c=0,d=0,e=0;e<b;e++)c+=a[e].clientX,d+=a[e].clientY;return[c/b,d/b]}
+function ki(a){if(!(a instanceof Wg))return!0;var b=!1,c=a.type;if(c===eh||c===gh||c===ch)c=a.b,a.type==ch?delete this.ia[c.pointerId]:a.type==eh?this.ia[c.pointerId]=c:c.pointerId in this.ia&&(this.ia[c.pointerId]=c),this.o=Ga(this.ia);this.C&&(a.type==gh?this.Pe(a):a.type==ch&&(this.C=this.tj(a)));a.type==eh?(this.C=a=this.Oe(a),b=this.Gc(a)):a.type==fh&&this.Mi(a);return!b}ji.prototype.Gc=function(a){return a};function mi(a){ji.call(this,{handleDownEvent:ni,handleDragEvent:oi,handleUpEvent:pi});a=a?a:{};this.a=a.kinetic;this.c=this.j=null;this.A=a.condition?a.condition:ei;this.s=!1}y(mi,ji);function oi(a){var b=li(this.o);this.a&&this.a.b.push(b[0],b[1],Date.now());if(this.c){var c=this.c[0]-b[0],d=b[1]-this.c[1];a=a.map;var e=a.aa(),f=e.V(),d=c=[c,d],g=f.resolution;d[0]*=g;d[1]*=g;Gb(c,f.rotation);Bb(c,f.center);c=e.Pd(c);a.render();e.mb(c)}this.c=b}
+function pi(a){a=a.map;var b=a.aa();if(0===this.o.length){var c;if(c=!this.s&&this.a)if(c=this.a,6>c.b.length)c=!1;else{var d=Date.now()-c.i,e=c.b.length-3;if(c.b[e+2]<d)c=!1;else{for(var f=e-3;0<f&&c.b[f+2]>d;)f-=3;var d=c.b[e+2]-c.b[f+2],g=c.b[e]-c.b[f],e=c.b[e+1]-c.b[f+1];c.c=Math.atan2(e,g);c.a=Math.sqrt(g*g+e*e)/d;c=c.a>c.g}}c&&(c=this.a,c=(c.g-c.a)/c.f,e=this.a.c,f=b.ab(),this.j=Uh(this.a,f),a.Wa(this.j),f=a.Ga(f),c=a.Ma([f[0]-c*Math.cos(e),f[1]-c*Math.sin(e)]),c=b.Pd(c),b.mb(c));Xd(b,-1);a.render();
+return!1}this.c=null;return!0}function ni(a){if(0<this.o.length&&this.A(a)){var b=a.map,c=b.aa();this.c=null;this.C||Xd(c,1);b.render();this.j&&nb(b.R,this.j)&&(c.mb(a.frameState.viewState.center),this.j=null);this.a&&(a=this.a,a.b.length=0,a.c=0,a.a=0);this.s=1<this.o.length;return!0}return!1}mi.prototype.Gc=rc;function qi(a){a=a?a:{};ji.call(this,{handleDownEvent:ri,handleDragEvent:si,handleUpEvent:ti});this.c=a.condition?a.condition:ai;this.a=void 0;this.j=void 0!==a.duration?a.duration:250}y(qi,ji);function si(a){if(hi(a)){var b=a.map,c=b.Za();a=a.pixel;c=Math.atan2(c[1]/2-a[1],a[0]-c[0]/2);if(void 0!==this.a){a=c-this.a;var d=b.aa(),e=d.La();b.render();Wh(b,d,e-a)}this.a=c}}
+function ti(a){if(!hi(a))return!0;a=a.map;var b=a.aa();Xd(b,-1);var c=b.La(),d=this.j,c=b.constrainRotation(c,0);Wh(a,b,c,void 0,d);return!1}function ri(a){return hi(a)&&bi(a)&&this.c(a)?(a=a.map,Xd(a.aa(),1),a.render(),this.a=void 0,!0):!1}qi.prototype.Gc=rc;function ui(a){this.f=null;this.a=document.createElement("div");this.a.style.position="absolute";this.a.className="ol-box "+a;this.g=this.c=this.b=null}y(ui,Sa);ui.prototype.ka=function(){this.setMap(null)};function vi(a){var b=a.c,c=a.g;a=a.a.style;a.left=Math.min(b[0],c[0])+"px";a.top=Math.min(b[1],c[1])+"px";a.width=Math.abs(c[0]-b[0])+"px";a.height=Math.abs(c[1]-b[1])+"px"}
+ui.prototype.setMap=function(a){if(this.b){this.b.A.removeChild(this.a);var b=this.a.style;b.left=b.top=b.width=b.height="inherit"}(this.b=a)&&this.b.A.appendChild(this.a)};function wi(a){var b=a.c,c=a.g,b=[b,[b[0],c[1]],c,[c[0],b[1]]].map(a.b.Ma,a.b);b[4]=b[0].slice();a.f?a.f.pa([b]):a.f=new E([b])}ui.prototype.W=function(){return this.f};function xi(a,b,c){Wa.call(this,a);this.coordinate=b;this.mapBrowserEvent=c}y(xi,Wa);function yi(a){ji.call(this,{handleDownEvent:zi,handleDragEvent:Ai,handleUpEvent:Bi});a=a?a:{};this.a=new ui(a.className||"ol-dragbox");this.c=null;this.D=a.condition?a.condition:qc;this.A=a.boxEndCondition?a.boxEndCondition:Ci}y(yi,ji);function Ci(a,b,c){a=c[0]-b[0];b=c[1]-b[1];return 64<=a*a+b*b}
+function Ai(a){if(hi(a)){var b=this.a,c=a.pixel;b.c=this.c;b.g=c;wi(b);vi(b);this.b(new xi("boxdrag",a.coordinate,a))}}yi.prototype.W=function(){return this.a.W()};yi.prototype.s=na;function Bi(a){if(!hi(a))return!0;this.a.setMap(null);this.A(a,this.c,a.pixel)&&(this.s(a),this.b(new xi("boxend",a.coordinate,a)));return!1}
+function zi(a){if(hi(a)&&bi(a)&&this.D(a)){this.c=a.pixel;this.a.setMap(a.map);var b=this.a,c=this.c;b.c=this.c;b.g=c;wi(b);vi(b);this.b(new xi("boxstart",a.coordinate,a));return!0}return!1};function Di(a){a=a?a:{};var b=a.condition?a.condition:fi;this.j=void 0!==a.duration?a.duration:200;this.R=void 0!==a.out?a.out:!1;yi.call(this,{condition:b,className:a.className||"ol-dragzoom"})}y(Di,yi);
+Di.prototype.s=function(){var a=this.v,b=a.aa(),c=a.Za(),d=this.W().H();if(this.R){var e=b.Kc(c),d=[a.Ga(cc(d)),a.Ga(ec(d))],f=Wb(Infinity,Infinity,-Infinity,-Infinity,void 0),g,h;g=0;for(h=d.length;g<h;++g)Mb(f,d[g]);oc(e,1/Td(f,c));d=e}c=b.constrainResolution(Td(d,c));e=b.$();f=b.ab();a.Wa(ee({resolution:e,duration:this.j,easing:Zd}));a.Wa(ce({source:f,duration:this.j,easing:Zd}));b.mb(kc(d));b.Ub(c)};function Ei(a){Vh.call(this,{handleEvent:Fi});a=a||{};this.a=function(a){return ei(a)&&gi(a)};this.c=void 0!==a.condition?a.condition:this.a;this.o=void 0!==a.duration?a.duration:100;this.j=void 0!==a.pixelDelta?a.pixelDelta:128}y(Ei,Vh);
+function Fi(a){var b=!1;if("keydown"==a.type){var c=a.originalEvent.keyCode;if(this.c(a)&&(40==c||37==c||39==c||38==c)){var d=a.map,b=d.aa(),e=b.$()*this.j,f=0,g=0;40==c?g=-e:37==c?f=-e:39==c?f=e:g=e;c=[f,g];Gb(c,b.La());e=this.o;if(f=b.ab())e&&0<e&&d.Wa(ce({source:f,duration:e,easing:ae})),d=b.Pd([f[0]+c[0],f[1]+c[1]]),b.mb(d);a.preventDefault();b=!0}}return!b};function Gi(a){Vh.call(this,{handleEvent:Hi});a=a?a:{};this.c=a.condition?a.condition:gi;this.a=a.delta?a.delta:1;this.o=void 0!==a.duration?a.duration:100}y(Gi,Vh);function Hi(a){var b=!1;if("keydown"==a.type||"keypress"==a.type){var c=a.originalEvent.charCode;if(this.c(a)&&(43==c||45==c)){b=a.map;c=43==c?this.a:-this.a;b.render();var d=b.aa();Xh(b,d,c,void 0,this.o);a.preventDefault();b=!0}}return!b};function Ii(a){Vh.call(this,{handleEvent:Ji});a=a||{};this.c=0;this.C=void 0!==a.duration?a.duration:250;this.s=void 0!==a.useAnchor?a.useAnchor:!0;this.a=null;this.j=this.o=void 0}y(Ii,Vh);
+function Ji(a){var b=!1;if("wheel"==a.type||"mousewheel"==a.type){var b=a.map,c=a.originalEvent;this.s&&(this.a=a.coordinate);var d;"wheel"==a.type?(d=c.deltaY,dg&&c.deltaMode===pa.WheelEvent.DOM_DELTA_PIXEL&&(d/=gg),c.deltaMode===pa.WheelEvent.DOM_DELTA_LINE&&(d*=40)):"mousewheel"==a.type&&(d=-c.wheelDeltaY,eg&&(d/=3));this.c+=d;void 0===this.o&&(this.o=Date.now());d=Math.max(80-(Date.now()-this.o),0);pa.clearTimeout(this.j);this.j=pa.setTimeout(this.A.bind(this,b),d);a.preventDefault();b=!0}return!b}
+Ii.prototype.A=function(a){var b=sa(this.c,-1,1),c=a.aa();a.render();Xh(a,c,-b,this.a,this.C);this.c=0;this.a=null;this.j=this.o=void 0};Ii.prototype.D=function(a){this.s=a;a||(this.a=null)};function Ki(a){ji.call(this,{handleDownEvent:Li,handleDragEvent:Mi,handleUpEvent:Ni});a=a||{};this.c=null;this.j=void 0;this.a=!1;this.s=0;this.D=void 0!==a.threshold?a.threshold:.3;this.A=void 0!==a.duration?a.duration:250}y(Ki,ji);
+function Mi(a){var b=0,c=this.o[0],d=this.o[1],c=Math.atan2(d.clientY-c.clientY,d.clientX-c.clientX);void 0!==this.j&&(b=c-this.j,this.s+=b,!this.a&&Math.abs(this.s)>this.D&&(this.a=!0));this.j=c;a=a.map;c=a.a.getBoundingClientRect();d=li(this.o);d[0]-=c.left;d[1]-=c.top;this.c=a.Ma(d);this.a&&(c=a.aa(),d=c.La(),a.render(),Wh(a,c,d+b,this.c))}
+function Ni(a){if(2>this.o.length){a=a.map;var b=a.aa();Xd(b,-1);if(this.a){var c=b.La(),d=this.c,e=this.A,c=b.constrainRotation(c,0);Wh(a,b,c,d,e)}return!1}return!0}function Li(a){return 2<=this.o.length?(a=a.map,this.c=null,this.j=void 0,this.a=!1,this.s=0,this.C||Xd(a.aa(),1),a.render(),!0):!1}Ki.prototype.Gc=rc;function Oi(a){ji.call(this,{handleDownEvent:Pi,handleDragEvent:Qi,handleUpEvent:Ri});a=a?a:{};this.c=null;this.s=void 0!==a.duration?a.duration:400;this.a=void 0;this.j=1}y(Oi,ji);function Qi(a){var b=1,c=this.o[0],d=this.o[1],e=c.clientX-d.clientX,c=c.clientY-d.clientY,e=Math.sqrt(e*e+c*c);void 0!==this.a&&(b=this.a/e);this.a=e;1!=b&&(this.j=b);a=a.map;var e=a.aa(),c=e.$(),d=a.a.getBoundingClientRect(),f=li(this.o);f[0]-=d.left;f[1]-=d.top;this.c=a.Ma(f);a.render();Yh(a,e,c*b,this.c)}
+function Ri(a){if(2>this.o.length){a=a.map;var b=a.aa();Xd(b,-1);var c=b.$(),d=this.c,e=this.s,c=b.constrainResolution(c,0,this.j-1);Yh(a,b,c,d,e);return!1}return!0}function Pi(a){return 2<=this.o.length?(a=a.map,this.c=null,this.a=void 0,this.j=1,this.C||Xd(a.aa(),1),a.render(),!0):!1}Oi.prototype.Gc=rc;function Si(a){a=a?a:{};var b=new le,c=new Th(-.005,.05,100);(void 0!==a.altShiftDragRotate?a.altShiftDragRotate:1)&&b.push(new qi);(void 0!==a.doubleClickZoom?a.doubleClickZoom:1)&&b.push(new Zh({delta:a.zoomDelta,duration:a.zoomDuration}));(void 0!==a.dragPan?a.dragPan:1)&&b.push(new mi({kinetic:c}));(void 0!==a.pinchRotate?a.pinchRotate:1)&&b.push(new Ki);(void 0!==a.pinchZoom?a.pinchZoom:1)&&b.push(new Oi({duration:a.zoomDuration}));if(void 0!==a.keyboard?a.keyboard:1)b.push(new Ei),b.push(new Gi({delta:a.zoomDelta,
+duration:a.zoomDuration}));(void 0!==a.mouseWheelZoom?a.mouseWheelZoom:1)&&b.push(new Ii({duration:a.zoomDuration}));(void 0!==a.shiftDragZoom?a.shiftDragZoom:1)&&b.push(new Di({duration:a.zoomDuration}));return b};function Ti(a){var b=a||{};a=Ea({},b);delete a.layers;b=b.layers;ih.call(this,a);this.f=[];this.a={};B(this,gb("layers"),this.Tk,this);b?Array.isArray(b)&&(b=new le(b.slice())):b=new le;this.oh(b)}y(Ti,ih);k=Ti.prototype;k.ce=function(){this.xb()&&this.u()};
+k.Tk=function(){this.f.forEach(Ka);this.f.length=0;var a=this.Tc();this.f.push(B(a,"add",this.Sk,this),B(a,"remove",this.Uk,this));for(var b in this.a)this.a[b].forEach(Ka);Fa(this.a);var a=a.a,c,d;b=0;for(c=a.length;b<c;b++)d=a[b],this.a[w(d).toString()]=[B(d,"propertychange",this.ce,this),B(d,"change",this.ce,this)];this.u()};k.Sk=function(a){a=a.element;var b=w(a).toString();this.a[b]=[B(a,"propertychange",this.ce,this),B(a,"change",this.ce,this)];this.u()};
+k.Uk=function(a){a=w(a.element).toString();this.a[a].forEach(Ka);delete this.a[a];this.u()};k.Tc=function(){return this.get("layers")};k.oh=function(a){this.set("layers",a)};
+k.hf=function(a){var b=void 0!==a?a:[],c=b.length;this.Tc().forEach(function(a){a.hf(b)});a=jh(this);var d,e;for(d=b.length;c<d;c++)e=b[c],e.opacity*=a.opacity,e.visible=e.visible&&a.visible,e.maxResolution=Math.min(e.maxResolution,a.maxResolution),e.minResolution=Math.max(e.minResolution,a.minResolution),void 0!==a.extent&&(e.extent=void 0!==e.extent?mc(e.extent,a.extent):a.extent);return b};k.kf=function(){return"ready"};function Ui(a){vc.call(this,{code:a,units:"m",extent:Vi,global:!0,worldExtent:Wi})}y(Ui,vc);Ui.prototype.getPointResolution=function(a,b){return a/ta(b[1]/6378137)};var Xi=6378137*Math.PI,Vi=[-Xi,-Xi,Xi,Xi],Wi=[-180,-85,180,85],Hc="EPSG:3857 EPSG:102100 EPSG:102113 EPSG:900913 urn:ogc:def:crs:EPSG:6.18:3:3857 urn:ogc:def:crs:EPSG::3857 http://www.opengis.net/gml/srs/epsg.xml#3857".split(" ").map(function(a){return new Ui(a)});
+function Ic(a,b,c){var d=a.length;c=1<c?c:2;void 0===b&&(2<c?b=a.slice():b=Array(d));for(var e=0;e<d;e+=c)b[e]=6378137*Math.PI*a[e]/180,b[e+1]=6378137*Math.log(Math.tan(Math.PI*(a[e+1]+90)/360));return b}function Jc(a,b,c){var d=a.length;c=1<c?c:2;void 0===b&&(2<c?b=a.slice():b=Array(d));for(var e=0;e<d;e+=c)b[e]=180*a[e]/(6378137*Math.PI),b[e+1]=360*Math.atan(Math.exp(a[e+1]/6378137))/Math.PI-90;return b};var Yi=new sc(6378137);function Zi(a,b){vc.call(this,{code:a,units:"degrees",extent:$i,axisOrientation:b,global:!0,metersPerUnit:aj,worldExtent:$i})}y(Zi,vc);Zi.prototype.getPointResolution=function(a){return a};
+var $i=[-180,-90,180,90],aj=Math.PI*Yi.radius/180,Kc=[new Zi("CRS:84"),new Zi("EPSG:4326","neu"),new Zi("urn:ogc:def:crs:EPSG::4326","neu"),new Zi("urn:ogc:def:crs:EPSG:6.6:4326","neu"),new Zi("urn:ogc:def:crs:OGC:1.3:CRS84"),new Zi("urn:ogc:def:crs:OGC:2:84"),new Zi("http://www.opengis.net/gml/srs/epsg.xml#4326","neu"),new Zi("urn:x-ogc:def:crs:EPSG:4326","neu")];function bj(){zc(Hc);zc(Kc);Gc()};function cj(a){mh.call(this,a?a:{})}y(cj,mh);function dj(a){a=a?a:{};var b=Ea({},a);delete b.preload;delete b.useInterimTilesOnError;mh.call(this,b);this.l(void 0!==a.preload?a.preload:0);this.A(void 0!==a.useInterimTilesOnError?a.useInterimTilesOnError:!0)}y(dj,mh);dj.prototype.f=function(){return this.get("preload")};dj.prototype.l=function(a){this.set("preload",a)};dj.prototype.c=function(){return this.get("useInterimTilesOnError")};dj.prototype.A=function(a){this.set("useInterimTilesOnError",a)};var ej=[0,0,0,1],fj=[],gj=[0,0,0,1];function hj(a,b,c,d){0!==b&&(a.translate(c,d),a.rotate(b),a.translate(-c,-d))};function ij(a){a=a||{};this.b=void 0!==a.color?a.color:null;this.a=void 0}ij.prototype.g=function(){return this.b};ij.prototype.f=function(a){this.b=a;this.a=void 0};function jj(a){void 0===a.a&&(a.a=a.b instanceof CanvasPattern||a.b instanceof CanvasGradient?w(a.b).toString():"f"+(a.b?ve(a.b):"-"));return a.a};function kj(){this.a=-1};function lj(){this.a=64;this.b=Array(4);this.c=Array(this.a);this.b[0]=1732584193;this.b[1]=4023233417;this.b[2]=2562383102;this.b[3]=271733878;this.f=this.g=0}(function(){function a(){}a.prototype=kj.prototype;lj.a=kj.prototype;lj.prototype=new a;lj.prototype.constructor=lj;lj.b=function(a,c,d){for(var e=Array(arguments.length-2),f=2;f<arguments.length;f++)e[f-2]=arguments[f];return kj.prototype[c].apply(a,e)}})();
+function mj(a,b,c){c||(c=0);var d=Array(16);if(da(b))for(var e=0;16>e;++e)d[e]=b.charCodeAt(c++)|b.charCodeAt(c++)<<8|b.charCodeAt(c++)<<16|b.charCodeAt(c++)<<24;else for(e=0;16>e;++e)d[e]=b[c++]|b[c++]<<8|b[c++]<<16|b[c++]<<24;b=a.b[0];c=a.b[1];var e=a.b[2],f=a.b[3],g;g=b+(f^c&(e^f))+d[0]+3614090360&4294967295;b=c+(g<<7&4294967295|g>>>25);g=f+(e^b&(c^e))+d[1]+3905402710&4294967295;f=b+(g<<12&4294967295|g>>>20);g=e+(c^f&(b^c))+d[2]+606105819&4294967295;e=f+(g<<17&4294967295|g>>>15);g=c+(b^e&(f^b))+
+d[3]+3250441966&4294967295;c=e+(g<<22&4294967295|g>>>10);g=b+(f^c&(e^f))+d[4]+4118548399&4294967295;b=c+(g<<7&4294967295|g>>>25);g=f+(e^b&(c^e))+d[5]+1200080426&4294967295;f=b+(g<<12&4294967295|g>>>20);g=e+(c^f&(b^c))+d[6]+2821735955&4294967295;e=f+(g<<17&4294967295|g>>>15);g=c+(b^e&(f^b))+d[7]+4249261313&4294967295;c=e+(g<<22&4294967295|g>>>10);g=b+(f^c&(e^f))+d[8]+1770035416&4294967295;b=c+(g<<7&4294967295|g>>>25);g=f+(e^b&(c^e))+d[9]+2336552879&4294967295;f=b+(g<<12&4294967295|g>>>20);g=e+(c^f&
+(b^c))+d[10]+4294925233&4294967295;e=f+(g<<17&4294967295|g>>>15);g=c+(b^e&(f^b))+d[11]+2304563134&4294967295;c=e+(g<<22&4294967295|g>>>10);g=b+(f^c&(e^f))+d[12]+1804603682&4294967295;b=c+(g<<7&4294967295|g>>>25);g=f+(e^b&(c^e))+d[13]+4254626195&4294967295;f=b+(g<<12&4294967295|g>>>20);g=e+(c^f&(b^c))+d[14]+2792965006&4294967295;e=f+(g<<17&4294967295|g>>>15);g=c+(b^e&(f^b))+d[15]+1236535329&4294967295;c=e+(g<<22&4294967295|g>>>10);g=b+(e^f&(c^e))+d[1]+4129170786&4294967295;b=c+(g<<5&4294967295|g>>>
+27);g=f+(c^e&(b^c))+d[6]+3225465664&4294967295;f=b+(g<<9&4294967295|g>>>23);g=e+(b^c&(f^b))+d[11]+643717713&4294967295;e=f+(g<<14&4294967295|g>>>18);g=c+(f^b&(e^f))+d[0]+3921069994&4294967295;c=e+(g<<20&4294967295|g>>>12);g=b+(e^f&(c^e))+d[5]+3593408605&4294967295;b=c+(g<<5&4294967295|g>>>27);g=f+(c^e&(b^c))+d[10]+38016083&4294967295;f=b+(g<<9&4294967295|g>>>23);g=e+(b^c&(f^b))+d[15]+3634488961&4294967295;e=f+(g<<14&4294967295|g>>>18);g=c+(f^b&(e^f))+d[4]+3889429448&4294967295;c=e+(g<<20&4294967295|
+g>>>12);g=b+(e^f&(c^e))+d[9]+568446438&4294967295;b=c+(g<<5&4294967295|g>>>27);g=f+(c^e&(b^c))+d[14]+3275163606&4294967295;f=b+(g<<9&4294967295|g>>>23);g=e+(b^c&(f^b))+d[3]+4107603335&4294967295;e=f+(g<<14&4294967295|g>>>18);g=c+(f^b&(e^f))+d[8]+1163531501&4294967295;c=e+(g<<20&4294967295|g>>>12);g=b+(e^f&(c^e))+d[13]+2850285829&4294967295;b=c+(g<<5&4294967295|g>>>27);g=f+(c^e&(b^c))+d[2]+4243563512&4294967295;f=b+(g<<9&4294967295|g>>>23);g=e+(b^c&(f^b))+d[7]+1735328473&4294967295;e=f+(g<<14&4294967295|
+g>>>18);g=c+(f^b&(e^f))+d[12]+2368359562&4294967295;c=e+(g<<20&4294967295|g>>>12);g=b+(c^e^f)+d[5]+4294588738&4294967295;b=c+(g<<4&4294967295|g>>>28);g=f+(b^c^e)+d[8]+2272392833&4294967295;f=b+(g<<11&4294967295|g>>>21);g=e+(f^b^c)+d[11]+1839030562&4294967295;e=f+(g<<16&4294967295|g>>>16);g=c+(e^f^b)+d[14]+4259657740&4294967295;c=e+(g<<23&4294967295|g>>>9);g=b+(c^e^f)+d[1]+2763975236&4294967295;b=c+(g<<4&4294967295|g>>>28);g=f+(b^c^e)+d[4]+1272893353&4294967295;f=b+(g<<11&4294967295|g>>>21);g=e+(f^
+b^c)+d[7]+4139469664&4294967295;e=f+(g<<16&4294967295|g>>>16);g=c+(e^f^b)+d[10]+3200236656&4294967295;c=e+(g<<23&4294967295|g>>>9);g=b+(c^e^f)+d[13]+681279174&4294967295;b=c+(g<<4&4294967295|g>>>28);g=f+(b^c^e)+d[0]+3936430074&4294967295;f=b+(g<<11&4294967295|g>>>21);g=e+(f^b^c)+d[3]+3572445317&4294967295;e=f+(g<<16&4294967295|g>>>16);g=c+(e^f^b)+d[6]+76029189&4294967295;c=e+(g<<23&4294967295|g>>>9);g=b+(c^e^f)+d[9]+3654602809&4294967295;b=c+(g<<4&4294967295|g>>>28);g=f+(b^c^e)+d[12]+3873151461&4294967295;
+f=b+(g<<11&4294967295|g>>>21);g=e+(f^b^c)+d[15]+530742520&4294967295;e=f+(g<<16&4294967295|g>>>16);g=c+(e^f^b)+d[2]+3299628645&4294967295;c=e+(g<<23&4294967295|g>>>9);g=b+(e^(c|~f))+d[0]+4096336452&4294967295;b=c+(g<<6&4294967295|g>>>26);g=f+(c^(b|~e))+d[7]+1126891415&4294967295;f=b+(g<<10&4294967295|g>>>22);g=e+(b^(f|~c))+d[14]+2878612391&4294967295;e=f+(g<<15&4294967295|g>>>17);g=c+(f^(e|~b))+d[5]+4237533241&4294967295;c=e+(g<<21&4294967295|g>>>11);g=b+(e^(c|~f))+d[12]+1700485571&4294967295;b=c+
+(g<<6&4294967295|g>>>26);g=f+(c^(b|~e))+d[3]+2399980690&4294967295;f=b+(g<<10&4294967295|g>>>22);g=e+(b^(f|~c))+d[10]+4293915773&4294967295;e=f+(g<<15&4294967295|g>>>17);g=c+(f^(e|~b))+d[1]+2240044497&4294967295;c=e+(g<<21&4294967295|g>>>11);g=b+(e^(c|~f))+d[8]+1873313359&4294967295;b=c+(g<<6&4294967295|g>>>26);g=f+(c^(b|~e))+d[15]+4264355552&4294967295;f=b+(g<<10&4294967295|g>>>22);g=e+(b^(f|~c))+d[6]+2734768916&4294967295;e=f+(g<<15&4294967295|g>>>17);g=c+(f^(e|~b))+d[13]+1309151649&4294967295;
+c=e+(g<<21&4294967295|g>>>11);g=b+(e^(c|~f))+d[4]+4149444226&4294967295;b=c+(g<<6&4294967295|g>>>26);g=f+(c^(b|~e))+d[11]+3174756917&4294967295;f=b+(g<<10&4294967295|g>>>22);g=e+(b^(f|~c))+d[2]+718787259&4294967295;e=f+(g<<15&4294967295|g>>>17);g=c+(f^(e|~b))+d[9]+3951481745&4294967295;a.b[0]=a.b[0]+b&4294967295;a.b[1]=a.b[1]+(e+(g<<21&4294967295|g>>>11))&4294967295;a.b[2]=a.b[2]+e&4294967295;a.b[3]=a.b[3]+f&4294967295}
+function nj(a,b){var c;void 0===c&&(c=b.length);for(var d=c-a.a,e=a.c,f=a.g,g=0;g<c;){if(0==f)for(;g<=d;)mj(a,b,g),g+=a.a;if(da(b))for(;g<c;){if(e[f++]=b.charCodeAt(g++),f==a.a){mj(a,e);f=0;break}}else for(;g<c;)if(e[f++]=b[g++],f==a.a){mj(a,e);f=0;break}}a.g=f;a.f+=c};function oj(a){a=a||{};this.b=void 0!==a.color?a.color:null;this.f=a.lineCap;this.g=void 0!==a.lineDash?a.lineDash:null;this.c=a.lineJoin;this.i=a.miterLimit;this.a=a.width;this.l=void 0}k=oj.prototype;k.Kn=function(){return this.b};k.dk=function(){return this.f};k.Ln=function(){return this.g};k.ek=function(){return this.c};k.jk=function(){return this.i};k.Mn=function(){return this.a};k.Nn=function(a){this.b=a;this.l=void 0};k.fp=function(a){this.f=a;this.l=void 0};
+k.On=function(a){this.g=a;this.l=void 0};k.gp=function(a){this.c=a;this.l=void 0};k.hp=function(a){this.i=a;this.l=void 0};k.lp=function(a){this.a=a;this.l=void 0};
+function pj(a){if(void 0===a.l){var b="s"+(a.b?ve(a.b):"-")+","+(void 0!==a.f?a.f.toString():"-")+","+(a.g?a.g.toString():"-")+","+(void 0!==a.c?a.c:"-")+","+(void 0!==a.i?a.i.toString():"-")+","+(void 0!==a.a?a.a.toString():"-"),c=new lj;nj(c,b);b=Array((56>c.g?c.a:2*c.a)-c.g);b[0]=128;for(var d=1;d<b.length-8;++d)b[d]=0;for(var e=8*c.f,d=b.length-8;d<b.length;++d)b[d]=e&255,e/=256;nj(c,b);b=Array(16);for(d=e=0;4>d;++d)for(var f=0;32>f;f+=8)b[e++]=c.b[d]>>>f&255;if(8192>=b.length)c=String.fromCharCode.apply(null,
+b);else for(c="",d=0;d<b.length;d+=8192)e=pe(b,d,d+8192),c+=String.fromCharCode.apply(null,e);a.l=c}return a.l};function qj(a){a=a||{};this.l=this.f=this.c=null;this.g=void 0!==a.fill?a.fill:null;this.b=void 0!==a.stroke?a.stroke:null;this.a=a.radius;this.A=[0,0];this.s=this.D=this.o=null;var b=a.atlasManager,c,d=null,e,f=0;this.b&&(e=ve(this.b.b),f=this.b.a,void 0===f&&(f=1),d=this.b.g,hg||(d=null));var g=2*(this.a+f)+1;e={strokeStyle:e,Bd:f,size:g,lineDash:d};if(void 0===b)b=Oe(g,g),this.f=b.canvas,c=g=this.f.width,this.Gh(e,b,0,0),this.g?this.l=this.f:(b=Oe(e.size,e.size),this.l=b.canvas,this.Fh(e,b,0,0));
+else{g=Math.round(g);(d=!this.g)&&(c=this.Fh.bind(this,e));var f=this.b?pj(this.b):"-",h=this.g?jj(this.g):"-";this.c&&f==this.c[1]&&h==this.c[2]&&this.a==this.c[3]||(this.c=["c"+f+h+(void 0!==this.a?this.a.toString():"-"),f,h,this.a]);b=b.add(this.c[0],g,g,this.Gh.bind(this,e),c);this.f=b.image;this.A=[b.offsetX,b.offsetY];c=b.image.width;this.l=d?b.Sg:this.f}this.o=[g/2,g/2];this.D=[g,g];this.s=[c,c];Ch.call(this,{opacity:1,rotateWithView:!1,rotation:0,scale:1,snapToPixel:void 0!==a.snapToPixel?
+a.snapToPixel:!0})}y(qj,Ch);k=qj.prototype;k.Yb=function(){return this.o};k.Bn=function(){return this.g};k.pe=function(){return this.l};k.jc=function(){return this.f};k.td=function(){return 2};k.ld=function(){return this.s};k.Ia=function(){return this.A};k.Cn=function(){return this.a};k.Fb=function(){return this.D};k.Dn=function(){return this.b};k.pf=na;k.load=na;k.Xf=na;
+k.Gh=function(a,b,c,d){b.setTransform(1,0,0,1,0,0);b.translate(c,d);b.beginPath();b.arc(a.size/2,a.size/2,this.a,0,2*Math.PI,!0);this.g&&(b.fillStyle=xe(this.g.b),b.fill());this.b&&(b.strokeStyle=a.strokeStyle,b.lineWidth=a.Bd,a.lineDash&&b.setLineDash(a.lineDash),b.stroke());b.closePath()};
+k.Fh=function(a,b,c,d){b.setTransform(1,0,0,1,0,0);b.translate(c,d);b.beginPath();b.arc(a.size/2,a.size/2,this.a,0,2*Math.PI,!0);b.fillStyle=ve(ej);b.fill();this.b&&(b.strokeStyle=a.strokeStyle,b.lineWidth=a.Bd,a.lineDash&&b.setLineDash(a.lineDash),b.stroke());b.closePath()};function rj(a){a=a||{};this.i=null;this.g=sj;void 0!==a.geometry&&this.Jh(a.geometry);this.c=void 0!==a.fill?a.fill:null;this.a=void 0!==a.image?a.image:null;this.f=void 0!==a.stroke?a.stroke:null;this.l=void 0!==a.text?a.text:null;this.b=a.zIndex}k=rj.prototype;k.W=function(){return this.i};k.Zj=function(){return this.g};k.Pn=function(){return this.c};k.Qn=function(){return this.a};k.Rn=function(){return this.f};k.Ha=function(){return this.l};k.Sn=function(){return this.b};
+k.Jh=function(a){"function"===typeof a?this.g=a:"string"===typeof a?this.g=function(b){return b.get(a)}:a?a&&(this.g=function(){return a}):this.g=sj;this.i=a};k.Tn=function(a){this.b=a};function tj(a){if("function"!==typeof a){var b;b=Array.isArray(a)?a:[a];a=function(){return b}}return a}var uj=null;function vj(){if(!uj){var a=new ij({color:"rgba(255,255,255,0.4)"}),b=new oj({color:"#3399CC",width:1.25});uj=[new rj({image:new qj({fill:a,stroke:b,radius:5}),fill:a,stroke:b})]}return uj}
+function wj(){var a={},b=[255,255,255,1],c=[0,153,255,1];a.Polygon=[new rj({fill:new ij({color:[255,255,255,.5]})})];a.MultiPolygon=a.Polygon;a.LineString=[new rj({stroke:new oj({color:b,width:5})}),new rj({stroke:new oj({color:c,width:3})})];a.MultiLineString=a.LineString;a.Circle=a.Polygon.concat(a.LineString);a.Point=[new rj({image:new qj({radius:6,fill:new ij({color:c}),stroke:new oj({color:b,width:1.5})}),zIndex:Infinity})];a.MultiPoint=a.Point;a.GeometryCollection=a.Polygon.concat(a.LineString,
+a.Point);return a}function sj(a){return a.W()};function G(a){a=a?a:{};var b=Ea({},a);delete b.style;delete b.renderBuffer;delete b.updateWhileAnimating;delete b.updateWhileInteracting;mh.call(this,b);this.a=void 0!==a.renderBuffer?a.renderBuffer:100;this.A=null;this.i=void 0;this.l(a.style);this.S=void 0!==a.updateWhileAnimating?a.updateWhileAnimating:!1;this.T=void 0!==a.updateWhileInteracting?a.updateWhileInteracting:!1}y(G,mh);function xj(a){return a.get("renderOrder")}G.prototype.C=function(){return this.A};G.prototype.D=function(){return this.i};
+G.prototype.l=function(a){this.A=void 0!==a?a:vj;this.i=null===a?void 0:tj(this.A);this.u()};function I(a){a=a?a:{};var b=Ea({},a);delete b.preload;delete b.useInterimTilesOnError;G.call(this,b);this.Y(a.preload?a.preload:0);this.ia(a.useInterimTilesOnError?a.useInterimTilesOnError:!0);this.s=a.renderMode||"hybrid"}y(I,G);I.prototype.f=function(){return this.get("preload")};I.prototype.c=function(){return this.get("useInterimTilesOnError")};I.prototype.Y=function(a){this.set("preload",a)};I.prototype.ia=function(a){this.set("useInterimTilesOnError",a)};function yj(a,b,c,d,e){this.f=a;this.A=b;this.c=c;this.D=d;this.Hc=e;this.i=this.b=this.a=this.ia=this.Ra=this.Y=null;this.qa=this.za=this.v=this.Ba=this.ya=this.R=0;this.Gb=!1;this.l=this.ta=0;this.Aa=!1;this.S=0;this.g="";this.j=this.C=this.qb=this.Sa=0;this.T=this.s=this.o=null;this.U=[];this.Hb=Xc()}y(yj,kh);
+function zj(a,b,c){if(a.i){b=gd(b,0,c,2,a.D,a.U);c=a.f;var d=a.Hb,e=c.globalAlpha;1!=a.v&&(c.globalAlpha=e*a.v);var f=a.ta;a.Gb&&(f+=a.Hc);var g,h;g=0;for(h=b.length;g<h;g+=2){var l=b[g]-a.R,m=b[g+1]-a.ya;a.Aa&&(l=Math.round(l),m=Math.round(m));if(0!==f||1!=a.l){var n=l+a.R,p=m+a.ya;qh(d,n,p,a.l,a.l,f,-n,-p);c.setTransform(d[0],d[1],d[4],d[5],d[12],d[13])}c.drawImage(a.i,a.za,a.qa,a.S,a.Ba,l,m,a.S,a.Ba)}0===f&&1==a.l||c.setTransform(1,0,0,1,0,0);1!=a.v&&(c.globalAlpha=e)}}
+function Aj(a,b,c,d){var e=0;if(a.T&&""!==a.g){a.o&&Bj(a,a.o);a.s&&Cj(a,a.s);var f=a.T,g=a.f,h=a.ia;h?(h.font!=f.font&&(h.font=g.font=f.font),h.textAlign!=f.textAlign&&(h.textAlign=g.textAlign=f.textAlign),h.textBaseline!=f.textBaseline&&(h.textBaseline=g.textBaseline=f.textBaseline)):(g.font=f.font,g.textAlign=f.textAlign,g.textBaseline=f.textBaseline,a.ia={font:f.font,textAlign:f.textAlign,textBaseline:f.textBaseline});b=gd(b,e,c,d,a.D,a.U);for(f=a.f;e<c;e+=d){g=b[e]+a.Sa;h=b[e+1]+a.qb;if(0!==a.C||
+1!=a.j){var l=qh(a.Hb,g,h,a.j,a.j,a.C,-g,-h);f.setTransform(l[0],l[1],l[4],l[5],l[12],l[13])}a.s&&f.strokeText(a.g,g,h);a.o&&f.fillText(a.g,g,h)}0===a.C&&1==a.j||f.setTransform(1,0,0,1,0,0)}}function Dj(a,b,c,d,e,f){var g=a.f;a=gd(b,c,d,e,a.D,a.U);g.moveTo(a[0],a[1]);b=a.length;f&&(b-=2);for(c=2;c<b;c+=2)g.lineTo(a[c],a[c+1]);f&&g.closePath();return d}function Ej(a,b,c,d,e){var f,g;f=0;for(g=d.length;f<g;++f)c=Dj(a,b,c,d[f],e,!0);return c}k=yj.prototype;
+k.Rd=function(a){if(nc(this.c,a.H())){if(this.a||this.b){this.a&&Bj(this,this.a);this.b&&Cj(this,this.b);var b;b=this.D;var c=this.U,d=a.la();b=d?gd(d,0,d.length,a.va(),b,c):null;c=b[2]-b[0];d=b[3]-b[1];c=Math.sqrt(c*c+d*d);d=this.f;d.beginPath();d.arc(b[0],b[1],c,0,2*Math.PI);this.a&&d.fill();this.b&&d.stroke()}""!==this.g&&Aj(this,a.rd(),2,2)}};k.sd=function(a){this.Sb(a.c,a.f);this.Tb(a.a);this.Vb(a.Ha())};
+k.sc=function(a){switch(a.X()){case "Point":this.uc(a);break;case "LineString":this.hd(a);break;case "Polygon":this.bf(a);break;case "MultiPoint":this.tc(a);break;case "MultiLineString":this.$e(a);break;case "MultiPolygon":this.af(a);break;case "GeometryCollection":this.Ze(a);break;case "Circle":this.Rd(a)}};k.Ye=function(a,b){var c=(0,b.g)(a);c&&nc(this.c,c.H())&&(this.sd(b),this.sc(c))};k.Ze=function(a){a=a.c;var b,c;b=0;for(c=a.length;b<c;++b)this.sc(a[b])};
+k.uc=function(a){var b=a.la();a=a.va();this.i&&zj(this,b,b.length);""!==this.g&&Aj(this,b,b.length,a)};k.tc=function(a){var b=a.la();a=a.va();this.i&&zj(this,b,b.length);""!==this.g&&Aj(this,b,b.length,a)};k.hd=function(a){if(nc(this.c,a.H())){if(this.b){Cj(this,this.b);var b=this.f,c=a.la();b.beginPath();Dj(this,c,0,c.length,a.va(),!1);b.stroke()}""!==this.g&&(a=Fj(a),Aj(this,a,2,2))}};
+k.$e=function(a){var b=a.H();if(nc(this.c,b)){if(this.b){Cj(this,this.b);var b=this.f,c=a.la(),d=0,e=a.Db(),f=a.va();b.beginPath();var g,h;g=0;for(h=e.length;g<h;++g)d=Dj(this,c,d,e[g],f,!1);b.stroke()}""!==this.g&&(a=Gj(a),Aj(this,a,a.length,2))}};k.bf=function(a){if(nc(this.c,a.H())){if(this.b||this.a){this.a&&Bj(this,this.a);this.b&&Cj(this,this.b);var b=this.f;b.beginPath();Ej(this,a.Mb(),0,a.Db(),a.va());this.a&&b.fill();this.b&&b.stroke()}""!==this.g&&(a=Md(a),Aj(this,a,2,2))}};
+k.af=function(a){if(nc(this.c,a.H())){if(this.b||this.a){this.a&&Bj(this,this.a);this.b&&Cj(this,this.b);var b=this.f,c=Hj(a),d=0,e=a.i,f=a.va(),g,h;g=0;for(h=e.length;g<h;++g){var l=e[g];b.beginPath();d=Ej(this,c,d,l,f);this.a&&b.fill();this.b&&b.stroke()}}""!==this.g&&(a=Ij(a),Aj(this,a,a.length,2))}};function Bj(a,b){var c=a.f,d=a.Y;d?d.fillStyle!=b.fillStyle&&(d.fillStyle=c.fillStyle=b.fillStyle):(c.fillStyle=b.fillStyle,a.Y={fillStyle:b.fillStyle})}
+function Cj(a,b){var c=a.f,d=a.Ra;d?(d.lineCap!=b.lineCap&&(d.lineCap=c.lineCap=b.lineCap),hg&&!pb(d.lineDash,b.lineDash)&&c.setLineDash(d.lineDash=b.lineDash),d.lineJoin!=b.lineJoin&&(d.lineJoin=c.lineJoin=b.lineJoin),d.lineWidth!=b.lineWidth&&(d.lineWidth=c.lineWidth=b.lineWidth),d.miterLimit!=b.miterLimit&&(d.miterLimit=c.miterLimit=b.miterLimit),d.strokeStyle!=b.strokeStyle&&(d.strokeStyle=c.strokeStyle=b.strokeStyle)):(c.lineCap=b.lineCap,hg&&c.setLineDash(b.lineDash),c.lineJoin=b.lineJoin,c.lineWidth=
+b.lineWidth,c.miterLimit=b.miterLimit,c.strokeStyle=b.strokeStyle,a.Ra={lineCap:b.lineCap,lineDash:b.lineDash,lineJoin:b.lineJoin,lineWidth:b.lineWidth,miterLimit:b.miterLimit,strokeStyle:b.strokeStyle})}
+k.Sb=function(a,b){if(a){var c=a.b;this.a={fillStyle:xe(c?c:ej)}}else this.a=null;if(b){var c=b.b,d=b.f,e=b.g,f=b.c,g=b.a,h=b.i;this.b={lineCap:void 0!==d?d:"round",lineDash:e?e:fj,lineJoin:void 0!==f?f:"round",lineWidth:this.A*(void 0!==g?g:1),miterLimit:void 0!==h?h:10,strokeStyle:ve(c?c:gj)}}else this.b=null};
+k.Tb=function(a){if(a){var b=a.Yb(),c=a.jc(1),d=a.Ia(),e=a.Fb();this.R=b[0];this.ya=b[1];this.Ba=e[1];this.i=c;this.v=a.v;this.za=d[0];this.qa=d[1];this.Gb=a.U;this.ta=a.j;this.l=a.i;this.Aa=a.C;this.S=e[0]}else this.i=null};
+k.Vb=function(a){if(a){var b=a.b;b?(b=b.b,this.o={fillStyle:xe(b?b:ej)}):this.o=null;var c=a.l;if(c){var b=c.b,d=c.f,e=c.g,f=c.c,g=c.a,c=c.i;this.s={lineCap:void 0!==d?d:"round",lineDash:e?e:fj,lineJoin:void 0!==f?f:"round",lineWidth:void 0!==g?g:1,miterLimit:void 0!==c?c:10,strokeStyle:ve(b?b:gj)}}else this.s=null;var b=a.g,d=a.f,e=a.c,f=a.i,g=a.a,c=a.Ha(),h=a.o;a=a.j;this.T={font:void 0!==b?b:"10px sans-serif",textAlign:void 0!==h?h:"center",textBaseline:void 0!==a?a:"middle"};this.g=void 0!==c?
+c:"";this.Sa=void 0!==d?this.A*d:0;this.qb=void 0!==e?this.A*e:0;this.C=void 0!==f?f:0;this.j=this.A*(void 0!==g?g:1)}else this.g=""};function Jj(a){th.call(this,a);this.R=Xc()}y(Jj,th);
+Jj.prototype.i=function(a,b,c){Kj(this,"precompose",c,a,void 0);var d=this.f?this.f.a():null;if(d){var e=b.extent,f=void 0!==e;if(f){var g=a.pixelRatio,h=a.size[0]*g,l=a.size[1]*g,m=a.viewState.rotation,n=fc(e),p=ec(e),q=dc(e),e=cc(e);sh(a.coordinateToPixelMatrix,n,n);sh(a.coordinateToPixelMatrix,p,p);sh(a.coordinateToPixelMatrix,q,q);sh(a.coordinateToPixelMatrix,e,e);c.save();hj(c,-m,h/2,l/2);c.beginPath();c.moveTo(n[0]*g,n[1]*g);c.lineTo(p[0]*g,p[1]*g);c.lineTo(q[0]*g,q[1]*g);c.lineTo(e[0]*g,e[1]*
+g);c.clip();hj(c,m,h/2,l/2)}g=this.s;h=c.globalAlpha;c.globalAlpha=b.opacity;c.drawImage(d,0,0,+d.width,+d.height,Math.round(g[12]),Math.round(g[13]),Math.round(d.width*g[0]),Math.round(d.height*g[5]));c.globalAlpha=h;f&&c.restore()}Lj(this,c,a)};
+function Kj(a,b,c,d,e){var f=a.a;if(ab(f,b)){var g=d.size[0]*d.pixelRatio,h=d.size[1]*d.pixelRatio,l=d.viewState.rotation;hj(c,-l,g/2,h/2);a=void 0!==e?e:Mj(a,d,0);a=new yj(c,d.pixelRatio,d.extent,a,d.viewState.rotation);f.b(new lh(b,f,a,d,c,null));hj(c,l,g/2,h/2)}}function Lj(a,b,c,d){Kj(a,"postcompose",b,c,d)}function Mj(a,b,c){var d=b.viewState,e=b.pixelRatio;return qh(a.R,e*b.size[0]/2,e*b.size[1]/2,e/d.resolution,-e/d.resolution,-d.rotation,-d.center[0]+c,-d.center[1])};var Nj=["Polygon","LineString","Image","Text"];function Oj(a,b,c){this.qa=a;this.T=b;this.f=null;this.c=0;this.resolution=c;this.Ba=this.ya=null;this.a=[];this.coordinates=[];this.Ra=Xc();this.b=[];this.Y=[];this.ia=Xc();this.za=Xc()}y(Oj,kh);
+function Pj(a,b,c,d,e,f){var g=a.coordinates.length,h=a.df(),l=[b[c],b[c+1]],m=[NaN,NaN],n=!0,p,q,r;for(p=c+e;p<d;p+=e)m[0]=b[p],m[1]=b[p+1],r=Vb(h,m),r!==q?(n&&(a.coordinates[g++]=l[0],a.coordinates[g++]=l[1]),a.coordinates[g++]=m[0],a.coordinates[g++]=m[1],n=!1):1===r?(a.coordinates[g++]=m[0],a.coordinates[g++]=m[1],n=!1):n=!0,l[0]=m[0],l[1]=m[1],q=r;p===c+e&&(a.coordinates[g++]=l[0],a.coordinates[g++]=l[1]);f&&(a.coordinates[g++]=b[c],a.coordinates[g++]=b[c+1]);return g}
+function Qj(a,b){a.ya=[0,b,0];a.a.push(a.ya);a.Ba=[0,b,0];a.b.push(a.Ba)}
+function Rj(a,b,c,d,e,f,g,h,l){var m;rh(d,a.Ra)?m=a.Y:(m=gd(a.coordinates,0,a.coordinates.length,2,d,a.Y),$c(a.Ra,d));d=!Ha(f);var n=0,p=g.length,q,r,u=a.ia;a=a.za;for(var x,v,D,A;n<p;){var z=g[n],F,N,K,X;switch(z[0]){case 0:q=z[1];d&&f[w(q).toString()]||!q.W()?n=z[2]:void 0===l||nc(l,q.W().H())?++n:n=z[2];break;case 1:b.beginPath();++n;break;case 2:q=z[1];r=m[q];z=m[q+1];D=m[q+2]-r;q=m[q+3]-z;b.arc(r,z,Math.sqrt(D*D+q*q),0,2*Math.PI,!0);++n;break;case 3:b.closePath();++n;break;case 4:q=z[1];r=z[2];
+F=z[3];K=z[4]*c;var oa=z[5]*c,H=z[6];N=z[7];var ya=z[8],Ua=z[9];D=z[11];A=z[12];var Xa=z[13],Va=z[14];for(z[10]&&(D+=e);q<r;q+=2){z=m[q]-K;X=m[q+1]-oa;Xa&&(z=Math.round(z),X=Math.round(X));if(1!=A||0!==D){var Aa=z+K,Qb=X+oa;qh(u,Aa,Qb,A,A,D,-Aa,-Qb);b.transform(u[0],u[1],u[4],u[5],u[12],u[13])}Aa=b.globalAlpha;1!=N&&(b.globalAlpha=Aa*N);var Qb=Va+ya>F.width?F.width-ya:Va,Nb=H+Ua>F.height?F.height-Ua:H;b.drawImage(F,ya,Ua,Qb,Nb,z,X,Qb*c,Nb*c);1!=N&&(b.globalAlpha=Aa);if(1!=A||0!==D)cd(u,a),b.transform(a[0],
+a[1],a[4],a[5],a[12],a[13])}++n;break;case 5:q=z[1];r=z[2];K=z[3];oa=z[4]*c;H=z[5]*c;D=z[6];A=z[7]*c;F=z[8];for(N=z[9];q<r;q+=2){z=m[q]+oa;X=m[q+1]+H;if(1!=A||0!==D)qh(u,z,X,A,A,D,-z,-X),b.transform(u[0],u[1],u[4],u[5],u[12],u[13]);ya=K.split("\n");Ua=ya.length;1<Ua?(Xa=Math.round(1.5*b.measureText("M").width),X-=(Ua-1)/2*Xa):Xa=0;for(Va=0;Va<Ua;Va++)Aa=ya[Va],N&&b.strokeText(Aa,z,X),F&&b.fillText(Aa,z,X),X+=Xa;if(1!=A||0!==D)cd(u,a),b.transform(a[0],a[1],a[4],a[5],a[12],a[13])}++n;break;case 6:if(void 0!==
+h&&(q=z[1],q=h(q)))return q;++n;break;case 7:b.fill();++n;break;case 8:q=z[1];r=z[2];z=m[q];X=m[q+1];D=z+.5|0;A=X+.5|0;if(D!==x||A!==v)b.moveTo(z,X),x=D,v=A;for(q+=2;q<r;q+=2)if(z=m[q],X=m[q+1],D=z+.5|0,A=X+.5|0,q==r-2||D!==x||A!==v)b.lineTo(z,X),x=D,v=A;++n;break;case 9:b.fillStyle=z[1];++n;break;case 10:x=void 0!==z[7]?z[7]:!0;v=z[2];b.strokeStyle=z[1];b.lineWidth=x?v*c:v;b.lineCap=z[3];b.lineJoin=z[4];b.miterLimit=z[5];hg&&b.setLineDash(z[6]);v=x=NaN;++n;break;case 11:b.font=z[1];b.textAlign=z[2];
+b.textBaseline=z[3];++n;break;case 12:b.stroke();++n;break;default:++n}}}Oj.prototype.Pa=function(a,b,c,d,e){Rj(this,a,b,c,d,e,this.a,void 0)};function Sj(a){var b=a.b;b.reverse();var c,d=b.length,e,f,g=-1;for(c=0;c<d;++c)if(e=b[c],f=e[0],6==f)g=c;else if(0==f){e[2]=c;e=a.b;for(f=c;g<f;){var h=e[g];e[g]=e[f];e[f]=h;++g;--f}g=-1}}function Tj(a,b){a.ya[2]=a.a.length;a.ya=null;a.Ba[2]=a.b.length;a.Ba=null;var c=[6,b];a.a.push(c);a.b.push(c)}Oj.prototype.ke=na;Oj.prototype.df=function(){return this.T};
+function Uj(a,b,c){Oj.call(this,a,b,c);this.o=this.S=null;this.R=this.D=this.C=this.A=this.U=this.v=this.s=this.j=this.l=this.i=this.g=void 0}y(Uj,Oj);Uj.prototype.uc=function(a,b){if(this.o){Qj(this,b);var c=a.la(),d=this.coordinates.length,c=Pj(this,c,0,c.length,a.va(),!1);this.a.push([4,d,c,this.o,this.g,this.i,this.l,this.j,this.s,this.v,this.U,this.A,this.C,this.D,this.R]);this.b.push([4,d,c,this.S,this.g,this.i,this.l,this.j,this.s,this.v,this.U,this.A,this.C,this.D,this.R]);Tj(this,b)}};
+Uj.prototype.tc=function(a,b){if(this.o){Qj(this,b);var c=a.la(),d=this.coordinates.length,c=Pj(this,c,0,c.length,a.va(),!1);this.a.push([4,d,c,this.o,this.g,this.i,this.l,this.j,this.s,this.v,this.U,this.A,this.C,this.D,this.R]);this.b.push([4,d,c,this.S,this.g,this.i,this.l,this.j,this.s,this.v,this.U,this.A,this.C,this.D,this.R]);Tj(this,b)}};Uj.prototype.ke=function(){Sj(this);this.i=this.g=void 0;this.o=this.S=null;this.R=this.D=this.A=this.U=this.v=this.s=this.j=this.C=this.l=void 0};
+Uj.prototype.Tb=function(a){var b=a.Yb(),c=a.Fb(),d=a.pe(1),e=a.jc(1),f=a.Ia();this.g=b[0];this.i=b[1];this.S=d;this.o=e;this.l=c[1];this.j=a.v;this.s=f[0];this.v=f[1];this.U=a.U;this.A=a.j;this.C=a.i;this.D=a.C;this.R=c[0]};function Vj(a,b,c){Oj.call(this,a,b,c);this.g={fd:void 0,ad:void 0,bd:null,cd:void 0,dd:void 0,ed:void 0,nf:0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}y(Vj,Oj);
+function Wj(a,b,c,d,e){var f=a.coordinates.length;b=Pj(a,b,c,d,e,!1);f=[8,f,b];a.a.push(f);a.b.push(f);return d}k=Vj.prototype;k.df=function(){this.f||(this.f=Pb(this.T),0<this.c&&Ob(this.f,this.resolution*(this.c+1)/2,this.f));return this.f};
+function Xj(a){var b=a.g,c=b.strokeStyle,d=b.lineCap,e=b.lineDash,f=b.lineJoin,g=b.lineWidth,h=b.miterLimit;b.fd==c&&b.ad==d&&pb(b.bd,e)&&b.cd==f&&b.dd==g&&b.ed==h||(b.nf!=a.coordinates.length&&(a.a.push([12]),b.nf=a.coordinates.length),a.a.push([10,c,g,d,f,h,e],[1]),b.fd=c,b.ad=d,b.bd=e,b.cd=f,b.dd=g,b.ed=h)}
+k.hd=function(a,b){var c=this.g,d=c.lineWidth;void 0!==c.strokeStyle&&void 0!==d&&(Xj(this),Qj(this,b),this.b.push([10,c.strokeStyle,c.lineWidth,c.lineCap,c.lineJoin,c.miterLimit,c.lineDash],[1]),c=a.la(),Wj(this,c,0,c.length,a.va()),this.b.push([12]),Tj(this,b))};
+k.$e=function(a,b){var c=this.g,d=c.lineWidth;if(void 0!==c.strokeStyle&&void 0!==d){Xj(this);Qj(this,b);this.b.push([10,c.strokeStyle,c.lineWidth,c.lineCap,c.lineJoin,c.miterLimit,c.lineDash],[1]);var c=a.Db(),d=a.la(),e=a.va(),f=0,g,h;g=0;for(h=c.length;g<h;++g)f=Wj(this,d,f,c[g],e);this.b.push([12]);Tj(this,b)}};k.ke=function(){this.g.nf!=this.coordinates.length&&this.a.push([12]);Sj(this);this.g=null};
+k.Sb=function(a,b){var c=b.b;this.g.strokeStyle=ve(c?c:gj);c=b.f;this.g.lineCap=void 0!==c?c:"round";c=b.g;this.g.lineDash=c?c:fj;c=b.c;this.g.lineJoin=void 0!==c?c:"round";c=b.a;this.g.lineWidth=void 0!==c?c:1;c=b.i;this.g.miterLimit=void 0!==c?c:10;this.g.lineWidth>this.c&&(this.c=this.g.lineWidth,this.f=null)};
+function Yj(a,b,c){Oj.call(this,a,b,c);this.g={ug:void 0,fd:void 0,ad:void 0,bd:null,cd:void 0,dd:void 0,ed:void 0,fillStyle:void 0,strokeStyle:void 0,lineCap:void 0,lineDash:null,lineJoin:void 0,lineWidth:void 0,miterLimit:void 0}}y(Yj,Oj);
+function Zj(a,b,c,d,e){var f=a.g,g=[1];a.a.push(g);a.b.push(g);var h,g=0;for(h=d.length;g<h;++g){var l=d[g],m=a.coordinates.length;c=Pj(a,b,c,l,e,!0);c=[8,m,c];m=[3];a.a.push(c,m);a.b.push(c,m);c=l}b=[7];a.b.push(b);void 0!==f.fillStyle&&a.a.push(b);void 0!==f.strokeStyle&&(f=[12],a.a.push(f),a.b.push(f));return c}k=Yj.prototype;
+k.Rd=function(a,b){var c=this.g,d=c.strokeStyle;if(void 0!==c.fillStyle||void 0!==d){ak(this);Qj(this,b);this.b.push([9,ve(ej)]);void 0!==c.strokeStyle&&this.b.push([10,c.strokeStyle,c.lineWidth,c.lineCap,c.lineJoin,c.miterLimit,c.lineDash]);var e=a.la(),d=this.coordinates.length;Pj(this,e,0,e.length,a.va(),!1);e=[1];d=[2,d];this.a.push(e,d);this.b.push(e,d);d=[7];this.b.push(d);void 0!==c.fillStyle&&this.a.push(d);void 0!==c.strokeStyle&&(c=[12],this.a.push(c),this.b.push(c));Tj(this,b)}};
+k.bf=function(a,b){var c=this.g,d=c.strokeStyle;if(void 0!==c.fillStyle||void 0!==d)ak(this),Qj(this,b),this.b.push([9,ve(ej)]),void 0!==c.strokeStyle&&this.b.push([10,c.strokeStyle,c.lineWidth,c.lineCap,c.lineJoin,c.miterLimit,c.lineDash]),c=a.Db(),d=a.Mb(),Zj(this,d,0,c,a.va()),Tj(this,b)};
+k.af=function(a,b){var c=this.g,d=c.strokeStyle;if(void 0!==c.fillStyle||void 0!==d){ak(this);Qj(this,b);this.b.push([9,ve(ej)]);void 0!==c.strokeStyle&&this.b.push([10,c.strokeStyle,c.lineWidth,c.lineCap,c.lineJoin,c.miterLimit,c.lineDash]);var c=a.i,d=Hj(a),e=a.va(),f=0,g,h;g=0;for(h=c.length;g<h;++g)f=Zj(this,d,f,c[g],e);Tj(this,b)}};k.ke=function(){Sj(this);this.g=null;var a=this.qa;if(0!==a){var b=this.coordinates,c,d;c=0;for(d=b.length;c<d;++c)b[c]=a*Math.round(b[c]/a)}};
+k.df=function(){this.f||(this.f=Pb(this.T),0<this.c&&Ob(this.f,this.resolution*(this.c+1)/2,this.f));return this.f};
+k.Sb=function(a,b){var c=this.g;if(a){var d=a.b;c.fillStyle=xe(d?d:ej)}else c.fillStyle=void 0;b?(d=b.b,c.strokeStyle=ve(d?d:gj),d=b.f,c.lineCap=void 0!==d?d:"round",d=b.g,c.lineDash=d?d.slice():fj,d=b.c,c.lineJoin=void 0!==d?d:"round",d=b.a,c.lineWidth=void 0!==d?d:1,d=b.i,c.miterLimit=void 0!==d?d:10,c.lineWidth>this.c&&(this.c=c.lineWidth,this.f=null)):(c.strokeStyle=void 0,c.lineCap=void 0,c.lineDash=null,c.lineJoin=void 0,c.lineWidth=void 0,c.miterLimit=void 0)};
+function ak(a){var b=a.g,c=b.fillStyle,d=b.strokeStyle,e=b.lineCap,f=b.lineDash,g=b.lineJoin,h=b.lineWidth,l=b.miterLimit;void 0!==c&&b.ug!=c&&(a.a.push([9,c]),b.ug=b.fillStyle);void 0===d||b.fd==d&&b.ad==e&&b.bd==f&&b.cd==g&&b.dd==h&&b.ed==l||(a.a.push([10,d,h,e,g,l,f]),b.fd=d,b.ad=e,b.bd=f,b.cd=g,b.dd=h,b.ed=l)}function bk(a,b,c){Oj.call(this,a,b,c);this.D=this.C=this.A=null;this.o="";this.U=this.v=this.s=this.j=0;this.l=this.i=this.g=null}y(bk,Oj);
+function ck(a,b,c,d,e){if(""!==a.o&&a.l&&(a.g||a.i)){if(a.g){var f=a.g,g=a.A;if(!g||g.fillStyle!=f.fillStyle){var h=[9,f.fillStyle];a.a.push(h);a.b.push(h);g?g.fillStyle=f.fillStyle:a.A={fillStyle:f.fillStyle}}}a.i&&(f=a.i,g=a.C,g&&g.lineCap==f.lineCap&&g.lineDash==f.lineDash&&g.lineJoin==f.lineJoin&&g.lineWidth==f.lineWidth&&g.miterLimit==f.miterLimit&&g.strokeStyle==f.strokeStyle||(h=[10,f.strokeStyle,f.lineWidth,f.lineCap,f.lineJoin,f.miterLimit,f.lineDash,!1],a.a.push(h),a.b.push(h),g?(g.lineCap=
+f.lineCap,g.lineDash=f.lineDash,g.lineJoin=f.lineJoin,g.lineWidth=f.lineWidth,g.miterLimit=f.miterLimit,g.strokeStyle=f.strokeStyle):a.C={lineCap:f.lineCap,lineDash:f.lineDash,lineJoin:f.lineJoin,lineWidth:f.lineWidth,miterLimit:f.miterLimit,strokeStyle:f.strokeStyle}));f=a.l;g=a.D;g&&g.font==f.font&&g.textAlign==f.textAlign&&g.textBaseline==f.textBaseline||(h=[11,f.font,f.textAlign,f.textBaseline],a.a.push(h),a.b.push(h),g?(g.font=f.font,g.textAlign=f.textAlign,g.textBaseline=f.textBaseline):a.D=
+{font:f.font,textAlign:f.textAlign,textBaseline:f.textBaseline});Qj(a,e);f=a.coordinates.length;b=Pj(a,b,0,c,d,!1);b=[5,f,b,a.o,a.j,a.s,a.v,a.U,!!a.g,!!a.i];a.a.push(b);a.b.push(b);Tj(a,e)}}
+bk.prototype.Vb=function(a){if(a){var b=a.b;b?(b=b.b,b=xe(b?b:ej),this.g?this.g.fillStyle=b:this.g={fillStyle:b}):this.g=null;var c=a.l;if(c){var b=c.b,d=c.f,e=c.g,f=c.c,g=c.a,c=c.i,d=void 0!==d?d:"round",e=e?e.slice():fj,f=void 0!==f?f:"round",g=void 0!==g?g:1,c=void 0!==c?c:10,b=ve(b?b:gj);if(this.i){var h=this.i;h.lineCap=d;h.lineDash=e;h.lineJoin=f;h.lineWidth=g;h.miterLimit=c;h.strokeStyle=b}else this.i={lineCap:d,lineDash:e,lineJoin:f,lineWidth:g,miterLimit:c,strokeStyle:b}}else this.i=null;
+var l=a.g,b=a.f,d=a.c,e=a.i,g=a.a,c=a.Ha(),f=a.o,h=a.j;a=void 0!==l?l:"10px sans-serif";f=void 0!==f?f:"center";h=void 0!==h?h:"middle";this.l?(l=this.l,l.font=a,l.textAlign=f,l.textBaseline=h):this.l={font:a,textAlign:f,textBaseline:h};this.o=void 0!==c?c:"";this.j=void 0!==b?b:0;this.s=void 0!==d?d:0;this.v=void 0!==e?e:0;this.U=void 0!==g?g:1}else this.o=""};function dk(a,b,c,d){this.o=a;this.g=b;this.l=c;this.f=d;this.a={};this.c=Oe(1,1);this.i=Xc()}
+function ek(a){for(var b in a.a){var c=a.a[b],d;for(d in c)c[d].ke()}}dk.prototype.ra=function(a,b,c,d,e){var f=this.i;qh(f,.5,.5,1/b,-1/b,-c,-a[0],-a[1]);var g=this.c;g.clearRect(0,0,1,1);var h;void 0!==this.f&&(h=Lb(),Mb(h,a),Ob(h,b*this.f,h));return fk(this,g,f,c,d,function(a){if(0<g.getImageData(0,0,1,1).data[3]){if(a=e(a))return a;g.clearRect(0,0,1,1)}},h)};
+dk.prototype.b=function(a,b){var c=void 0!==a?a.toString():"0",d=this.a[c];void 0===d&&(d={},this.a[c]=d);c=d[b];void 0===c&&(c=new gk[b](this.o,this.g,this.l),d[b]=c);return c};dk.prototype.Ya=function(){return Ha(this.a)};
+dk.prototype.Pa=function(a,b,c,d,e,f){var g=Object.keys(this.a).map(Number);g.sort(ib);var h=this.g,l=h[0],m=h[1],n=h[2],h=h[3],l=[l,m,l,h,n,h,n,m];gd(l,0,8,2,c,l);a.save();a.beginPath();a.moveTo(l[0],l[1]);a.lineTo(l[2],l[3]);a.lineTo(l[4],l[5]);a.lineTo(l[6],l[7]);a.closePath();a.clip();f=f?f:Nj;for(var p,q,l=0,m=g.length;l<m;++l)for(p=this.a[g[l].toString()],n=0,h=f.length;n<h;++n)q=p[f[n]],void 0!==q&&q.Pa(a,b,c,d,e);a.restore()};
+function fk(a,b,c,d,e,f,g){var h=Object.keys(a.a).map(Number);h.sort(function(a,b){return b-a});var l,m,n,p,q;l=0;for(m=h.length;l<m;++l)for(p=a.a[h[l].toString()],n=Nj.length-1;0<=n;--n)if(q=p[Nj[n]],void 0!==q&&(q=Rj(q,b,1,c,d,e,q.b,f,g)))return q}var gk={Image:Uj,LineString:Vj,Polygon:Yj,Text:bk};function hk(a,b,c,d){this.g=a;this.b=b;this.c=c;this.f=d}k=hk.prototype;k.get=function(a){return this.f[a]};k.Db=function(){return this.c};k.H=function(){this.a||(this.a="Point"===this.g?Xb(this.b):Yb(this.b,0,this.b.length,2));return this.a};k.Mb=function(){return this.b};k.la=hk.prototype.Mb;k.W=function(){return this};k.Nm=function(){return this.f};k.od=hk.prototype.W;k.va=function(){return 2};k.ec=na;k.X=function(){return this.g};function ik(a,b){return w(a)-w(b)}function jk(a,b){var c=.5*a/b;return c*c}function lk(a,b,c,d,e,f){var g=!1,h,l;if(h=c.a)l=h.td(),2==l||3==l?h.Xf(e,f):(0==l&&h.load(),h.pf(e,f),g=!0);if(e=(0,c.g)(b))d=e.od(d),(0,mk[d.X()])(a,d,c,b);return g}
+var mk={Point:function(a,b,c,d){var e=c.a;if(e){if(2!=e.td())return;var f=a.b(c.b,"Image");f.Tb(e);f.uc(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),ck(a,b.la(),2,2,d)},LineString:function(a,b,c,d){var e=c.f;if(e){var f=a.b(c.b,"LineString");f.Sb(null,e);f.hd(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),ck(a,Fj(b),2,2,d)},Polygon:function(a,b,c,d){var e=c.c,f=c.f;if(e||f){var g=a.b(c.b,"Polygon");g.Sb(e,f);g.bf(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),ck(a,Md(b),2,2,d)},MultiPoint:function(a,b,c,d){var e=
+c.a;if(e){if(2!=e.td())return;var f=a.b(c.b,"Image");f.Tb(e);f.tc(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),c=b.la(),ck(a,c,c.length,b.va(),d)},MultiLineString:function(a,b,c,d){var e=c.f;if(e){var f=a.b(c.b,"LineString");f.Sb(null,e);f.$e(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),b=Gj(b),ck(a,b,b.length,2,d)},MultiPolygon:function(a,b,c,d){var e=c.c,f=c.f;if(f||e){var g=a.b(c.b,"Polygon");g.Sb(e,f);g.af(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),b=Ij(b),ck(a,b,b.length,2,d)},GeometryCollection:function(a,
+b,c,d){b=b.c;var e,f;e=0;for(f=b.length;e<f;++e)(0,mk[b[e].X()])(a,b[e],c,d)},Circle:function(a,b,c,d){var e=c.c,f=c.f;if(e||f){var g=a.b(c.b,"Polygon");g.Sb(e,f);g.Rd(b,d)}if(e=c.Ha())a=a.b(c.b,"Text"),a.Vb(e),ck(a,b.rd(),2,2,d)}};function nk(a,b,c,d,e,f){this.c=void 0!==f?f:null;oh.call(this,a,b,c,void 0!==f?0:2,d);this.g=e}y(nk,oh);nk.prototype.i=function(a){this.state=a?3:2;ph(this)};nk.prototype.load=function(){0==this.state&&(this.state=1,ph(this),this.c(this.i.bind(this)))};nk.prototype.a=function(){return this.g};var ok,pk=pa.navigator,qk=pa.chrome,rk=-1<pk.userAgent.indexOf("OPR"),sk=-1<pk.userAgent.indexOf("Edge");ok=!(!pk.userAgent.match("CriOS")&&null!==qk&&void 0!==qk&&"Google Inc."===pk.vendor&&0==rk&&0==sk);function tk(a,b,c,d){var e=Rc(c,b,a);c=b.getPointResolution(d,c);b=b.$b();void 0!==b&&(c*=b);b=a.$b();void 0!==b&&(c/=b);a=a.getPointResolution(c,e)/c;isFinite(a)&&0<a&&(c/=a);return c}function uk(a,b,c,d){a=c-a;b=d-b;var e=Math.sqrt(a*a+b*b);return[Math.round(c+a/e),Math.round(d+b/e)]}
+function vk(a,b,c,d,e,f,g,h,l,m,n){var p=Oe(Math.round(c*a),Math.round(c*b));if(0===l.length)return p.canvas;p.scale(c,c);var q=Lb();l.forEach(function(a){ac(q,a.extent)});var r=Oe(Math.round(c*ic(q)/d),Math.round(c*jc(q)/d)),u=c/d;l.forEach(function(a){r.drawImage(a.image,m,m,a.image.width-2*m,a.image.height-2*m,(a.extent[0]-q[0])*u,-(a.extent[3]-q[3])*u,ic(a.extent)*u,jc(a.extent)*u)});var x=fc(g);h.f.forEach(function(a){var b=a.source,e=a.target,g=b[1][0],h=b[1][1],l=b[2][0],m=b[2][1];a=(e[0][0]-
+x[0])/f;var n=-(e[0][1]-x[1])/f,u=(e[1][0]-x[0])/f,H=-(e[1][1]-x[1])/f,ya=(e[2][0]-x[0])/f,Ua=-(e[2][1]-x[1])/f,e=b[0][0],b=b[0][1],g=g-e,h=h-b,l=l-e,m=m-b;a:{g=[[g,h,0,0,u-a],[l,m,0,0,ya-a],[0,0,g,h,H-n],[0,0,l,m,Ua-n]];h=g.length;for(l=0;l<h;l++){for(var m=l,Xa=Math.abs(g[l][l]),Va=l+1;Va<h;Va++){var Aa=Math.abs(g[Va][l]);Aa>Xa&&(Xa=Aa,m=Va)}if(0===Xa){g=null;break a}Xa=g[m];g[m]=g[l];g[l]=Xa;for(m=l+1;m<h;m++)for(Xa=-g[m][l]/g[l][l],Va=l;Va<h+1;Va++)g[m][Va]=l==Va?0:g[m][Va]+Xa*g[l][Va]}l=Array(h);
+for(m=h-1;0<=m;m--)for(l[m]=g[m][h]/g[m][m],Xa=m-1;0<=Xa;Xa--)g[Xa][h]-=g[Xa][m]*l[m];g=l}g&&(p.save(),p.beginPath(),ok?(l=(a+u+ya)/3,m=(n+H+Ua)/3,h=uk(l,m,a,n),u=uk(l,m,u,H),ya=uk(l,m,ya,Ua),p.moveTo(h[0],h[1]),p.lineTo(u[0],u[1]),p.lineTo(ya[0],ya[1])):(p.moveTo(a,n),p.lineTo(u,H),p.lineTo(ya,Ua)),p.closePath(),p.clip(),p.transform(g[0],g[2],g[1],g[3],a,n),p.translate(q[0]-e,q[3]-b),p.scale(d/c,-d/c),p.drawImage(r.canvas,0,0),p.restore())});n&&(p.save(),p.strokeStyle="black",p.lineWidth=1,h.f.forEach(function(a){var b=
+a.target;a=(b[0][0]-x[0])/f;var c=-(b[0][1]-x[1])/f,d=(b[1][0]-x[0])/f,e=-(b[1][1]-x[1])/f,g=(b[2][0]-x[0])/f,b=-(b[2][1]-x[1])/f;p.beginPath();p.moveTo(a,c);p.lineTo(d,e);p.lineTo(g,b);p.closePath();p.stroke()}),p.restore());return p.canvas};function wk(a,b,c,d,e){this.g=a;this.c=b;var f={},g=Pc(this.c,this.g);this.a=function(a){var b=a[0]+"/"+a[1];f[b]||(f[b]=g(a));return f[b]};this.i=d;this.s=e*e;this.f=[];this.o=!1;this.j=this.g.a&&!!d&&!!this.g.H()&&ic(d)==ic(this.g.H());this.b=this.g.H()?ic(this.g.H()):null;this.l=this.c.H()?ic(this.c.H()):null;a=fc(c);b=ec(c);d=dc(c);c=cc(c);e=this.a(a);var h=this.a(b),l=this.a(d),m=this.a(c);xk(this,a,b,d,c,e,h,l,m,10);if(this.o){var n=Infinity;this.f.forEach(function(a){n=Math.min(n,a.source[0][0],
+a.source[1][0],a.source[2][0])});this.f.forEach(function(a){if(Math.max(a.source[0][0],a.source[1][0],a.source[2][0])-n>this.b/2){var b=[[a.source[0][0],a.source[0][1]],[a.source[1][0],a.source[1][1]],[a.source[2][0],a.source[2][1]]];b[0][0]-n>this.b/2&&(b[0][0]-=this.b);b[1][0]-n>this.b/2&&(b[1][0]-=this.b);b[2][0]-n>this.b/2&&(b[2][0]-=this.b);Math.max(b[0][0],b[1][0],b[2][0])-Math.min(b[0][0],b[1][0],b[2][0])<this.b/2&&(a.source=b)}},this)}f={}}
+function xk(a,b,c,d,e,f,g,h,l,m){var n=Kb([f,g,h,l]),p=a.b?ic(n)/a.b:null,q=a.g.a&&.5<p&&1>p,r=!1;if(0<m){if(a.c.g&&a.l)var u=Kb([b,c,d,e]),r=r|.25<ic(u)/a.l;!q&&a.g.g&&p&&(r|=.25<p)}if(r||!a.i||nc(n,a.i)){if(!(r||isFinite(f[0])&&isFinite(f[1])&&isFinite(g[0])&&isFinite(g[1])&&isFinite(h[0])&&isFinite(h[1])&&isFinite(l[0])&&isFinite(l[1])))if(0<m)r=!0;else return;if(0<m&&(r||(p=a.a([(b[0]+d[0])/2,(b[1]+d[1])/2]),n=q?(xa(f[0],a.b)+xa(h[0],a.b))/2-xa(p[0],a.b):(f[0]+h[0])/2-p[0],p=(f[1]+h[1])/2-p[1],
+r=n*n+p*p>a.s),r)){Math.abs(b[0]-d[0])<=Math.abs(b[1]-d[1])?(q=[(c[0]+d[0])/2,(c[1]+d[1])/2],n=a.a(q),p=[(e[0]+b[0])/2,(e[1]+b[1])/2],r=a.a(p),xk(a,b,c,q,p,f,g,n,r,m-1),xk(a,p,q,d,e,r,n,h,l,m-1)):(q=[(b[0]+c[0])/2,(b[1]+c[1])/2],n=a.a(q),p=[(d[0]+e[0])/2,(d[1]+e[1])/2],r=a.a(p),xk(a,b,q,p,e,f,n,r,l,m-1),xk(a,q,c,d,p,n,g,h,r,m-1));return}if(q){if(!a.j)return;a.o=!0}a.f.push({source:[f,h,l],target:[b,d,e]});a.f.push({source:[f,g,h],target:[b,c,d]})}}
+function yk(a){var b=Lb();a.f.forEach(function(a){a=a.source;Mb(b,a[0]);Mb(b,a[1]);Mb(b,a[2])});return b};function zk(a,b,c,d,e,f){this.v=b;this.s=a.H();var g=b.H(),h=g?mc(c,g):c,g=tk(a,b,kc(h),d);this.o=new wk(a,b,h,this.s,.5*g);this.c=d;this.g=c;a=yk(this.o);this.j=(this.ob=f(a,g,e))?this.ob.f:1;this.Ad=this.i=null;e=2;f=[];this.ob&&(e=0,f=this.ob.l);oh.call(this,c,d,this.j,e,f)}y(zk,oh);zk.prototype.ka=function(){1==this.state&&(Ka(this.Ad),this.Ad=null);oh.prototype.ka.call(this)};zk.prototype.a=function(){return this.i};
+zk.prototype.zd=function(){var a=this.ob.V();2==a&&(this.i=vk(ic(this.g)/this.c,jc(this.g)/this.c,this.j,this.ob.$(),0,this.c,this.g,this.o,[{extent:this.ob.H(),image:this.ob.a()}],0));this.state=a;ph(this)};zk.prototype.load=function(){if(0==this.state){this.state=1;ph(this);var a=this.ob.V();2==a||3==a?this.zd():(this.Ad=B(this.ob,"change",function(){var a=this.ob.V();if(2==a||3==a)Ka(this.Ad),this.Ad=null,this.zd()},this),this.ob.load())}};function Ak(a){jf.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,state:a.state});this.C=void 0!==a.resolutions?a.resolutions:null;this.a=null;this.qa=0}y(Ak,jf);function Bk(a,b){if(a.C){var c=kb(a.C,b,0);b=a.C[c]}return b}
+Ak.prototype.A=function(a,b,c,d){var e=this.f;if(e&&d&&!Oc(e,d)){if(this.a){if(this.qa==this.g&&Oc(this.a.v,d)&&this.a.$()==b&&this.a.f==c&&$b(this.a.H(),a))return this.a;Ta(this.a);this.a=null}this.a=new zk(e,d,a,b,c,function(a,b,c){return this.Mc(a,b,c,e)}.bind(this));this.qa=this.g;return this.a}e&&(d=e);return this.Mc(a,b,c,d)};Ak.prototype.o=function(a){a=a.target;switch(a.V()){case 1:this.b(new Ck(Dk,a));break;case 2:this.b(new Ck(Ek,a));break;case 3:this.b(new Ck(Fk,a))}};
+function Gk(a,b){a.a().src=b}function Ck(a,b){Wa.call(this,a);this.image=b}y(Ck,Wa);var Dk="imageloadstart",Ek="imageloadend",Fk="imageloaderror";function Hk(a){Ak.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions,state:a.state});this.ia=a.canvasFunction;this.T=null;this.Y=0;this.ta=void 0!==a.ratio?a.ratio:1.5}y(Hk,Ak);Hk.prototype.Mc=function(a,b,c,d){b=Bk(this,b);var e=this.T;if(e&&this.Y==this.g&&e.$()==b&&e.f==c&&Ub(e.H(),a))return e;a=a.slice();oc(a,this.ta);(d=this.ia(a,b,c,[ic(a)/b*c,jc(a)/b*c],d))&&(e=new nk(a,b,c,this.l,d));this.T=e;this.Y=this.g;return e};function Ik(a){eb.call(this);this.i=void 0;this.a="geometry";this.c=null;this.l=void 0;this.f=null;B(this,gb(this.a),this.be,this);void 0!==a&&(a instanceof Tc||!a?this.Ua(a):this.G(a))}y(Ik,eb);k=Ik.prototype;k.clone=function(){var a=new Ik(this.O());a.Ec(this.a);var b=this.W();b&&a.Ua(b.clone());(b=this.c)&&a.sf(b);return a};k.W=function(){return this.get(this.a)};k.Xa=function(){return this.i};k.$j=function(){return this.a};k.Jl=function(){return this.c};k.ec=function(){return this.l};k.Kl=function(){this.u()};
+k.be=function(){this.f&&(Ka(this.f),this.f=null);var a=this.W();a&&(this.f=B(a,"change",this.Kl,this));this.u()};k.Ua=function(a){this.set(this.a,a)};k.sf=function(a){this.l=(this.c=a)?Jk(a):void 0;this.u()};k.mc=function(a){this.i=a;this.u()};k.Ec=function(a){Qa(this,gb(this.a),this.be,this);this.a=a;B(this,gb(this.a),this.be,this);this.be()};function Jk(a){if("function"!==typeof a){var b;b=Array.isArray(a)?a:[a];a=function(){return b}}return a};function Kk(a,b,c,d,e){df.call(this,a,b);this.g=Oe();this.l=d;this.c=null;this.f={gd:!1,Tf:null,bi:-1,Uf:-1,yd:null,ui:[]};this.v=e;this.j=c}y(Kk,df);k=Kk.prototype;k.$a=function(){return-1==this.f.Uf?null:this.g.canvas};k.Ul=function(){return this.l};k.ib=function(){return this.j};k.load=function(){0==this.state&&(this.state=1,ef(this),this.v(this,this.j),this.s(null,NaN,null))};k.gi=function(a){this.c=a;this.state=2;ef(this)};k.vf=function(a){this.o=a};k.ki=function(a){this.s=a};var Lk=document.implementation.createDocument("","",null);function Mk(a,b){return Lk.createElementNS(a,b)}function Nk(a,b){return Ok(a,b,[]).join("")}function Ok(a,b,c){if(a.nodeType==Node.CDATA_SECTION_NODE||a.nodeType==Node.TEXT_NODE)b?c.push(String(a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):c.push(a.nodeValue);else for(a=a.firstChild;a;a=a.nextSibling)Ok(a,b,c);return c}function Pk(a){return a instanceof Document}function Qk(a){return a instanceof Node}
+function Rk(a){return(new DOMParser).parseFromString(a,"application/xml")}function Sk(a,b){return function(c,d){var e=a.call(b,c,d);void 0!==e&&mb(d[d.length-1],e)}}function Tk(a,b){return function(c,d){var e=a.call(void 0!==b?b:this,c,d);void 0!==e&&d[d.length-1].push(e)}}function Uk(a,b){return function(c,d){var e=a.call(void 0!==b?b:this,c,d);void 0!==e&&(d[d.length-1]=e)}}
+function Vk(a){return function(b,c){var d=a.call(this,b,c);if(void 0!==d){var e=c[c.length-1],f=b.localName,g;f in e?g=e[f]:g=e[f]=[];g.push(d)}}}function J(a,b){return function(c,d){var e=a.call(this,c,d);void 0!==e&&(d[d.length-1][void 0!==b?b:c.localName]=e)}}function L(a,b){return function(c,d,e){a.call(void 0!==b?b:this,c,d,e);e[e.length-1].node.appendChild(c)}}
+function Wk(a){var b,c;return function(d,e,f){if(!b){b={};var g={};g[d.localName]=a;b[d.namespaceURI]=g;c=Xk(d.localName)}Yk(b,c,e,f)}}function Xk(a,b){return function(c,d,e){c=d[d.length-1].node;d=a;void 0===d&&(d=e);e=b;void 0===b&&(e=c.namespaceURI);return Mk(e,d)}}var Zk=Xk();function $k(a,b){for(var c=b.length,d=Array(c),e=0;e<c;++e)d[e]=a[b[e]];return d}function M(a,b,c){c=void 0!==c?c:{};var d,e;d=0;for(e=a.length;d<e;++d)c[a[d]]=b;return c}
+function al(a,b,c,d){for(b=b.firstElementChild;b;b=b.nextElementSibling){var e=a[b.namespaceURI];void 0!==e&&(e=e[b.localName])&&e.call(d,b,c)}}function O(a,b,c,d,e){d.push(a);al(b,c,d,e);return d.pop()}function Yk(a,b,c,d,e,f){for(var g=(void 0!==e?e:c).length,h,l,m=0;m<g;++m)h=c[m],void 0!==h&&(l=b.call(f,h,d,void 0!==e?e[m]:void 0),void 0!==l&&a[l.namespaceURI][l.localName].call(f,l,h,d))}function bl(a,b,c,d,e,f,g){e.push(a);Yk(b,c,d,e,f,g);e.pop()};function cl(a,b,c,d){return function(e,f,g){var h=new XMLHttpRequest;h.open("GET","function"===typeof a?a(e,f,g):a,!0);"arraybuffer"==b.X()&&(h.responseType="arraybuffer");h.onload=function(){if(200<=h.status&&300>h.status){var a=b.X(),e;"json"==a||"text"==a?e=h.responseText:"xml"==a?(e=h.responseXML)||(e=Rk(h.responseText)):"arraybuffer"==a&&(e=h.response);e&&c.call(this,b.Fa(e,{featureProjection:g}),b.Oa(e))}else d.call(this)}.bind(this);h.send()}}
+function dl(a,b){return cl(a,b,function(a,b){this.vf(b);this.gi(a)},function(){this.state=3;ef(this)})}function el(a,b){return cl(a,b,function(a){this.Jc(a)},na)};function fl(){return[[-Infinity,-Infinity,Infinity,Infinity]]};var gl,hl,il,jl;
+(function(){var a={},b={ja:a};(function(c){if("object"===typeof a&&"undefined"!==typeof b)b.ja=c();else{var d;"undefined"!==typeof window?d=window:"undefined"!==typeof global?d=global:"undefined"!==typeof self?d=self:d=this;d.Tp=c()}})(function(){return function d(a,b,g){function h(m,p){if(!b[m]){if(!a[m]){var q="function"==typeof require&&require;if(!p&&q)return q(m,!0);if(l)return l(m,!0);q=Error("Cannot find module '"+m+"'");throw q.code="MODULE_NOT_FOUND",q;}q=b[m]={ja:{}};a[m][0].call(q.ja,function(b){var d=
+a[m][1][b];return h(d?d:b)},q,q.ja,d,a,b,g)}return b[m].ja}for(var l="function"==typeof require&&require,m=0;m<g.length;m++)h(g[m]);return h}({1:[function(a,b){function f(a,b){if(!(this instanceof f))return new f(a,b);this.Te=Math.max(4,a||9);this.hg=Math.max(2,Math.ceil(.4*this.Te));b&&this.mj(b);this.clear()}function g(a,b){h(a,0,a.children.length,b,a)}function h(a,b,d,e,f){f||(f=x(null));f.ca=Infinity;f.fa=Infinity;f.ea=-Infinity;f.ga=-Infinity;for(var g;b<d;b++)g=a.children[b],l(f,a.Ta?e(g):g);
+return f}function l(a,b){a.ca=Math.min(a.ca,b.ca);a.fa=Math.min(a.fa,b.fa);a.ea=Math.max(a.ea,b.ea);a.ga=Math.max(a.ga,b.ga)}function m(a,b){return a.ca-b.ca}function n(a,b){return a.fa-b.fa}function p(a){return(a.ea-a.ca)*(a.ga-a.fa)}function q(a){return a.ea-a.ca+(a.ga-a.fa)}function r(a,b){return a.ca<=b.ca&&a.fa<=b.fa&&b.ea<=a.ea&&b.ga<=a.ga}function u(a,b){return b.ca<=a.ea&&b.fa<=a.ga&&b.ea>=a.ca&&b.ga>=a.fa}function x(a){return{children:a,height:1,Ta:!0,ca:Infinity,fa:Infinity,ea:-Infinity,
+ga:-Infinity}}function v(a,b,d,e,f){for(var g=[b,d],h;g.length;)d=g.pop(),b=g.pop(),d-b<=e||(h=b+Math.ceil((d-b)/e/2)*e,D(a,h,b,d,f),g.push(b,h,h,d))}b.ja=f;var D=a("quickselect");f.prototype={all:function(){return this.cg(this.data,[])},search:function(a){var b=this.data,d=[],e=this.lb;if(!u(a,b))return d;for(var f=[],g,h,l,m;b;){g=0;for(h=b.children.length;g<h;g++)l=b.children[g],m=b.Ta?e(l):l,u(a,m)&&(b.Ta?d.push(l):r(a,m)?this.cg(l,d):f.push(l));b=f.pop()}return d},load:function(a){if(!a||!a.length)return this;
+if(a.length<this.hg){for(var b=0,d=a.length;b<d;b++)this.Ca(a[b]);return this}a=this.eg(a.slice(),0,a.length-1,0);this.data.children.length?this.data.height===a.height?this.jg(this.data,a):(this.data.height<a.height&&(b=this.data,this.data=a,a=b),this.gg(a,this.data.height-a.height-1,!0)):this.data=a;return this},Ca:function(a){a&&this.gg(a,this.data.height-1);return this},clear:function(){this.data=x([]);return this},remove:function(a,b){if(!a)return this;for(var d=this.data,e=this.lb(a),f=[],g=
+[],h,l,m,n;d||f.length;){d||(d=f.pop(),l=f[f.length-1],h=g.pop(),n=!0);if(d.Ta){a:{m=a;var p=d.children,q=b;if(q){for(var u=0;u<p.length;u++)if(q(m,p[u])){m=u;break a}m=-1}else m=p.indexOf(m)}if(-1!==m){d.children.splice(m,1);f.push(d);this.kj(f);break}}n||d.Ta||!r(d,e)?l?(h++,d=l.children[h],n=!1):d=null:(f.push(d),g.push(h),h=0,l=d,d=d.children[0])}return this},lb:function(a){return a},Ve:m,We:n,toJSON:function(){return this.data},cg:function(a,b){for(var d=[];a;)a.Ta?b.push.apply(b,a.children):
+d.push.apply(d,a.children),a=d.pop();return b},eg:function(a,b,d,e){var f=d-b+1,h=this.Te,l;if(f<=h)return l=x(a.slice(b,d+1)),g(l,this.lb),l;e||(e=Math.ceil(Math.log(f)/Math.log(h)),h=Math.ceil(f/Math.pow(h,e-1)));l=x([]);l.Ta=!1;l.height=e;var f=Math.ceil(f/h),h=f*Math.ceil(Math.sqrt(h)),m,n,p;for(v(a,b,d,h,this.Ve);b<=d;b+=h)for(n=Math.min(b+h-1,d),v(a,b,n,f,this.We),m=b;m<=n;m+=f)p=Math.min(m+f-1,n),l.children.push(this.eg(a,m,p,e-1));g(l,this.lb);return l},jj:function(a,b,d,e){for(var f,g,h,
+l,m,n,q,r;;){e.push(b);if(b.Ta||e.length-1===d)break;q=r=Infinity;f=0;for(g=b.children.length;f<g;f++)h=b.children[f],m=p(h),n=(Math.max(h.ea,a.ea)-Math.min(h.ca,a.ca))*(Math.max(h.ga,a.ga)-Math.min(h.fa,a.fa))-m,n<r?(r=n,q=m<q?m:q,l=h):n===r&&m<q&&(q=m,l=h);b=l||b.children[0]}return b},gg:function(a,b,d){var e=this.lb;d=d?a:e(a);var e=[],f=this.jj(d,this.data,b,e);f.children.push(a);for(l(f,d);0<=b;)if(e[b].children.length>this.Te)this.sj(e,b),b--;else break;this.gj(d,e,b)},sj:function(a,b){var d=
+a[b],e=d.children.length,f=this.hg;this.hj(d,f,e);e=this.ij(d,f,e);e=x(d.children.splice(e,d.children.length-e));e.height=d.height;e.Ta=d.Ta;g(d,this.lb);g(e,this.lb);b?a[b-1].children.push(e):this.jg(d,e)},jg:function(a,b){this.data=x([a,b]);this.data.height=a.height+1;this.data.Ta=!1;g(this.data,this.lb)},ij:function(a,b,d){var e,f,g,l,m,n,q;m=n=Infinity;for(e=b;e<=d-b;e++)f=h(a,0,e,this.lb),g=h(a,e,d,this.lb),l=Math.max(0,Math.min(f.ea,g.ea)-Math.max(f.ca,g.ca))*Math.max(0,Math.min(f.ga,g.ga)-
+Math.max(f.fa,g.fa)),f=p(f)+p(g),l<m?(m=l,q=e,n=f<n?f:n):l===m&&f<n&&(n=f,q=e);return q},hj:function(a,b,d){var e=a.Ta?this.Ve:m,f=a.Ta?this.We:n,g=this.dg(a,b,d,e);b=this.dg(a,b,d,f);g<b&&a.children.sort(e)},dg:function(a,b,d,e){a.children.sort(e);e=this.lb;var f=h(a,0,b,e),g=h(a,d-b,d,e),m=q(f)+q(g),n,p;for(n=b;n<d-b;n++)p=a.children[n],l(f,a.Ta?e(p):p),m+=q(f);for(n=d-b-1;n>=b;n--)p=a.children[n],l(g,a.Ta?e(p):p),m+=q(g);return m},gj:function(a,b,d){for(;0<=d;d--)l(b[d],a)},kj:function(a){for(var b=
+a.length-1,d;0<=b;b--)0===a[b].children.length?0<b?(d=a[b-1].children,d.splice(d.indexOf(a[b]),1)):this.clear():g(a[b],this.lb)},mj:function(a){var b=["return a"," - b",";"];this.Ve=new Function("a","b",b.join(a[0]));this.We=new Function("a","b",b.join(a[1]));this.lb=new Function("a","return {minX: a"+a[0]+", minY: a"+a[1]+", maxX: a"+a[2]+", maxY: a"+a[3]+"};")}}},{quickselect:2}],2:[function(a,b){function f(a,b,d,e,q){d=d||0;e=e||a.length-1;for(q=q||h;e>d;){if(600<e-d){var r=e-d+1,u=b-d+1,x=Math.log(r),
+v=.5*Math.exp(2*x/3),x=.5*Math.sqrt(x*v*(r-v)/r)*(0>u-r/2?-1:1);f(a,b,Math.max(d,Math.floor(b-u*v/r+x)),Math.min(e,Math.floor(b+(r-u)*v/r+x)),q)}r=a[b];u=d;v=e;g(a,d,b);for(0<q(a[e],r)&&g(a,d,e);u<v;){g(a,u,v);u++;for(v--;0>q(a[u],r);)u++;for(;0<q(a[v],r);)v--}0===q(a[d],r)?g(a,d,v):(v++,g(a,v,e));v<=b&&(d=v+1);b<=v&&(e=v-1)}}function g(a,b,d){var e=a[b];a[b]=a[d];a[d]=e}function h(a,b){return a<b?-1:a>b?1:0}b.ja=f},{}]},{},[1])(1)});gl=b.ja})();function kl(a){this.a=gl(a);this.b={}}k=kl.prototype;k.Ca=function(a,b){var c={ca:a[0],fa:a[1],ea:a[2],ga:a[3],value:b};this.a.Ca(c);this.b[w(b)]=c};k.load=function(a,b){for(var c=Array(b.length),d=0,e=b.length;d<e;d++){var f=a[d],g=b[d],f={ca:f[0],fa:f[1],ea:f[2],ga:f[3],value:g};c[d]=f;this.b[w(g)]=f}this.a.load(c)};k.remove=function(a){a=w(a);var b=this.b[a];delete this.b[a];return null!==this.a.remove(b)};
+function ll(a,b,c){var d=w(c),d=a.b[d];$b([d.ca,d.fa,d.ea,d.ga],b)||(a.remove(c),a.Ca(b,c))}function ml(a){return a.a.all().map(function(a){return a.value})}function nl(a,b){return a.a.search({ca:b[0],fa:b[1],ea:b[2],ga:b[3]}).map(function(a){return a.value})}k.forEach=function(a,b){return pl(ml(this),a,b)};function ql(a,b,c,d){return pl(nl(a,b),c,d)}function pl(a,b,c){for(var d,e=0,f=a.length;e<f&&!(d=b.call(c,a[e]));e++);return d}k.Ya=function(){return Ha(this.b)};
+k.clear=function(){this.a.clear();this.b={}};k.H=function(){var a=this.a.data;return[a.ca,a.fa,a.ea,a.ga]};function P(a){a=a||{};jf.call(this,{attributions:a.attributions,logo:a.logo,projection:void 0,state:"ready",wrapX:void 0!==a.wrapX?a.wrapX:!0});this.S=na;this.qa=a.format;this.T=a.url;void 0!==a.loader?this.S=a.loader:void 0!==this.T&&(this.S=el(this.T,this.qa));this.qb=void 0!==a.strategy?a.strategy:fl;var b=void 0!==a.useSpatialIndex?a.useSpatialIndex:!0;this.a=b?new kl:null;this.Y=new kl;this.i={};this.o={};this.j={};this.s={};this.c=null;var c,d;a.features instanceof le?(c=a.features,d=c.a):Array.isArray(a.features)&&
+(d=a.features);b||void 0!==c||(c=new le(d));void 0!==d&&rl(this,d);void 0!==c&&sl(this,c)}y(P,jf);k=P.prototype;k.rb=function(a){var b=w(a).toString();if(tl(this,b,a)){ul(this,b,a);var c=a.W();c?(b=c.H(),this.a&&this.a.Ca(b,a)):this.i[b]=a;this.b(new vl("addfeature",a))}this.u()};function ul(a,b,c){a.s[b]=[B(c,"change",a.Eh,a),B(c,"propertychange",a.Eh,a)]}function tl(a,b,c){var d=!0,e=c.Xa();void 0!==e?e.toString()in a.o?d=!1:a.o[e.toString()]=c:a.j[b]=c;return d}k.Jc=function(a){rl(this,a);this.u()};
+function rl(a,b){var c,d,e,f,g=[],h=[],l=[];d=0;for(e=b.length;d<e;d++)f=b[d],c=w(f).toString(),tl(a,c,f)&&h.push(f);d=0;for(e=h.length;d<e;d++){f=h[d];c=w(f).toString();ul(a,c,f);var m=f.W();m?(c=m.H(),g.push(c),l.push(f)):a.i[c]=f}a.a&&a.a.load(g,l);d=0;for(e=h.length;d<e;d++)a.b(new vl("addfeature",h[d]))}
+function sl(a,b){var c=!1;B(a,"addfeature",function(a){c||(c=!0,b.push(a.feature),c=!1)});B(a,"removefeature",function(a){c||(c=!0,b.remove(a.feature),c=!1)});B(b,"add",function(a){c||(a=a.element,c=!0,this.rb(a),c=!1)},a);B(b,"remove",function(a){c||(a=a.element,c=!0,this.nb(a),c=!1)},a);a.c=b}
+k.clear=function(a){if(a){for(var b in this.s)this.s[b].forEach(Ka);this.c||(this.s={},this.o={},this.j={})}else if(this.a){this.a.forEach(this.Sf,this);for(var c in this.i)this.Sf(this.i[c])}this.c&&this.c.clear();this.a&&this.a.clear();this.Y.clear();this.i={};this.b(new vl("clear"));this.u()};k.wg=function(a,b){if(this.a)return this.a.forEach(a,b);if(this.c)return this.c.forEach(a,b)};function wl(a,b,c){a.ub([b[0],b[1],b[0],b[1]],function(a){if(a.W().sg(b))return c.call(void 0,a)})}
+k.ub=function(a,b,c){if(this.a)return ql(this.a,a,b,c);if(this.c)return this.c.forEach(b,c)};k.xg=function(a,b,c){return this.ub(a,function(d){if(d.W().Ka(a)&&(d=b.call(c,d)))return d})};k.Fg=function(){return this.c};k.oe=function(){var a;this.c?a=this.c.a:this.a&&(a=ml(this.a),Ha(this.i)||mb(a,Ga(this.i)));return a};k.Eg=function(a){var b=[];wl(this,a,function(a){b.push(a)});return b};k.ef=function(a){return nl(this.a,a)};
+k.Ag=function(a,b){var c=a[0],d=a[1],e=null,f=[NaN,NaN],g=Infinity,h=[-Infinity,-Infinity,Infinity,Infinity],l=b?b:qc;ql(this.a,h,function(a){if(l(a)){var b=a.W(),p=g;g=b.sb(c,d,f,g);g<p&&(e=a,a=Math.sqrt(g),h[0]=c-a,h[1]=d-a,h[2]=c+a,h[3]=d+a)}});return e};k.H=function(){return this.a.H()};k.Dg=function(a){a=this.o[a.toString()];return void 0!==a?a:null};k.Ch=function(){return this.qa};k.Dh=function(){return this.T};
+k.Eh=function(a){a=a.target;var b=w(a).toString(),c=a.W();c?(c=c.H(),b in this.i?(delete this.i[b],this.a&&this.a.Ca(c,a)):this.a&&ll(this.a,c,a)):b in this.i||(this.a&&this.a.remove(a),this.i[b]=a);c=a.Xa();void 0!==c?(c=c.toString(),b in this.j?(delete this.j[b],this.o[c]=a):this.o[c]!==a&&(xl(this,a),this.o[c]=a)):b in this.j||(xl(this,a),this.j[b]=a);this.u();this.b(new vl("changefeature",a))};k.Ya=function(){return this.a.Ya()&&Ha(this.i)};
+k.Pc=function(a,b,c){var d=this.Y;a=this.qb(a,b);var e,f;e=0;for(f=a.length;e<f;++e){var g=a[e];ql(d,g,function(a){return Ub(a.extent,g)})||(this.S.call(this,g,b,c),d.Ca(g,{extent:g.slice()}))}};k.nb=function(a){var b=w(a).toString();b in this.i?delete this.i[b]:this.a&&this.a.remove(a);this.Sf(a);this.u()};k.Sf=function(a){var b=w(a).toString();this.s[b].forEach(Ka);delete this.s[b];var c=a.Xa();void 0!==c?delete this.o[c.toString()]:delete this.j[b];this.b(new vl("removefeature",a))};
+function xl(a,b){for(var c in a.o)if(a.o[c]===b){delete a.o[c];break}}function vl(a,b){Wa.call(this,a);this.feature=b}y(vl,Wa);function yl(a){this.c=a.source;this.Aa=Xc();this.i=Oe();this.j=[0,0];this.v=null;Hk.call(this,{attributions:a.attributions,canvasFunction:this.Dj.bind(this),logo:a.logo,projection:a.projection,ratio:a.ratio,resolutions:a.resolutions,state:this.c.V()});this.S=null;this.s=void 0;this.xh(a.style);B(this.c,"change",this.en,this)}y(yl,Hk);k=yl.prototype;
+k.Dj=function(a,b,c,d,e){var f=new dk(.5*b/c,a,b);this.c.Pc(a,b,e);var g=!1;this.c.ub(a,function(a){var d;if(!(d=g)){var e;(d=a.ec())?e=d.call(a,b):this.s&&(e=this.s(a,b));if(e){var n,p=!1;Array.isArray(e)||(e=[e]);d=0;for(n=e.length;d<n;++d)p=lk(f,a,e[d],jk(b,c),this.dn,this)||p;d=p}else d=!1}g=d},this);ek(f);if(g)return null;this.j[0]!=d[0]||this.j[1]!=d[1]?(this.i.canvas.width=d[0],this.i.canvas.height=d[1],this.j[0]=d[0],this.j[1]=d[1]):this.i.clearRect(0,0,d[0],d[1]);a=zl(this,kc(a),b,c,d);f.Pa(this.i,
+c,a,0,{});this.v=f;return this.i.canvas};k.ra=function(a,b,c,d,e){if(this.v){var f={};return this.v.ra(a,b,0,d,function(a){var b=w(a).toString();if(!(b in f))return f[b]=!0,e(a)})}};k.an=function(){return this.c};k.bn=function(){return this.S};k.cn=function(){return this.s};function zl(a,b,c,d,e){return qh(a.Aa,e[0]/2,e[1]/2,d/c,-d/c,0,-b[0],-b[1])}k.dn=function(){this.u()};k.en=function(){lf(this,this.c.V())};k.xh=function(a){this.S=void 0!==a?a:vj;this.s=a?tj(this.S):void 0;this.u()};function Al(a){Jj.call(this,a);this.f=null;this.s=Xc();this.o=this.c=null}y(Al,Jj);Al.prototype.ra=function(a,b,c,d){var e=this.a;return e.ha().ra(a,b.viewState.resolution,b.viewState.rotation,b.skippedFeatureUids,function(a){return c.call(d,a,e)})};
+Al.prototype.Cc=function(a,b,c,d){if(this.f&&this.f.a())if(this.a.ha()instanceof yl){if(a=a.slice(),sh(b.pixelToCoordinateMatrix,a,a),this.ra(a,b,qc,this))return c.call(d,this.a)}else if(this.c||(this.c=Xc(),cd(this.s,this.c)),b=[0,0],sh(this.c,a,b),this.o||(this.o=Oe(1,1)),this.o.clearRect(0,0,1,1),this.o.drawImage(this.f?this.f.a():null,b[0],b[1],1,1,0,0,1,1),0<this.o.getImageData(0,0,1,1).data[3])return c.call(d,this.a)};
+Al.prototype.l=function(a,b){var c=a.pixelRatio,d=a.viewState,e=d.center,f=d.resolution,g=this.a.ha(),h=a.viewHints,l=a.extent;void 0!==b.extent&&(l=mc(l,b.extent));h[0]||h[1]||hc(l)||(d=g.A(l,f,c,d.projection))&&vh(this,d)&&(this.f=d);if(this.f){var d=this.f,h=d.H(),l=d.$(),m=d.f,f=c*l/(f*m);qh(this.s,c*a.size[0]/2,c*a.size[1]/2,f,f,0,m*(h[0]-e[0])/l,m*(e[1]-h[3])/l);this.c=null;xh(a.attributions,d.l);yh(a,g)}return!!this.f};function Bl(a){Jj.call(this,a);this.c=Oe();this.o=null;this.j=Lb();this.S=[0,0,0];this.D=Xc();this.C=0}y(Bl,Jj);Bl.prototype.i=function(a,b,c){var d=Mj(this,a,0);Kj(this,"precompose",c,a,d);Cl(this,c,a,b);Lj(this,c,a,d)};
+Bl.prototype.l=function(a,b){function c(a){a=a.V();return 2==a||4==a||3==a&&!r}var d=a.pixelRatio,e=a.viewState,f=e.projection,g=this.a,h=g.ha(),l=h.eb(f),m=l.Lb(e.resolution,this.C),n=l.$(m),p=e.center;n==e.resolution?(p=Ah(p,n,a.size),e=lc(p,n,e.rotation,a.size)):e=a.extent;void 0!==b.extent&&(e=mc(e,b.extent));if(hc(e))return!1;n=sf(l,e,n);p={};p[m]={};var q=this.Qd(h,f,p),r=g.c(),u=Lb(),x=new fe(0,0,0,0),v,D,A,z;for(A=n.ca;A<=n.ea;++A)for(z=n.fa;z<=n.ga;++z)v=h.ac(m,A,z,d,f),!c(v)&&v.a&&(v=v.a),
+c(v)?p[m][v.ma.toString()]=v:(D=qf(l,v.ma,q,x,u),D||(v=rf(l,v.ma,x,u))&&q(m+1,v));q=Object.keys(p).map(Number);q.sort(ib);var u=[],F,x=0;for(A=q.length;x<A;++x)for(F in v=q[x],z=p[v],z)v=z[F],2==v.V()&&u.push(v);this.o=u;zh(a.usedTiles,h,m,n);Bh(a,h,l,d,f,e,m,g.f());wh(a,h);yh(a,h);return!0};Bl.prototype.Cc=function(a,b,c,d){var e=this.c.canvas,f=b.size;e.width=f[0];e.height=f[1];this.i(b,jh(this.a),this.c);if(0<this.c.getImageData(a[0],a[1],1,1).data[3])return c.call(d,this.a)};
+function Cl(a,b,c,d){var e=c.pixelRatio,f=c.viewState,g=f.center,h=f.projection,l=f.resolution,f=f.rotation,m=c.size,n=Math.round(e*m[0]/2),p=Math.round(e*m[1]/2),m=e/l,q=a.a,r=q.ha(),u=r.Ud(h),x=r.eb(h),q=ab(q,"render"),v=b,D,A,z,F;if(f||q)v=a.c,D=v.canvas,F=x.Lb(l),z=r.$d(F,e,h),F=hf(x.Ja(F)),z=z[0]/F[0],l=b.canvas.width*z,A=b.canvas.height*z,F=Math.round(Math.sqrt(l*l+A*A)),D.width!=F?D.width=D.height=F:v.clearRect(0,0,F,F),D=(F-l)/2/z,A=(F-A)/2/z,m*=z,n=Math.round(z*(n+D)),p=Math.round(z*(p+A));
+l=v.globalAlpha;v.globalAlpha=d.opacity;var N=a.o,K,X=r.jf(h)&&1==d.opacity;X||(N.reverse(),K=[]);var oa=d.extent;if(d=void 0!==oa){var H=fc(oa),ya=ec(oa),Ua=dc(oa),oa=cc(oa);sh(c.coordinateToPixelMatrix,H,H);sh(c.coordinateToPixelMatrix,ya,ya);sh(c.coordinateToPixelMatrix,Ua,Ua);sh(c.coordinateToPixelMatrix,oa,oa);var Xa=D||0,Va=A||0;v.save();var Aa=v.canvas.width*e/2,Qb=v.canvas.height*e/2;hj(v,-f,Aa,Qb);v.beginPath();v.moveTo(H[0]*e+Xa,H[1]*e+Va);v.lineTo(ya[0]*e+Xa,ya[1]*e+Va);v.lineTo(Ua[0]*
+e+Xa,Ua[1]*e+Va);v.lineTo(oa[0]*e+Xa,oa[1]*e+Va);v.clip();hj(v,f,Aa,Qb)}H=0;for(ya=N.length;H<ya;++H){var Ua=N[H],oa=Ua.ma,Qb=x.Ea(oa,a.j),Aa=oa[0],Nb=cc(x.Ea(x.qd(g,Aa,a.S))),oa=Math.round(ic(Qb)*m),Xa=Math.round(jc(Qb)*m),Va=Math.round((Qb[0]-Nb[0])*m/oa)*oa+n+Math.round((Nb[0]-g[0])*m),Qb=Math.round((Nb[1]-Qb[3])*m/Xa)*Xa+p+Math.round((g[1]-Nb[1])*m);if(!X){Nb=[Va,Qb,Va+oa,Qb+Xa];v.save();for(var kk=0,vs=K.length;kk<vs;++kk){var De=K[kk];nc(Nb,De)&&(v.beginPath(),v.moveTo(Nb[0],Nb[1]),v.lineTo(Nb[0],
+Nb[3]),v.lineTo(Nb[2],Nb[3]),v.lineTo(Nb[2],Nb[1]),v.moveTo(De[0],De[1]),v.lineTo(De[2],De[1]),v.lineTo(De[2],De[3]),v.lineTo(De[0],De[3]),v.closePath(),v.clip())}K.push(Nb)}Aa=r.$d(Aa,e,h);v.drawImage(Ua.$a(),u,u,Aa[0],Aa[1],Va,Qb,oa,Xa);X||v.restore()}d&&v.restore();q&&(e=D-n/z+n,h=A-p/z+p,g=qh(a.D,F/2-e,F/2-h,m,-m,-f,-g[0]+e/m,-g[1]-h/m),Kj(a,"render",v,c,g));(f||q)&&b.drawImage(v.canvas,-Math.round(D),-Math.round(A),F/z,F/z);v.globalAlpha=l};function Dl(a){Jj.call(this,a);this.c=!1;this.C=-1;this.A=NaN;this.v=Lb();this.o=this.U=null;this.j=Oe()}y(Dl,Jj);
+Dl.prototype.i=function(a,b,c){var d=a.extent,e=a.pixelRatio,f=b.Qc?a.skippedFeatureUids:{},g=a.viewState,h=g.projection,g=g.rotation,l=h.H(),m=this.a.ha(),n=Mj(this,a,0);Kj(this,"precompose",c,a,n);var p=this.o;if(p&&!p.Ya()){var q;ab(this.a,"render")?(this.j.canvas.width=c.canvas.width,this.j.canvas.height=c.canvas.height,q=this.j):q=c;var r=q.globalAlpha;q.globalAlpha=b.opacity;b=a.size[0]*e;var u=a.size[1]*e;hj(q,-g,b/2,u/2);p.Pa(q,e,n,g,f);if(m.D&&h.a&&!Ub(l,d)){for(var h=d[0],m=ic(l),x=0;h<
+l[0];)--x,n=m*x,n=Mj(this,a,n),p.Pa(q,e,n,g,f),h+=m;x=0;for(h=d[2];h>l[2];)++x,n=m*x,n=Mj(this,a,n),p.Pa(q,e,n,g,f),h-=m;n=Mj(this,a,0)}hj(q,g,b/2,u/2);q!=c&&(Kj(this,"render",q,a,n),c.drawImage(q.canvas,0,0));q.globalAlpha=r}Lj(this,c,a,n)};Dl.prototype.ra=function(a,b,c,d){if(this.o){var e=this.a,f={};return this.o.ra(a,b.viewState.resolution,b.viewState.rotation,{},function(a){var b=w(a).toString();if(!(b in f))return f[b]=!0,c.call(d,a,e)})}};Dl.prototype.D=function(){uh(this)};
+Dl.prototype.l=function(a){function b(a){var b,d=a.ec();d?b=d.call(a,m):(d=c.i)&&(b=d(a,m));if(b){if(b){d=!1;if(Array.isArray(b))for(var e=0,f=b.length;e<f;++e)d=lk(q,a,b[e],jk(m,n),this.D,this)||d;else d=lk(q,a,b,jk(m,n),this.D,this)||d;a=d}else a=!1;this.c=this.c||a}}var c=this.a,d=c.ha();xh(a.attributions,d.l);yh(a,d);var e=a.viewHints[0],f=a.viewHints[1],g=c.S,h=c.T;if(!this.c&&!g&&e||!h&&f)return!0;var l=a.extent,h=a.viewState,e=h.projection,m=h.resolution,n=a.pixelRatio,f=c.g,p=c.a,g=xj(c);
+void 0===g&&(g=ik);l=Ob(l,p*m);p=h.projection.H();d.D&&h.projection.a&&!Ub(p,a.extent)&&(a=Math.max(ic(l)/2,ic(p)),l[0]=p[0]-a,l[2]=p[2]+a);if(!this.c&&this.A==m&&this.C==f&&this.U==g&&Ub(this.v,l))return!0;this.o=null;this.c=!1;var q=new dk(.5*m/n,l,m,c.a);d.Pc(l,m,e);if(g){var r=[];d.ub(l,function(a){r.push(a)},this);r.sort(g);r.forEach(b,this)}else d.ub(l,b,this);ek(q);this.A=m;this.C=f;this.U=g;this.v=l;this.o=q;return!0};function El(a,b){var c=/\{z\}/g,d=/\{x\}/g,e=/\{y\}/g,f=/\{-y\}/g;return function(g){if(g)return a.replace(c,g[0].toString()).replace(d,g[1].toString()).replace(e,function(){return(-g[2]-1).toString()}).replace(f,function(){var a=b.a?b.a[g[0]]:null;return(a.ga-a.fa+1+g[2]).toString()})}}function Fl(a,b){for(var c=a.length,d=Array(c),e=0;e<c;++e)d[e]=El(a[e],b);return Gl(d)}function Gl(a){return 1===a.length?a[0]:function(b,c,d){if(b)return a[xa((b[1]<<b[0])+b[2],a.length)](b,c,d)}}
+function Hl(){}function Il(a){var b=[],c=/\{(\d)-(\d)\}/.exec(a)||/\{([a-z])-([a-z])\}/.exec(a);if(c){var d=c[2].charCodeAt(0),e;for(e=c[1].charCodeAt(0);e<=d;++e)b.push(a.replace(c[0],String.fromCharCode(e)))}else b.push(a);return b};function Jl(a){zf.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,extent:a.extent,logo:a.logo,opaque:a.opaque,projection:a.projection,state:a.state,tileGrid:a.tileGrid,tilePixelRatio:a.tilePixelRatio,wrapX:a.wrapX});this.tileLoadFunction=a.tileLoadFunction;this.tileUrlFunction=this.vc?this.vc.bind(this):Hl;this.urls=null;a.urls?this.bb(a.urls):a.url&&this.Va(a.url);a.tileUrlFunction&&this.Qa(a.tileUrlFunction)}y(Jl,zf);k=Jl.prototype;k.fb=function(){return this.tileLoadFunction};
+k.gb=function(){return this.tileUrlFunction};k.hb=function(){return this.urls};k.Bh=function(a){a=a.target;switch(a.V()){case 1:this.b(new Df("tileloadstart",a));break;case 2:this.b(new Df("tileloadend",a));break;case 3:this.b(new Df("tileloaderror",a))}};k.kb=function(a){this.a.clear();this.tileLoadFunction=a;this.u()};k.Qa=function(a,b){this.tileUrlFunction=a;"undefined"!==typeof b?Bf(this,b):this.u()};
+k.Va=function(a){var b=this.urls=Il(a);this.Qa(this.vc?this.vc.bind(this):Fl(b,this.tileGrid),a)};k.bb=function(a){this.urls=a;var b=a.join("\n");this.Qa(this.vc?this.vc.bind(this):Fl(a,this.tileGrid),b)};k.Yf=function(a,b,c){a=this.Eb(a,b,c);Ze(this.a,a)&&this.a.get(a)};function Kl(a){Jl.call(this,{attributions:a.attributions,cacheSize:void 0!==a.cacheSize?a.cacheSize:128,extent:a.extent,logo:a.logo,opaque:!1,projection:a.projection,state:a.state,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction?a.tileLoadFunction:Ll,tileUrlFunction:a.tileUrlFunction,tilePixelRatio:a.tilePixelRatio,url:a.url,urls:a.urls,wrapX:void 0===a.wrapX?!0:a.wrapX});this.c=a.format?a.format:null;this.tileClass=a.tileClass?a.tileClass:Kk}y(Kl,Jl);
+Kl.prototype.ac=function(a,b,c,d,e){var f=this.Eb(a,b,c);if(Ze(this.a,f))return this.a.get(f);a=[a,b,c];d=(b=Cf(this,a,e))?this.tileUrlFunction(b,d,e):void 0;d=new this.tileClass(a,void 0!==d?0:4,void 0!==d?d:"",this.c,this.tileLoadFunction);B(d,"change",this.Bh,this);this.a.set(f,d);return d};Kl.prototype.$d=function(a,b){var c=hf(this.tileGrid.Ja(a));return[c[0]*b,c[1]*b]};function Ll(a,b){a.ki(dl(b,a.l))};var Ml={image:Nj,hybrid:["Polygon","LineString"]},Nl={hybrid:["Image","Text"],vector:Nj};function Ol(a){Bl.call(this,a);this.U=!1;this.v=Xc();this.C="vector"==a.s?1:0}y(Ol,Bl);
+Ol.prototype.i=function(a,b,c){var d=Mj(this,a,0);Kj(this,"precompose",c,a,d);var e=this.a.s;"vector"!==e&&Cl(this,c,a,b);if("image"!==e){var f=this.a,e=Nl[f.s],g=a.pixelRatio,h=b.Qc?a.skippedFeatureUids:{},l=a.viewState,m=l.center,n=l.rotation,p=a.size,l=g/l.resolution,q=f.ha(),r=q.bc(g),u=Mj(this,a,0);ab(f,"render")?(this.c.canvas.width=c.canvas.width,this.c.canvas.height=c.canvas.height,f=this.c):f=c;var x=f.globalAlpha;f.globalAlpha=b.opacity;b=this.o;var q=q.tileGrid,v,D,A,z,F,N,K,X;D=0;for(A=
+b.length;D<A;++D)z=b[D],K=z.f,F=q.Ea(z.ma,this.j),v=z.ma[0],N="tile-pixels"==z.o.wb(),v=q.$(v),X=v/r,v=Math.round(g*p[0]/2),z=Math.round(g*p[1]/2),N?(F=fc(F),F=qh(this.v,v,z,l*X,l*X,n,(F[0]-m[0])/X,(m[1]-F[1])/X)):F=u,hj(f,-n,v,z),K.yd.Pa(f,g,F,n,h,e),hj(f,n,v,z);f!=c&&(Kj(this,"render",f,a,u),c.drawImage(f.canvas,0,0));f.globalAlpha=x}Lj(this,c,a,d)};
+function Pl(a,b,c){function d(a){var b,c=a.ec();c?b=c.call(a,u):(c=e.i)&&(b=c(a,u));if(b){Array.isArray(b)||(b=[b]);var c=D,d=v;if(b){var f=!1;if(Array.isArray(b))for(var g=0,h=b.length;g<h;++g)f=lk(d,a,b[g],c,this.A,this)||f;else f=lk(d,a,b,c,this.A,this)||f;a=f}else a=!1;this.U=this.U||a;l.gd=l.gd||a}}var e=a.a,f=c.pixelRatio;c=c.viewState.projection;var g=e.g,h=xj(e)||null,l=b.f;if(l.gd||l.bi!=g||l.Tf!=h){l.yd=null;l.gd=!1;var m=e.ha(),n=m.tileGrid,p=b.ma,q=b.o,r="tile-pixels"==q.wb(),u=n.$(p[0]),
+x;r?(r=m=m.bc(f),n=hf(n.Ja(p[0])),n=[0,0,n[0]*r,n[1]*r]):(m=u,n=n.Ea(p),Oc(c,q)||(x=!0,b.vf(c)));l.gd=!1;var v=new dk(0,n,m,e.a),D=jk(m,f);b=b.c;h&&h!==l.Tf&&b.sort(h);n=0;for(p=b.length;n<p;++n)f=b[n],x&&f.W().jb(q,c),d.call(a,f);ek(v);l.bi=g;l.Tf=h;l.yd=v;l.resolution=NaN}}
+Ol.prototype.ra=function(a,b,c,d){var e=b.pixelRatio,f=b.viewState.resolution;b=b.viewState.rotation;var g=this.a,h={},l=this.o,m=g.ha(),n=m.tileGrid,p,q,r,u,x,v;r=0;for(u=l.length;r<u;++r)v=l[r],q=v.ma,x=m.tileGrid.Ea(q,this.j),Sb(x,a)&&("tile-pixels"===v.o.wb()?(x=fc(x),f=m.bc(e),q=n.$(q[0])/f,q=[(a[0]-x[0])/q,(x[1]-a[1])/q]):q=a,v=v.f.yd,p=p||v.ra(q,f,b,{},function(a){var b=w(a).toString();if(!(b in h))return h[b]=!0,c.call(d,a,g)}));return p};Ol.prototype.A=function(){uh(this)};
+Ol.prototype.l=function(a,b){var c=Bl.prototype.l.call(this,a,b);if(c)for(var d=Object.keys(a.Ee||{}),e=0,f=this.o.length;e<f;++e){var g=this.o[e];Pl(this,g,a);var h=g,g=a,l=this.a,m=Ml[l.s];if(m){var n=g.pixelRatio,p=h.f,q=l.g;if(!pb(p.ui,d)||p.Uf!==q){p.ui=d;p.Uf=q;var q=h.g,r=l.ha(),u=r.tileGrid,x=h.ma[0],v=u.$(x),l=hf(u.Ja(x)),x=u.$(x),D=x/v,A=l[0]*n*D,z=l[1]*n*D;q.canvas.width=A/D+.5;q.canvas.height=z/D+.5;q.scale(1/D,1/D);q.translate(A/2,z/2);D="tile-pixels"==h.o.wb();v=n/v;r=r.bc(n);x/=r;h=
+u.Ea(h.ma,this.j);D?h=qh(this.v,0,0,v*x,v*x,0,-l[0]*r/2,-l[1]*r/2):(h=kc(h),h=qh(this.v,0,0,v,-v,0,-h[0],-h[1]));p.yd.Pa(q,n,h,0,g.skippedFeatureUids||{},m)}}}return c};function Ql(a,b){Hh.call(this,0,b);this.f=Oe();this.b=this.f.canvas;this.b.style.width="100%";this.b.style.height="100%";this.b.className="ol-unselectable";a.insertBefore(this.b,a.childNodes[0]||null);this.a=!0;this.c=Xc()}y(Ql,Hh);Ql.prototype.Xe=function(a){return a instanceof cj?new Al(a):a instanceof dj?new Bl(a):a instanceof I?new Ol(a):a instanceof G?new Dl(a):null};
+function Rl(a,b,c){var d=a.i,e=a.f;if(ab(d,b)){var f=c.extent,g=c.pixelRatio,h=c.viewState.rotation,l=c.pixelRatio,m=c.viewState,n=m.resolution;a=qh(a.c,a.b.width/2,a.b.height/2,l/n,-l/n,-m.rotation,-m.center[0],-m.center[1]);f=new yj(e,g,f,a,h);d.b(new lh(b,d,f,c,e,null))}}Ql.prototype.X=function(){return"canvas"};
+Ql.prototype.Ce=function(a){if(a){var b=this.f,c=a.pixelRatio,d=Math.round(a.size[0]*c),c=Math.round(a.size[1]*c);this.b.width!=d||this.b.height!=c?(this.b.width=d,this.b.height=c):b.clearRect(0,0,d,c);var e=a.viewState.rotation;Ih(a);Rl(this,"precompose",a);var f=a.layerStatesArray;qb(f);hj(b,e,d/2,c/2);var g=a.viewState.resolution,h,l,m,n;h=0;for(l=f.length;h<l;++h)n=f[h],m=n.layer,m=Kh(this,m),nh(n,g)&&"ready"==n.R&&m.l(a,n)&&m.i(a,n,b);hj(b,-e,d/2,c/2);Rl(this,"postcompose",a);this.a||(this.b.style.display=
+"",this.a=!0);Lh(this,a);a.postRenderFunctions.push(Jh)}else this.a&&(this.b.style.display="none",this.a=!1)};function Sl(a,b){th.call(this,a);this.target=b}y(Sl,th);Sl.prototype.Nd=na;Sl.prototype.th=na;function Tl(a){var b=document.createElement("DIV");b.style.position="absolute";Sl.call(this,a,b);this.f=null;this.c=Zc()}y(Tl,Sl);Tl.prototype.ra=function(a,b,c,d){var e=this.a;return e.ha().ra(a,b.viewState.resolution,b.viewState.rotation,b.skippedFeatureUids,function(a){return c.call(d,a,e)})};Tl.prototype.Nd=function(){Ve(this.target);this.f=null};
+Tl.prototype.yf=function(a,b){var c=a.viewState,d=c.center,e=c.resolution,f=c.rotation,g=this.f,h=this.a.ha(),l=a.viewHints,m=a.extent;void 0!==b.extent&&(m=mc(m,b.extent));l[0]||l[1]||hc(m)||(c=h.A(m,e,a.pixelRatio,c.projection))&&vh(this,c)&&(g=c);g&&(l=g.H(),m=g.$(),c=Xc(),qh(c,a.size[0]/2,a.size[1]/2,m/e,m/e,f,(l[0]-d[0])/m,(d[1]-l[3])/m),g!=this.f&&(d=g.a(this),d.style.maxWidth="none",d.style.position="absolute",Ve(this.target),this.target.appendChild(d),this.f=g),rh(c,this.c)||(Se(this.target,
+c),$c(this.c,c)),xh(a.attributions,g.l),yh(a,h));return!0};function Ul(a){var b=document.createElement("DIV");b.style.position="absolute";Sl.call(this,a,b);this.c=!0;this.l=1;this.i=0;this.f={}}y(Ul,Sl);Ul.prototype.Nd=function(){Ve(this.target);this.i=0};
+Ul.prototype.yf=function(a,b){if(!b.visible)return this.c&&(this.target.style.display="none",this.c=!1),!0;var c=a.pixelRatio,d=a.viewState,e=d.projection,f=this.a,g=f.ha(),h=g.eb(e),l=g.Ud(e),m=h.Lb(d.resolution),n=h.$(m),p=d.center,q;n==d.resolution?(p=Ah(p,n,a.size),q=lc(p,n,d.rotation,a.size)):q=a.extent;void 0!==b.extent&&(q=mc(q,b.extent));var n=sf(h,q,n),r={};r[m]={};var u=this.Qd(g,e,r),x=f.c(),v=Lb(),D=new fe(0,0,0,0),A,z,F,N;for(F=n.ca;F<=n.ea;++F)for(N=n.fa;N<=n.ga;++N)A=g.ac(m,F,N,c,e),
+z=A.V(),z=2==z||4==z||3==z&&!x,!z&&A.a&&(A=A.a),z=A.V(),2==z?r[m][A.ma.toString()]=A:4==z||3==z&&!x||(z=qf(h,A.ma,u,D,v),z||(A=rf(h,A.ma,D,v))&&u(m+1,A));var K;if(this.i!=g.g){for(K in this.f)x=this.f[+K],Ue(x.target);this.f={};this.i=g.g}v=Object.keys(r).map(Number);v.sort(ib);var u={},X;F=0;for(N=v.length;F<N;++F){K=v[F];K in this.f?x=this.f[K]:(x=h.qd(p,K),x=new Vl(h,x),u[K]=!0,this.f[K]=x);K=r[K];for(X in K){A=x;z=K[X];var oa=l,H=z.ma,ya=H[0],Ua=H[1],Xa=H[2],H=H.toString();if(!(H in A.a)){var ya=
+hf(A.c.Ja(ya),A.o),Va=z.$a(A),Aa=Va.style;Aa.maxWidth="none";var Qb,Nb;0<oa?(Qb=document.createElement("DIV"),Nb=Qb.style,Nb.overflow="hidden",Nb.width=ya[0]+"px",Nb.height=ya[1]+"px",Aa.position="absolute",Aa.left=-oa+"px",Aa.top=-oa+"px",Aa.width=ya[0]+2*oa+"px",Aa.height=ya[1]+2*oa+"px",Qb.appendChild(Va)):(Aa.width=ya[0]+"px",Aa.height=ya[1]+"px",Qb=Va,Nb=Aa);Nb.position="absolute";Nb.left=(Ua-A.g[1])*ya[0]+"px";Nb.top=(A.g[2]-Xa)*ya[1]+"px";A.b||(A.b=document.createDocumentFragment());A.b.appendChild(Qb);
+A.a[H]=z}}x.b&&(x.target.appendChild(x.b),x.b=null)}l=Object.keys(this.f).map(Number);l.sort(ib);F=Xc();X=0;for(v=l.length;X<v;++X)if(K=l[X],x=this.f[K],K in r)if(A=x.$(),N=x.Ia(),qh(F,a.size[0]/2,a.size[1]/2,A/d.resolution,A/d.resolution,d.rotation,(N[0]-p[0])/A,(p[1]-N[1])/A),x.setTransform(F),K in u){for(--K;0<=K;--K)if(K in this.f){this.f[K].target.parentNode&&this.f[K].target.parentNode.insertBefore(x.target,this.f[K].target.nextSibling);break}0>K&&this.target.insertBefore(x.target,this.target.childNodes[0]||
+null)}else{if(!a.viewHints[0]&&!a.viewHints[1]){z=pf(x.c,q,x.g[0],D);K=[];A=void 0;for(A in x.a)N=x.a[A],z.contains(N.ma)||K.push(N);z=0;for(oa=K.length;z<oa;++z)N=K[z],A=N.ma.toString(),Ue(N.$a(x)),delete x.a[A]}}else Ue(x.target),delete this.f[K];b.opacity!=this.l&&(this.l=this.target.style.opacity=b.opacity);b.visible&&!this.c&&(this.target.style.display="",this.c=!0);zh(a.usedTiles,g,m,n);Bh(a,g,h,c,e,q,m,f.f());wh(a,g);yh(a,g);return!0};
+function Vl(a,b){this.target=document.createElement("DIV");this.target.style.position="absolute";this.target.style.width="100%";this.target.style.height="100%";this.c=a;this.g=b;this.i=fc(a.Ea(b));this.l=a.$(b[0]);this.a={};this.b=null;this.f=Zc();this.o=[0,0]}Vl.prototype.Ia=function(){return this.i};Vl.prototype.$=function(){return this.l};Vl.prototype.setTransform=function(a){rh(a,this.f)||(Se(this.target,a),$c(this.f,a))};function Wl(a){this.i=Oe();var b=this.i.canvas;b.style.maxWidth="none";b.style.position="absolute";Sl.call(this,a,b);this.f=!1;this.l=-1;this.s=NaN;this.o=Lb();this.c=this.j=null;this.U=Xc();this.v=Xc()}y(Wl,Sl);k=Wl.prototype;k.Nd=function(){var a=this.i.canvas;a.width=a.width;this.l=0};
+k.th=function(a,b){var c=a.viewState,d=c.center,e=c.rotation,f=c.resolution,c=a.pixelRatio,g=a.size[0],h=a.size[1],l=g*c,m=h*c,d=qh(this.U,c*g/2,c*h/2,c/f,-c/f,-e,-d[0],-d[1]),f=this.i;f.canvas.width=l;f.canvas.height=m;g=qh(this.v,0,0,1/c,1/c,0,-(l-g)/2*c,-(m-h)/2*c);Se(f.canvas,g);Xl(this,"precompose",a,d);(g=this.c)&&!g.Ya()&&(f.globalAlpha=b.opacity,g.Pa(f,c,d,e,b.Qc?a.skippedFeatureUids:{}),Xl(this,"render",a,d));Xl(this,"postcompose",a,d)};
+function Xl(a,b,c,d){var e=a.i;a=a.a;ab(a,b)&&(d=new yj(e,c.pixelRatio,c.extent,d,c.viewState.rotation),a.b(new lh(b,a,d,c,e,null)))}k.ra=function(a,b,c,d){if(this.c){var e=this.a,f={};return this.c.ra(a,b.viewState.resolution,b.viewState.rotation,{},function(a){var b=w(a).toString();if(!(b in f))return f[b]=!0,c.call(d,a,e)})}};k.uh=function(){uh(this)};
+k.yf=function(a){function b(a){var b,d=a.ec();d?b=d.call(a,l):(d=c.i)&&(b=d(a,l));if(b){if(b){d=!1;if(Array.isArray(b))for(var e=0,f=b.length;e<f;++e)d=lk(n,a,b[e],jk(l,m),this.uh,this)||d;else d=lk(n,a,b,jk(l,m),this.uh,this)||d;a=d}else a=!1;this.f=this.f||a}}var c=this.a,d=c.ha();xh(a.attributions,d.l);yh(a,d);var e=a.viewHints[0],f=a.viewHints[1],g=c.S,h=c.T;if(!this.f&&!g&&e||!h&&f)return!0;var f=a.extent,g=a.viewState,e=g.projection,l=g.resolution,m=a.pixelRatio;a=c.g;h=c.a;g=xj(c);void 0===
+g&&(g=ik);f=Ob(f,h*l);if(!this.f&&this.s==l&&this.l==a&&this.j==g&&Ub(this.o,f))return!0;this.c=null;this.f=!1;var n=new dk(.5*l/m,f,l,c.a);d.Pc(f,l,e);if(g){var p=[];d.ub(f,function(a){p.push(a)},this);p.sort(g);p.forEach(b,this)}else d.ub(f,b,this);ek(n);this.s=l;this.l=a;this.j=g;this.o=f;this.c=n;return!0};function Yl(a,b){Hh.call(this,0,b);this.f=Oe();var c=this.f.canvas;c.style.position="absolute";c.style.width="100%";c.style.height="100%";c.className="ol-unselectable";a.insertBefore(c,a.childNodes[0]||null);this.c=Xc();this.b=document.createElement("DIV");this.b.className="ol-unselectable";c=this.b.style;c.position="absolute";c.width="100%";c.height="100%";B(this.b,"touchstart",Za);a.insertBefore(this.b,a.childNodes[0]||null);this.a=!0}y(Yl,Hh);Yl.prototype.ka=function(){Ue(this.b);Hh.prototype.ka.call(this)};
+Yl.prototype.Xe=function(a){if(a instanceof cj)a=new Tl(a);else if(a instanceof dj)a=new Ul(a);else if(a instanceof G)a=new Wl(a);else return null;return a};function Zl(a,b,c){var d=a.i;if(ab(d,b)){var e=c.extent,f=c.pixelRatio,g=c.viewState,h=g.rotation,l=a.f,m=l.canvas;qh(a.c,m.width/2,m.height/2,f/g.resolution,-f/g.resolution,-g.rotation,-g.center[0],-g.center[1]);a=new yj(l,f,e,a.c,h);d.b(new lh(b,d,a,c,l,null))}}Yl.prototype.X=function(){return"dom"};
+Yl.prototype.Ce=function(a){if(a){var b=this.i;if(ab(b,"precompose")||ab(b,"postcompose")){var b=this.f.canvas,c=a.pixelRatio;b.width=a.size[0]*c;b.height=a.size[1]*c}Zl(this,"precompose",a);b=a.layerStatesArray;qb(b);var c=a.viewState.resolution,d,e,f,g;d=0;for(e=b.length;d<e;++d)g=b[d],f=g.layer,f=Kh(this,f),this.b.insertBefore(f.target,this.b.childNodes[d]||null),nh(g,c)&&"ready"==g.R?f.yf(a,g)&&f.th(a,g):f.Nd();var b=a.layerStates,h;for(h in this.g)h in b||(f=this.g[h],Ue(f.target));this.a||(this.b.style.display=
+"",this.a=!0);Ih(a);Lh(this,a);a.postRenderFunctions.push(Jh);Zl(this,"postcompose",a)}else this.a&&(this.b.style.display="none",this.a=!1)};function $l(a){this.b=a}function am(a){this.b=a}y(am,$l);am.prototype.X=function(){return 35632};function bm(a){this.b=a}y(bm,$l);bm.prototype.X=function(){return 35633};function cm(){this.b="precision mediump float;varying vec2 a;varying float b;uniform float k;uniform sampler2D l;void main(void){vec4 texColor=texture2D(l,a);gl_FragColor.rgb=texColor.rgb;float alpha=texColor.a*b*k;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}"}y(cm,am);ba(cm);
+function dm(){this.b="varying vec2 a;varying float b;attribute vec2 c;attribute vec2 d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;void main(void){mat4 offsetMatrix=i;if(g==1.0){offsetMatrix=i*j;}vec4 offsets=offsetMatrix*vec4(e,0.,0.);gl_Position=h*vec4(c,0.,1.)+offsets;a=d;b=f;}"}y(dm,bm);ba(dm);
+function em(a,b){this.o=a.getUniformLocation(b,"j");this.j=a.getUniformLocation(b,"i");this.i=a.getUniformLocation(b,"k");this.l=a.getUniformLocation(b,"h");this.b=a.getAttribLocation(b,"e");this.a=a.getAttribLocation(b,"f");this.f=a.getAttribLocation(b,"c");this.g=a.getAttribLocation(b,"g");this.c=a.getAttribLocation(b,"d")};function fm(a){this.b=void 0!==a?a:[]};function gm(a,b){this.l=a;this.b=b;this.a={};this.c={};this.f={};this.j=this.s=this.i=this.o=null;(this.g=jb(ma,"OES_element_index_uint"))&&b.getExtension("OES_element_index_uint");B(this.l,"webglcontextlost",this.ao,this);B(this.l,"webglcontextrestored",this.bo,this)}y(gm,Sa);
+function hm(a,b,c){var d=a.b,e=c.b,f=String(w(c));if(f in a.a)d.bindBuffer(b,a.a[f].buffer);else{var g=d.createBuffer();d.bindBuffer(b,g);var h;34962==b?h=new Float32Array(e):34963==b&&(h=a.g?new Uint32Array(e):new Uint16Array(e));d.bufferData(b,h,35044);a.a[f]={Cb:c,buffer:g}}}function im(a,b){var c=a.b,d=String(w(b)),e=a.a[d];c.isContextLost()||c.deleteBuffer(e.buffer);delete a.a[d]}k=gm.prototype;
+k.ka=function(){Ra(this.l);var a=this.b;if(!a.isContextLost()){for(var b in this.a)a.deleteBuffer(this.a[b].buffer);for(b in this.f)a.deleteProgram(this.f[b]);for(b in this.c)a.deleteShader(this.c[b]);a.deleteFramebuffer(this.i);a.deleteRenderbuffer(this.j);a.deleteTexture(this.s)}};k.$n=function(){return this.b};
+function jm(a){if(!a.i){var b=a.b,c=b.createFramebuffer();b.bindFramebuffer(b.FRAMEBUFFER,c);var d=km(b,1,1),e=b.createRenderbuffer();b.bindRenderbuffer(b.RENDERBUFFER,e);b.renderbufferStorage(b.RENDERBUFFER,b.DEPTH_COMPONENT16,1,1);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,d,0);b.framebufferRenderbuffer(b.FRAMEBUFFER,b.DEPTH_ATTACHMENT,b.RENDERBUFFER,e);b.bindTexture(b.TEXTURE_2D,null);b.bindRenderbuffer(b.RENDERBUFFER,null);b.bindFramebuffer(b.FRAMEBUFFER,null);a.i=c;
+a.s=d;a.j=e}return a.i}function lm(a,b){var c=String(w(b));if(c in a.c)return a.c[c];var d=a.b,e=d.createShader(b.X());d.shaderSource(e,b.b);d.compileShader(e);return a.c[c]=e}function mm(a,b,c){var d=w(b)+"/"+w(c);if(d in a.f)return a.f[d];var e=a.b,f=e.createProgram();e.attachShader(f,lm(a,b));e.attachShader(f,lm(a,c));e.linkProgram(f);return a.f[d]=f}k.ao=function(){Fa(this.a);Fa(this.c);Fa(this.f);this.j=this.s=this.i=this.o=null};k.bo=function(){};
+k.we=function(a){if(a==this.o)return!1;this.b.useProgram(a);this.o=a;return!0};function nm(a,b,c){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR);void 0!==b&&a.texParameteri(3553,10242,b);void 0!==c&&a.texParameteri(3553,10243,c);return d}function km(a,b,c){var d=nm(a,void 0,void 0);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,b,c,0,a.RGBA,a.UNSIGNED_BYTE,null);return d}
+function om(a,b){var c=nm(a,33071,33071);a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,b);return c};function pm(a,b){this.C=this.A=void 0;this.j=kc(b);this.U=[];this.i=[];this.R=void 0;this.c=[];this.f=[];this.Ba=this.ya=void 0;this.a=[];this.D=this.o=null;this.S=void 0;this.ta=Zc();this.Aa=Zc();this.Y=this.T=void 0;this.Sa=Zc();this.za=this.ia=this.Ra=void 0;this.Gb=[];this.l=[];this.b=[];this.v=null;this.g=[];this.s=[];this.qa=void 0}y(pm,kh);
+function qm(a,b){var c=a.v,d=a.o,e=a.Gb,f=a.l,g=b.b;return function(){if(!g.isContextLost()){var a,l;a=0;for(l=e.length;a<l;++a)g.deleteTexture(e[a]);a=0;for(l=f.length;a<l;++a)g.deleteTexture(f[a])}im(b,c);im(b,d)}}
+function rm(a,b,c,d){var e=a.A,f=a.C,g=a.R,h=a.ya,l=a.Ba,m=a.S,n=a.T,p=a.Y,q=a.Ra?1:0,r=a.ia,u=a.za,x=a.qa,v=Math.cos(r),r=Math.sin(r),D=a.a.length,A=a.b.length,z,F,N,K,X,oa;for(z=0;z<c;z+=d)X=b[z]-a.j[0],oa=b[z+1]-a.j[1],F=A/8,N=-u*e,K=-u*(g-f),a.b[A++]=X,a.b[A++]=oa,a.b[A++]=N*v-K*r,a.b[A++]=N*r+K*v,a.b[A++]=n/l,a.b[A++]=(p+g)/h,a.b[A++]=m,a.b[A++]=q,N=u*(x-e),K=-u*(g-f),a.b[A++]=X,a.b[A++]=oa,a.b[A++]=N*v-K*r,a.b[A++]=N*r+K*v,a.b[A++]=(n+x)/l,a.b[A++]=(p+g)/h,a.b[A++]=m,a.b[A++]=q,N=u*(x-e),K=
+u*f,a.b[A++]=X,a.b[A++]=oa,a.b[A++]=N*v-K*r,a.b[A++]=N*r+K*v,a.b[A++]=(n+x)/l,a.b[A++]=p/h,a.b[A++]=m,a.b[A++]=q,N=-u*e,K=u*f,a.b[A++]=X,a.b[A++]=oa,a.b[A++]=N*v-K*r,a.b[A++]=N*r+K*v,a.b[A++]=n/l,a.b[A++]=p/h,a.b[A++]=m,a.b[A++]=q,a.a[D++]=F,a.a[D++]=F+1,a.a[D++]=F+2,a.a[D++]=F,a.a[D++]=F+2,a.a[D++]=F+3}pm.prototype.tc=function(a,b){this.g.push(this.a.length);this.s.push(b);var c=a.la();rm(this,c,c.length,a.va())};
+pm.prototype.uc=function(a,b){this.g.push(this.a.length);this.s.push(b);var c=a.la();rm(this,c,c.length,a.va())};function sm(a,b){var c=b.b;a.U.push(a.a.length);a.i.push(a.a.length);a.v=new fm(a.b);hm(b,34962,a.v);a.o=new fm(a.a);hm(b,34963,a.o);var d={};tm(a.Gb,a.c,d,c);tm(a.l,a.f,d,c);a.A=void 0;a.C=void 0;a.R=void 0;a.c=null;a.f=null;a.ya=void 0;a.Ba=void 0;a.a=null;a.S=void 0;a.T=void 0;a.Y=void 0;a.Ra=void 0;a.ia=void 0;a.za=void 0;a.b=null;a.qa=void 0}
+function tm(a,b,c,d){var e,f,g,h=b.length;for(g=0;g<h;++g)e=b[g],f=w(e).toString(),f in c?e=c[f]:(e=om(d,e),c[f]=e),a[g]=e}
+pm.prototype.Pa=function(a,b,c,d,e,f,g,h,l,m,n){f=a.b;hm(a,34962,this.v);hm(a,34963,this.o);var p=cm.Zb(),q=dm.Zb(),q=mm(a,p,q);this.D?p=this.D:this.D=p=new em(f,q);a.we(q);f.enableVertexAttribArray(p.f);f.vertexAttribPointer(p.f,2,5126,!1,32,0);f.enableVertexAttribArray(p.b);f.vertexAttribPointer(p.b,2,5126,!1,32,8);f.enableVertexAttribArray(p.c);f.vertexAttribPointer(p.c,2,5126,!1,32,16);f.enableVertexAttribArray(p.a);f.vertexAttribPointer(p.a,1,5126,!1,32,24);f.enableVertexAttribArray(p.g);f.vertexAttribPointer(p.g,
+1,5126,!1,32,28);q=this.Sa;qh(q,0,0,2/(c*e[0]),2/(c*e[1]),-d,-(b[0]-this.j[0]),-(b[1]-this.j[1]));b=this.Aa;c=2/e[0];e=2/e[1];ad(b);b[0]=c;b[5]=e;b[10]=1;b[15]=1;e=this.ta;ad(e);0!==d&&fd(e,-d);f.uniformMatrix4fv(p.l,!1,q);f.uniformMatrix4fv(p.j,!1,b);f.uniformMatrix4fv(p.o,!1,e);f.uniform1f(p.i,g);var r;if(void 0===l)um(this,f,a,h,this.Gb,this.U);else{if(m)a:{d=a.g?5125:5123;a=a.g?4:2;e=this.g.length-1;for(g=this.l.length-1;0<=g;--g)for(f.bindTexture(3553,this.l[g]),m=0<g?this.i[g-1]:0,b=this.i[g];0<=
+e&&this.g[e]>=m;){r=this.g[e];c=this.s[e];q=w(c).toString();if(void 0===h[q]&&c.W()&&(void 0===n||nc(n,c.W().H()))&&(f.clear(f.COLOR_BUFFER_BIT|f.DEPTH_BUFFER_BIT),f.drawElements(4,b-r,d,r*a),b=l(c))){h=b;break a}b=r;e--}h=void 0}else f.clear(f.COLOR_BUFFER_BIT|f.DEPTH_BUFFER_BIT),um(this,f,a,h,this.l,this.i),h=(h=l(null))?h:void 0;r=h}f.disableVertexAttribArray(p.f);f.disableVertexAttribArray(p.b);f.disableVertexAttribArray(p.c);f.disableVertexAttribArray(p.a);f.disableVertexAttribArray(p.g);return r};
+function um(a,b,c,d,e,f){var g=c.g?5125:5123;c=c.g?4:2;if(Ha(d)){var h;a=0;d=e.length;for(h=0;a<d;++a){b.bindTexture(3553,e[a]);var l=f[a];b.drawElements(4,l-h,g,h*c);h=l}}else{h=0;var m,l=0;for(m=e.length;l<m;++l){b.bindTexture(3553,e[l]);for(var n=0<l?f[l-1]:0,p=f[l],q=n;h<a.g.length&&a.g[h]<=p;){var r=w(a.s[h]).toString();void 0!==d[r]?(q!==n&&b.drawElements(4,n-q,g,q*c),n=q=h===a.g.length-1?p:a.g[h+1]):n=h===a.g.length-1?p:a.g[h+1];h++}q!==n&&b.drawElements(4,n-q,g,q*c)}}}
+pm.prototype.Tb=function(a){var b=a.Yb(),c=a.jc(1),d=a.ld(),e=a.pe(1),f=a.v,g=a.Ia(),h=a.U,l=a.j,m=a.Fb();a=a.i;var n;0===this.c.length?this.c.push(c):(n=this.c[this.c.length-1],w(n)!=w(c)&&(this.U.push(this.a.length),this.c.push(c)));0===this.f.length?this.f.push(e):(n=this.f[this.f.length-1],w(n)!=w(e)&&(this.i.push(this.a.length),this.f.push(e)));this.A=b[0];this.C=b[1];this.R=m[1];this.ya=d[1];this.Ba=d[0];this.S=f;this.T=g[0];this.Y=g[1];this.ia=l;this.Ra=h;this.za=a;this.qa=m[0]};
+function vm(a,b,c){this.f=b;this.c=a;this.g=c;this.a={}}function wm(a,b){var c=[],d;for(d in a.a)c.push(qm(a.a[d],b));return function(){for(var a=c.length,b,d=0;d<a;d++)b=c[d].apply(this,arguments);return b}}function xm(a,b){for(var c in a.a)sm(a.a[c],b)}vm.prototype.b=function(a,b){var c=this.a[b];void 0===c&&(c=new ym[b](this.c,this.f),this.a[b]=c);return c};vm.prototype.Ya=function(){return Ha(this.a)};
+vm.prototype.Pa=function(a,b,c,d,e,f,g,h){var l,m,n;l=0;for(m=Nj.length;l<m;++l)n=this.a[Nj[l]],void 0!==n&&n.Pa(a,b,c,d,e,f,g,h,void 0,!1)};function zm(a,b,c,d,e,f,g,h,l,m,n){var p=Am,q,r;for(q=Nj.length-1;0<=q;--q)if(r=a.a[Nj[q]],void 0!==r&&(r=r.Pa(b,c,d,e,p,f,g,h,l,m,n)))return r}
+vm.prototype.ra=function(a,b,c,d,e,f,g,h,l,m){var n=b.b;n.bindFramebuffer(n.FRAMEBUFFER,jm(b));var p;void 0!==this.g&&(p=Ob(Xb(a),d*this.g));return zm(this,b,a,d,e,g,h,l,function(a){var b=new Uint8Array(4);n.readPixels(0,0,1,1,n.RGBA,n.UNSIGNED_BYTE,b);if(0<b[3]&&(a=m(a)))return a},!0,p)};
+function Bm(a,b,c,d,e,f,g,h){var l=c.b;l.bindFramebuffer(l.FRAMEBUFFER,jm(c));return void 0!==zm(a,c,b,d,e,f,g,h,function(){var a=new Uint8Array(4);l.readPixels(0,0,1,1,l.RGBA,l.UNSIGNED_BYTE,a);return 0<a[3]},!1)}var ym={Image:pm},Am=[1,1];function Cm(a,b,c,d,e,f,g){this.b=a;this.f=b;this.g=f;this.c=g;this.o=e;this.l=d;this.i=c;this.a=null}y(Cm,kh);k=Cm.prototype;k.sd=function(a){this.Tb(a.a)};k.sc=function(a){switch(a.X()){case "Point":this.uc(a,null);break;case "MultiPoint":this.tc(a,null);break;case "GeometryCollection":this.Ze(a,null)}};k.Ye=function(a,b){var c=(0,b.g)(a);c&&nc(this.g,c.H())&&(this.sd(b),this.sc(c))};k.Ze=function(a){a=a.c;var b,c;b=0;for(c=a.length;b<c;++b)this.sc(a[b])};
+k.uc=function(a,b){var c=this.b,d=(new vm(1,this.g)).b(0,"Image");d.Tb(this.a);d.uc(a,b);sm(d,c);d.Pa(this.b,this.f,this.i,this.l,this.o,this.c,1,{},void 0,!1);qm(d,c)()};k.tc=function(a,b){var c=this.b,d=(new vm(1,this.g)).b(0,"Image");d.Tb(this.a);d.tc(a,b);sm(d,c);d.Pa(this.b,this.f,this.i,this.l,this.o,this.c,1,{},void 0,!1);qm(d,c)()};k.Tb=function(a){this.a=a};function Dm(){this.b="precision mediump float;varying vec2 a;uniform float f;uniform sampler2D g;void main(void){vec4 texColor=texture2D(g,a);gl_FragColor.rgb=texColor.rgb;gl_FragColor.a=texColor.a*f;}"}y(Dm,am);ba(Dm);function Em(){this.b="varying vec2 a;attribute vec2 b;attribute vec2 c;uniform mat4 d;uniform mat4 e;void main(void){gl_Position=e*vec4(b,0.,1.);a=(d*vec4(c,0.,1.)).st;}"}y(Em,bm);ba(Em);
+function Fm(a,b){this.g=a.getUniformLocation(b,"f");this.f=a.getUniformLocation(b,"e");this.i=a.getUniformLocation(b,"d");this.c=a.getUniformLocation(b,"g");this.b=a.getAttribLocation(b,"b");this.a=a.getAttribLocation(b,"c")};function Gm(a,b){th.call(this,b);this.f=a;this.S=new fm([-1,-1,0,0,1,-1,1,0,-1,1,0,1,1,1,1,1]);this.i=this.pb=null;this.l=void 0;this.s=Xc();this.U=Zc();this.v=null}y(Gm,th);
+function Hm(a,b,c){var d=a.f.f;if(void 0===a.l||a.l!=c){b.postRenderFunctions.push(function(a,b,c){a.isContextLost()||(a.deleteFramebuffer(b),a.deleteTexture(c))}.bind(null,d,a.i,a.pb));b=km(d,c,c);var e=d.createFramebuffer();d.bindFramebuffer(36160,e);d.framebufferTexture2D(36160,36064,3553,b,0);a.pb=b;a.i=e;a.l=c}else d.bindFramebuffer(36160,a.i)}
+Gm.prototype.vh=function(a,b,c){Im(this,"precompose",c,a);hm(c,34962,this.S);var d=c.b,e=Dm.Zb(),f=Em.Zb(),e=mm(c,e,f);this.v?f=this.v:this.v=f=new Fm(d,e);c.we(e)&&(d.enableVertexAttribArray(f.b),d.vertexAttribPointer(f.b,2,5126,!1,16,0),d.enableVertexAttribArray(f.a),d.vertexAttribPointer(f.a,2,5126,!1,16,8),d.uniform1i(f.c,0));d.uniformMatrix4fv(f.i,!1,this.s);d.uniformMatrix4fv(f.f,!1,this.U);d.uniform1f(f.g,b.opacity);d.bindTexture(3553,this.pb);d.drawArrays(5,0,4);Im(this,"postcompose",c,a)};
+function Im(a,b,c,d){a=a.a;if(ab(a,b)){var e=d.viewState;a.b(new lh(b,a,new Cm(c,e.center,e.resolution,e.rotation,d.size,d.extent,d.pixelRatio),d,null,c))}}Gm.prototype.zf=function(){this.i=this.pb=null;this.l=void 0};function Jm(a,b){Gm.call(this,a,b);this.j=this.o=this.c=null}y(Jm,Gm);function Km(a,b){var c=b.a();return om(a.f.f,c)}Jm.prototype.ra=function(a,b,c,d){var e=this.a;return e.ha().ra(a,b.viewState.resolution,b.viewState.rotation,b.skippedFeatureUids,function(a){return c.call(d,a,e)})};
+Jm.prototype.Af=function(a,b){var c=this.f.f,d=a.pixelRatio,e=a.viewState,f=e.center,g=e.resolution,h=e.rotation,l=this.c,m=this.pb,n=this.a.ha(),p=a.viewHints,q=a.extent;void 0!==b.extent&&(q=mc(q,b.extent));p[0]||p[1]||hc(q)||(e=n.A(q,g,d,e.projection))&&vh(this,e)&&(l=e,m=Km(this,e),this.pb&&a.postRenderFunctions.push(function(a,b){a.isContextLost()||a.deleteTexture(b)}.bind(null,c,this.pb)));l&&(c=this.f.c.l,Lm(this,c.width,c.height,d,f,g,h,l.H()),this.j=null,d=this.s,ad(d),ed(d,1,-1),dd(d,0,
+-1),this.c=l,this.pb=m,xh(a.attributions,l.l),yh(a,n));return!0};function Lm(a,b,c,d,e,f,g,h){b*=f;c*=f;a=a.U;ad(a);ed(a,2*d/b,2*d/c);fd(a,-g);dd(a,h[0]-e[0],h[1]-e[1]);ed(a,(h[2]-h[0])/2,(h[3]-h[1])/2);dd(a,1,1)}Jm.prototype.le=function(a,b){return void 0!==this.ra(a,b,qc,this)};
+Jm.prototype.Cc=function(a,b,c,d){if(this.c&&this.c.a())if(this.a.ha()instanceof yl){if(a=a.slice(),sh(b.pixelToCoordinateMatrix,a,a),this.ra(a,b,qc,this))return c.call(d,this.a)}else{var e=[this.c.a().width,this.c.a().height];if(!this.j){var f=b.size;b=Xc();ad(b);dd(b,-1,-1);ed(b,2/f[0],2/f[1]);dd(b,0,f[1]);ed(b,1,-1);f=Xc();cd(this.U,f);var g=Xc();ad(g);dd(g,0,e[1]);ed(g,1,-1);ed(g,e[0]/2,e[1]/2);dd(g,1,1);var h=Xc();bd(g,f,h);bd(h,b,h);this.j=h}b=[0,0];sh(this.j,a,b);if(!(0>b[0]||b[0]>e[0]||0>
+b[1]||b[1]>e[1])&&(this.o||(this.o=Oe(1,1)),this.o.clearRect(0,0,1,1),this.o.drawImage(this.c.a(),b[0],b[1],1,1,0,0,1,1),0<this.o.getImageData(0,0,1,1).data[3]))return c.call(d,this.a)}};function Mm(){this.b="precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}"}y(Mm,am);ba(Mm);function Nm(){this.b="varying vec2 a;attribute vec2 b;attribute vec2 c;uniform vec4 d;void main(void){gl_Position=vec4(b*d.xy+d.zw,0.,1.);a=c;}"}y(Nm,bm);ba(Nm);function Om(a,b){this.g=a.getUniformLocation(b,"e");this.f=a.getUniformLocation(b,"d");this.b=a.getAttribLocation(b,"b");this.a=a.getAttribLocation(b,"c")};function Pm(a,b){Gm.call(this,a,b);this.D=Mm.Zb();this.T=Nm.Zb();this.c=null;this.C=new fm([0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0]);this.A=this.o=null;this.j=-1;this.R=[0,0]}y(Pm,Gm);k=Pm.prototype;k.ka=function(){im(this.f.c,this.C);Gm.prototype.ka.call(this)};k.Qd=function(a,b,c){var d=this.f;return function(e,f){return Af(a,b,e,f,function(a){var b=Ze(d.a,a.ib());b&&(c[e]||(c[e]={}),c[e][a.ma.toString()]=a);return b})}};k.zf=function(){Gm.prototype.zf.call(this);this.c=null};
+k.Af=function(a,b,c){var d=this.f,e=c.b,f=a.viewState,g=f.projection,h=this.a,l=h.ha(),m=l.eb(g),n=m.Lb(f.resolution),p=m.$(n),q=l.$d(n,a.pixelRatio,g),r=q[0]/hf(m.Ja(n),this.R)[0],u=p/r,x=l.Ud(g),v=f.center,D;p==f.resolution?(v=Ah(v,p,a.size),D=lc(v,p,f.rotation,a.size)):D=a.extent;p=sf(m,D,p);if(this.o&&he(this.o,p)&&this.j==l.g)u=this.A;else{var A=[p.ea-p.ca+1,p.ga-p.fa+1],z=Math.pow(2,Math.ceil(Math.log(Math.max(A[0]*q[0],A[1]*q[1]))/Math.LN2)),A=u*z,F=m.Ia(n),N=F[0]+p.ca*q[0]*u,u=F[1]+p.fa*q[1]*
+u,u=[N,u,N+A,u+A];Hm(this,a,z);e.viewport(0,0,z,z);e.clearColor(0,0,0,0);e.clear(16384);e.disable(3042);z=mm(c,this.D,this.T);c.we(z);this.c||(this.c=new Om(e,z));hm(c,34962,this.C);e.enableVertexAttribArray(this.c.b);e.vertexAttribPointer(this.c.b,2,5126,!1,16,0);e.enableVertexAttribArray(this.c.a);e.vertexAttribPointer(this.c.a,2,5126,!1,16,8);e.uniform1i(this.c.g,0);c={};c[n]={};var K=this.Qd(l,g,c),X=h.c(),z=!0,N=Lb(),oa=new fe(0,0,0,0),H,ya,Ua;for(ya=p.ca;ya<=p.ea;++ya)for(Ua=p.fa;Ua<=p.ga;++Ua){F=
+l.ac(n,ya,Ua,r,g);if(void 0!==b.extent&&(H=m.Ea(F.ma,N),!nc(H,b.extent)))continue;H=F.V();H=2==H||4==H||3==H&&!X;!H&&F.a&&(F=F.a);H=F.V();if(2==H){if(Ze(d.a,F.ib())){c[n][F.ma.toString()]=F;continue}}else if(4==H||3==H&&!X)continue;z=!1;H=qf(m,F.ma,K,oa,N);H||(F=rf(m,F.ma,oa,N))&&K(n+1,F)}b=Object.keys(c).map(Number);b.sort(ib);for(var K=new Float32Array(4),Xa,Va,Aa,X=0,oa=b.length;X<oa;++X)for(Xa in Va=c[b[X]],Va)F=Va[Xa],H=m.Ea(F.ma,N),ya=2*(H[2]-H[0])/A,Ua=2*(H[3]-H[1])/A,Aa=2*(H[0]-u[0])/A-1,
+H=2*(H[1]-u[1])/A-1,Wc(K,ya,Ua,Aa,H),e.uniform4fv(this.c.f,K),Qm(d,F,q,x*r),e.drawArrays(5,0,4);z?(this.o=p,this.A=u,this.j=l.g):(this.A=this.o=null,this.j=-1,a.animate=!0)}zh(a.usedTiles,l,n,p);var Qb=d.o;Bh(a,l,m,r,g,D,n,h.f(),function(a){var b;(b=2!=a.V()||Ze(d.a,a.ib()))||(b=a.ib()in Qb.g);b||Qb.f([a,uf(m,a.ma),m.$(a.ma[0]),q,x*r])},this);wh(a,l);yh(a,l);e=this.s;ad(e);dd(e,(v[0]-u[0])/(u[2]-u[0]),(v[1]-u[1])/(u[3]-u[1]));0!==f.rotation&&fd(e,f.rotation);ed(e,a.size[0]*f.resolution/(u[2]-u[0]),
+a.size[1]*f.resolution/(u[3]-u[1]));dd(e,-.5,-.5);return!0};k.Cc=function(a,b,c,d){if(this.i){var e=[0,0];sh(this.s,[a[0]/b.size[0],(b.size[1]-a[1])/b.size[1]],e);a=[e[0]*this.l,e[1]*this.l];b=this.f.c.b;b.bindFramebuffer(b.FRAMEBUFFER,this.i);e=new Uint8Array(4);b.readPixels(a[0],a[1],1,1,b.RGBA,b.UNSIGNED_BYTE,e);if(0<e[3])return c.call(d,this.a)}};function Rm(a,b){Gm.call(this,a,b);this.j=!1;this.R=-1;this.D=NaN;this.A=Lb();this.o=this.c=this.C=null}y(Rm,Gm);k=Rm.prototype;k.vh=function(a,b,c){this.o=b;var d=a.viewState,e=this.c;e&&!e.Ya()&&e.Pa(c,d.center,d.resolution,d.rotation,a.size,a.pixelRatio,b.opacity,b.Qc?a.skippedFeatureUids:{})};k.ka=function(){var a=this.c;a&&(wm(a,this.f.c)(),this.c=null);Gm.prototype.ka.call(this)};
+k.ra=function(a,b,c,d){if(this.c&&this.o){var e=b.viewState,f=this.a,g={};return this.c.ra(a,this.f.c,e.center,e.resolution,e.rotation,b.size,b.pixelRatio,this.o.opacity,{},function(a){var b=w(a).toString();if(!(b in g))return g[b]=!0,c.call(d,a,f)})}};k.le=function(a,b){if(this.c&&this.o){var c=b.viewState;return Bm(this.c,a,this.f.c,c.resolution,c.rotation,b.pixelRatio,this.o.opacity,b.skippedFeatureUids)}return!1};
+k.Cc=function(a,b,c,d){a=a.slice();sh(b.pixelToCoordinateMatrix,a,a);if(this.le(a,b))return c.call(d,this.a)};k.wh=function(){uh(this)};
+k.Af=function(a,b,c){function d(a){var b,c=a.ec();c?b=c.call(a,m):(c=e.i)&&(b=c(a,m));if(b){if(b){c=!1;if(Array.isArray(b))for(var d=0,f=b.length;d<f;++d)c=lk(q,a,b[d],jk(m,n),this.wh,this)||c;else c=lk(q,a,b,jk(m,n),this.wh,this)||c;a=c}else a=!1;this.j=this.j||a}}var e=this.a;b=e.ha();xh(a.attributions,b.l);yh(a,b);var f=a.viewHints[0],g=a.viewHints[1],h=e.S,l=e.T;if(!this.j&&!h&&f||!l&&g)return!0;var g=a.extent,h=a.viewState,f=h.projection,m=h.resolution,n=a.pixelRatio,h=e.g,p=e.a,l=xj(e);void 0===
+l&&(l=ik);g=Ob(g,p*m);if(!this.j&&this.D==m&&this.R==h&&this.C==l&&Ub(this.A,g))return!0;this.c&&a.postRenderFunctions.push(wm(this.c,c));this.j=!1;var q=new vm(.5*m/n,g,e.a);b.Pc(g,m,f);if(l){var r=[];b.ub(g,function(a){r.push(a)},this);r.sort(l);r.forEach(d,this)}else b.ub(g,d,this);xm(q,c);this.D=m;this.R=h;this.C=l;this.A=g;this.c=q;return!0};function Sm(a,b){Hh.call(this,0,b);this.b=document.createElement("CANVAS");this.b.style.width="100%";this.b.style.height="100%";this.b.className="ol-unselectable";a.insertBefore(this.b,a.childNodes[0]||null);this.U=this.A=0;this.C=Oe();this.j=!0;this.f=ag(this.b,{antialias:!0,depth:!1,failIfMajorPerformanceCaveat:!0,preserveDrawingBuffer:!1,stencil:!0});this.c=new gm(this.b,this.f);B(this.b,"webglcontextlost",this.Pm,this);B(this.b,"webglcontextrestored",this.Qm,this);this.a=new Ye;this.v=null;this.o=
+new Mh(function(a){var b=a[1];a=a[2];var e=b[0]-this.v[0],b=b[1]-this.v[1];return 65536*Math.log(a)+Math.sqrt(e*e+b*b)/a}.bind(this),function(a){return a[0].ib()});this.D=function(){if(!this.o.Ya()){Qh(this.o);var a=Nh(this.o);Qm(this,a[0],a[3],a[4])}return!1}.bind(this);this.l=0;Tm(this)}y(Sm,Hh);
+function Qm(a,b,c,d){var e=a.f,f=b.ib();if(Ze(a.a,f))a=a.a.get(f),e.bindTexture(3553,a.pb),9729!=a.Wg&&(e.texParameteri(3553,10240,9729),a.Wg=9729),9729!=a.Yg&&(e.texParameteri(3553,10241,9729),a.Yg=9729);else{var g=e.createTexture();e.bindTexture(3553,g);if(0<d){var h=a.C.canvas,l=a.C;a.A!==c[0]||a.U!==c[1]?(h.width=c[0],h.height=c[1],a.A=c[0],a.U=c[1]):l.clearRect(0,0,c[0],c[1]);l.drawImage(b.$a(),d,d,c[0],c[1],0,0,c[0],c[1]);e.texImage2D(3553,0,6408,6408,5121,h)}else e.texImage2D(3553,0,6408,6408,
+5121,b.$a());e.texParameteri(3553,10240,9729);e.texParameteri(3553,10241,9729);e.texParameteri(3553,10242,33071);e.texParameteri(3553,10243,33071);a.a.set(f,{pb:g,Wg:9729,Yg:9729})}}k=Sm.prototype;k.Xe=function(a){return a instanceof cj?new Jm(this,a):a instanceof dj?new Pm(this,a):a instanceof G?new Rm(this,a):null};function Um(a,b,c){var d=a.i;if(ab(d,b)){a=a.c;var e=c.viewState;d.b(new lh(b,d,new Cm(a,e.center,e.resolution,e.rotation,c.size,c.extent,c.pixelRatio),c,null,a))}}
+k.ka=function(){var a=this.f;a.isContextLost()||this.a.forEach(function(b){b&&a.deleteTexture(b.pb)});Ta(this.c);Hh.prototype.ka.call(this)};k.Gj=function(a,b){for(var c=this.f,d;1024<this.a.wc()-this.l;){if(d=this.a.b.pc)c.deleteTexture(d.pb);else if(+this.a.b.cc==b.index)break;else--this.l;this.a.pop()}};k.X=function(){return"webgl"};k.Pm=function(a){a.preventDefault();this.a.clear();this.l=0;a=this.g;for(var b in a)a[b].zf()};k.Qm=function(){Tm(this);this.i.render()};
+function Tm(a){a=a.f;a.activeTexture(33984);a.blendFuncSeparate(770,771,1,771);a.disable(2884);a.disable(2929);a.disable(3089);a.disable(2960)}
+k.Ce=function(a){var b=this.c,c=this.f;if(c.isContextLost())return!1;if(!a)return this.j&&(this.b.style.display="none",this.j=!1),!1;this.v=a.focus;this.a.set((-a.index).toString(),null);++this.l;Um(this,"precompose",a);var d=[],e=a.layerStatesArray;qb(e);var f=a.viewState.resolution,g,h,l,m;g=0;for(h=e.length;g<h;++g)m=e[g],nh(m,f)&&"ready"==m.R&&(l=Kh(this,m.layer),l.Af(a,m,b)&&d.push(m));e=a.size[0]*a.pixelRatio;f=a.size[1]*a.pixelRatio;if(this.b.width!=e||this.b.height!=f)this.b.width=e,this.b.height=
+f;c.bindFramebuffer(36160,null);c.clearColor(0,0,0,0);c.clear(16384);c.enable(3042);c.viewport(0,0,this.b.width,this.b.height);g=0;for(h=d.length;g<h;++g)m=d[g],l=Kh(this,m.layer),l.vh(a,m,b);this.j||(this.b.style.display="",this.j=!0);Ih(a);1024<this.a.wc()-this.l&&a.postRenderFunctions.push(this.Gj.bind(this));this.o.Ya()||(a.postRenderFunctions.push(this.D),a.animate=!0);Um(this,"postcompose",a);Lh(this,a);a.postRenderFunctions.push(Jh)};
+k.ra=function(a,b,c,d,e,f){var g;if(this.f.isContextLost())return!1;var h=b.viewState,l=b.layerStatesArray,m;for(m=l.length-1;0<=m;--m){g=l[m];var n=g.layer;if(nh(g,h.resolution)&&e.call(f,n)&&(g=Kh(this,n).ra(a,b,c,d)))return g}};k.sh=function(a,b,c,d){var e=!1;if(this.f.isContextLost())return!1;var f=b.viewState,g=b.layerStatesArray,h;for(h=g.length-1;0<=h;--h){var l=g[h],m=l.layer;if(nh(l,f.resolution)&&c.call(d,m)&&(e=Kh(this,m).le(a,b)))return!0}return e};
+k.rh=function(a,b,c,d,e){if(this.f.isContextLost())return!1;var f=b.viewState,g,h=b.layerStatesArray,l;for(l=h.length-1;0<=l;--l){g=h[l];var m=g.layer;if(nh(g,f.resolution)&&e.call(d,m)&&(g=Kh(this,m).Cc(a,b,c,d)))return g}};var Vm=["canvas","webgl","dom"];
+function Q(a){eb.call(this);var b=Wm(a);this.Hb=void 0!==a.loadTilesWhileAnimating?a.loadTilesWhileAnimating:!1;this.Hc=void 0!==a.loadTilesWhileInteracting?a.loadTilesWhileInteracting:!1;this.Oe=void 0!==a.pixelRatio?a.pixelRatio:gg;this.Ne=b.logos;this.Y=function(){this.i=void 0;this.Uo.call(this,Date.now())}.bind(this);this.Sa=Xc();this.Pe=Xc();this.qb=0;this.f=null;this.Aa=Lb();this.D=this.S=null;this.a=document.createElement("DIV");this.a.className="ol-viewport"+(lg?" ol-touch":"");this.a.style.position=
+"relative";this.a.style.overflow="hidden";this.a.style.width="100%";this.a.style.height="100%";this.a.style.msTouchAction="none";this.a.style.touchAction="none";this.A=document.createElement("DIV");this.A.className="ol-overlaycontainer";this.a.appendChild(this.A);this.v=document.createElement("DIV");this.v.className="ol-overlaycontainer-stopevent";a=["click","dblclick","mousedown","touchstart","mspointerdown",eh,"mousewheel","wheel"];for(var c=0,d=a.length;c<d;++c)B(this.v,a[c],Ya);this.a.appendChild(this.v);
+this.za=new Xg(this);for(var e in hh)B(this.za,hh[e],this.Pg,this);this.ia=b.keyboardEventTarget;this.s=null;B(this.a,"wheel",this.Oc,this);B(this.a,"mousewheel",this.Oc,this);this.o=b.controls;this.l=b.interactions;this.j=b.overlays;this.Cf={};this.C=new b.Wo(this.a,this);this.T=null;this.R=[];this.ta=[];this.qa=new Rh(this.Bk.bind(this),this.hl.bind(this));this.Ee={};B(this,gb("layergroup"),this.Ok,this);B(this,gb("view"),this.il,this);B(this,gb("size"),this.el,this);B(this,gb("target"),this.gl,
+this);this.G(b.values);this.o.forEach(function(a){a.setMap(this)},this);B(this.o,"add",function(a){a.element.setMap(this)},this);B(this.o,"remove",function(a){a.element.setMap(null)},this);this.l.forEach(function(a){a.setMap(this)},this);B(this.l,"add",function(a){a.element.setMap(this)},this);B(this.l,"remove",function(a){a.element.setMap(null)},this);this.j.forEach(this.mg,this);B(this.j,"add",function(a){this.mg(a.element)},this);B(this.j,"remove",function(a){var b=a.element.Xa();void 0!==b&&delete this.Cf[b.toString()];
+a.element.setMap(null)},this)}y(Q,eb);k=Q.prototype;k.uj=function(a){this.o.push(a)};k.vj=function(a){this.l.push(a)};k.kg=function(a){this.xc().Tc().push(a)};k.lg=function(a){this.j.push(a)};k.mg=function(a){var b=a.Xa();void 0!==b&&(this.Cf[b.toString()]=a);a.setMap(this)};k.Wa=function(a){this.render();Array.prototype.push.apply(this.R,arguments)};
+k.ka=function(){Ta(this.za);Ta(this.C);Qa(this.a,"wheel",this.Oc,this);Qa(this.a,"mousewheel",this.Oc,this);void 0!==this.c&&(pa.removeEventListener("resize",this.c,!1),this.c=void 0);this.i&&(pa.cancelAnimationFrame(this.i),this.i=void 0);this.fh(null);eb.prototype.ka.call(this)};k.kd=function(a,b,c,d,e){if(this.f)return a=this.Ma(a),this.C.ra(a,this.f,b,void 0!==c?c:null,void 0!==d?d:qc,void 0!==e?e:null)};
+k.Tl=function(a,b,c,d,e){if(this.f)return this.C.rh(a,this.f,b,void 0!==c?c:null,void 0!==d?d:qc,void 0!==e?e:null)};k.kl=function(a,b,c){if(!this.f)return!1;a=this.Ma(a);return this.C.sh(a,this.f,void 0!==b?b:qc,void 0!==c?c:null)};k.Wj=function(a){return this.Ma(this.Td(a))};k.Td=function(a){var b=this.a.getBoundingClientRect();a=a.changedTouches?a.changedTouches[0]:a;return[a.clientX-b.left,a.clientY-b.top]};k.tf=function(){return this.get("target")};
+k.yc=function(){var a=this.tf();return void 0!==a?"string"===typeof a?document.getElementById(a):a:null};k.Ma=function(a){var b=this.f;return b?(a=a.slice(),sh(b.pixelToCoordinateMatrix,a,a)):null};k.Uj=function(){return this.o};k.nk=function(){return this.j};k.mk=function(a){a=this.Cf[a.toString()];return void 0!==a?a:null};k.ak=function(){return this.l};k.xc=function(){return this.get("layergroup")};k.eh=function(){return this.xc().Tc()};
+k.Ga=function(a){var b=this.f;return b?(a=a.slice(0,2),sh(b.coordinateToPixelMatrix,a,a)):null};k.Za=function(){return this.get("size")};k.aa=function(){return this.get("view")};k.Dk=function(){return this.a};k.Bk=function(a,b,c,d){var e=this.f;if(!(e&&b in e.wantedTiles&&e.wantedTiles[b][a.ma.toString()]))return Infinity;a=c[0]-e.focus[0];c=c[1]-e.focus[1];return 65536*Math.log(d)+Math.sqrt(a*a+c*c)/d};k.Oc=function(a,b){var c=new Vg(b||a.type,this,a);this.Pg(c)};
+k.Pg=function(a){if(this.f){this.T=a.coordinate;a.frameState=this.f;var b=this.l.a,c;if(!1!==this.b(a))for(c=b.length-1;0<=c;c--){var d=b[c];if(d.f()&&!d.handleEvent(a))break}}};k.cl=function(){var a=this.f,b=this.qa;if(!b.Ya()){var c=16,d=c;if(a){var e=a.viewHints;e[0]&&(c=this.Hb?8:0,d=2);e[1]&&(c=this.Hc?8:0,d=2)}b.i<c&&(Qh(b),Sh(b,c,d))}b=this.ta;c=0;for(d=b.length;c<d;++c)b[c](this,a);b.length=0};k.el=function(){this.render()};
+k.gl=function(){var a;this.tf()&&(a=this.yc());if(this.s){for(var b=0,c=this.s.length;b<c;++b)Ka(this.s[b]);this.s=null}a?(a.appendChild(this.a),a=this.ia?this.ia:a,this.s=[B(a,"keydown",this.Oc,this),B(a,"keypress",this.Oc,this)],this.c||(this.c=this.Xc.bind(this),pa.addEventListener("resize",this.c,!1))):(Ue(this.a),void 0!==this.c&&(pa.removeEventListener("resize",this.c,!1),this.c=void 0));this.Xc()};k.hl=function(){this.render()};k.jl=function(){this.render()};
+k.il=function(){this.S&&(Ka(this.S),this.S=null);var a=this.aa();a&&(this.S=B(a,"propertychange",this.jl,this));this.render()};k.Pk=function(){this.render()};k.Qk=function(){this.render()};k.Ok=function(){this.D&&(this.D.forEach(Ka),this.D=null);var a=this.xc();a&&(this.D=[B(a,"propertychange",this.Qk,this),B(a,"change",this.Pk,this)]);this.render()};k.Vo=function(){this.i&&pa.cancelAnimationFrame(this.i);this.Y()};k.render=function(){void 0===this.i&&(this.i=pa.requestAnimationFrame(this.Y))};
+k.Oo=function(a){return this.o.remove(a)};k.Po=function(a){return this.l.remove(a)};k.Ro=function(a){return this.xc().Tc().remove(a)};k.So=function(a){return this.j.remove(a)};
+k.Uo=function(a){var b,c,d,e=this.Za(),f=this.aa(),g=Lb(),h=null;if(void 0!==e&&0<e[0]&&0<e[1]&&f&&Wd(f)){var h=Sd(f,this.f?this.f.viewHints:void 0),l=this.xc().hf(),m={};b=0;for(c=l.length;b<c;++b)m[w(l[b].layer)]=l[b];d=f.V();h={animate:!1,attributions:{},coordinateToPixelMatrix:this.Sa,extent:g,focus:this.T?this.T:d.center,index:this.qb++,layerStates:m,layerStatesArray:l,logos:Ea({},this.Ne),pixelRatio:this.Oe,pixelToCoordinateMatrix:this.Pe,postRenderFunctions:[],size:e,skippedFeatureUids:this.Ee,
+tileQueue:this.qa,time:a,usedTiles:{},viewState:d,viewHints:h,wantedTiles:{}}}if(h){a=this.R;b=e=0;for(c=a.length;b<c;++b)f=a[b],f(this,h)&&(a[e++]=f);a.length=e;h.extent=lc(d.center,d.resolution,d.rotation,h.size,g)}this.f=h;this.C.Ce(h);h&&(h.animate&&this.render(),Array.prototype.push.apply(this.ta,h.postRenderFunctions),0!==this.R.length||h.viewHints[0]||h.viewHints[1]||$b(h.extent,this.Aa)||(this.b(new We("moveend",this,h)),Pb(h.extent,this.Aa)));this.b(new We("postrender",this,h));Tf(this.cl,
+this)};k.ji=function(a){this.set("layergroup",a)};k.Wf=function(a){this.set("size",a)};k.fh=function(a){this.set("target",a)};k.kp=function(a){this.set("view",a)};k.ti=function(a){a=w(a).toString();this.Ee[a]=!0;this.render()};
+k.Xc=function(){var a=this.yc();if(a){var b=pa.getComputedStyle(a);this.Wf([a.offsetWidth-parseFloat(b.borderLeftWidth)-parseFloat(b.paddingLeft)-parseFloat(b.paddingRight)-parseFloat(b.borderRightWidth),a.offsetHeight-parseFloat(b.borderTopWidth)-parseFloat(b.paddingTop)-parseFloat(b.paddingBottom)-parseFloat(b.borderBottomWidth)])}else this.Wf(void 0)};k.wi=function(a){a=w(a).toString();delete this.Ee[a];this.render()};
+function Wm(a){var b=null;void 0!==a.keyboardEventTarget&&(b="string"===typeof a.keyboardEventTarget?document.getElementById(a.keyboardEventTarget):a.keyboardEventTarget);var c={},d={};if(void 0===a.logo||"boolean"===typeof a.logo&&a.logo)d["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszWWMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvYasvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvXH1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1VkbMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLPVcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqTacrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaarldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+HizeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDnBAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSFhYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJREFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxCBrb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7ahgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCnB3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDgq82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC"]=
+"http://openlayers.org/";else{var e=a.logo;"string"===typeof e?d[e]="":e instanceof HTMLElement?d[w(e).toString()]=e:fa(e)&&(d[e.src]=e.href)}e=a.layers instanceof Ti?a.layers:new Ti({layers:a.layers});c.layergroup=e;c.target=a.target;c.view=void 0!==a.view?a.view:new Rd;var e=Hh,f;void 0!==a.renderer?Array.isArray(a.renderer)?f=a.renderer:"string"===typeof a.renderer&&(f=[a.renderer]):f=Vm;var g,h;g=0;for(h=f.length;g<h;++g){var l=f[g];if("canvas"==l){if(ig){e=Ql;break}}else if("dom"==l){e=Yl;break}else if("webgl"==
+l&&bg){e=Sm;break}}var m;void 0!==a.controls?m=Array.isArray(a.controls)?new le(a.controls.slice()):a.controls:m=Kf();var n;void 0!==a.interactions?n=Array.isArray(a.interactions)?new le(a.interactions.slice()):a.interactions:n=Si();a=void 0!==a.overlays?Array.isArray(a.overlays)?new le(a.overlays.slice()):a.overlays:new le;return{controls:m,interactions:n,keyboardEventTarget:b,logos:d,overlays:a,Wo:e,values:c}}bj();function Xm(a){eb.call(this);this.j=a.id;this.o=void 0!==a.insertFirst?a.insertFirst:!0;this.s=void 0!==a.stopEvent?a.stopEvent:!0;this.f=document.createElement("DIV");this.f.className="ol-overlay-container";this.f.style.position="absolute";this.autoPan=void 0!==a.autoPan?a.autoPan:!1;this.i=void 0!==a.autoPanAnimation?a.autoPanAnimation:{};this.l=void 0!==a.autoPanMargin?a.autoPanMargin:20;this.a={Md:"",fe:"",De:"",Fe:"",visible:!0};this.c=null;B(this,gb("element"),this.Jk,this);B(this,gb("map"),
+this.Vk,this);B(this,gb("offset"),this.Zk,this);B(this,gb("position"),this.al,this);B(this,gb("positioning"),this.bl,this);void 0!==a.element&&this.fi(a.element);this.li(void 0!==a.offset?a.offset:[0,0]);this.oi(void 0!==a.positioning?a.positioning:"top-left");void 0!==a.position&&this.uf(a.position)}y(Xm,eb);k=Xm.prototype;k.Sd=function(){return this.get("element")};k.Xa=function(){return this.j};k.he=function(){return this.get("map")};k.Kg=function(){return this.get("offset")};k.gh=function(){return this.get("position")};
+k.Lg=function(){return this.get("positioning")};k.Jk=function(){Ve(this.f);var a=this.Sd();a&&this.f.appendChild(a)};k.Vk=function(){this.c&&(Ue(this.f),Ka(this.c),this.c=null);var a=this.he();a&&(this.c=B(a,"postrender",this.render,this),Ym(this),a=this.s?a.v:a.A,this.o?a.insertBefore(this.f,a.childNodes[0]||null):a.appendChild(this.f))};k.render=function(){Ym(this)};k.Zk=function(){Ym(this)};
+k.al=function(){Ym(this);if(void 0!==this.get("position")&&this.autoPan){var a=this.he();if(void 0!==a&&a.yc()){var b=Zm(a.yc(),a.Za()),c=this.Sd(),d=c.offsetWidth,e=c.currentStyle||pa.getComputedStyle(c),d=d+(parseInt(e.marginLeft,10)+parseInt(e.marginRight,10)),e=c.offsetHeight,f=c.currentStyle||pa.getComputedStyle(c),e=e+(parseInt(f.marginTop,10)+parseInt(f.marginBottom,10)),g=Zm(c,[d,e]),c=this.l;Ub(b,g)||(d=g[0]-b[0],e=b[2]-g[2],f=g[1]-b[1],g=b[3]-g[3],b=[0,0],0>d?b[0]=d-c:0>e&&(b[0]=Math.abs(e)+
+c),0>f?b[1]=f-c:0>g&&(b[1]=Math.abs(g)+c),0===b[0]&&0===b[1])||(c=a.aa().ab(),d=a.Ga(c),b=[d[0]+b[0],d[1]+b[1]],this.i&&(this.i.source=c,a.Wa(ce(this.i))),a.aa().mb(a.Ma(b)))}}};k.bl=function(){Ym(this)};k.fi=function(a){this.set("element",a)};k.setMap=function(a){this.set("map",a)};k.li=function(a){this.set("offset",a)};k.uf=function(a){this.set("position",a)};function Zm(a,b){var c=a.getBoundingClientRect(),d=c.left+pa.pageXOffset,c=c.top+pa.pageYOffset;return[d,c,d+b[0],c+b[1]]}
+k.oi=function(a){this.set("positioning",a)};function $m(a,b){a.a.visible!==b&&(a.f.style.display=b?"":"none",a.a.visible=b)}
+function Ym(a){var b=a.he(),c=a.gh();if(void 0!==b&&b.f&&void 0!==c){var c=b.Ga(c),d=b.Za(),b=a.f.style,e=a.Kg(),f=a.Lg(),g=e[0],e=e[1];if("bottom-right"==f||"center-right"==f||"top-right"==f)""!==a.a.fe&&(a.a.fe=b.left=""),g=Math.round(d[0]-c[0]-g)+"px",a.a.De!=g&&(a.a.De=b.right=g);else{""!==a.a.De&&(a.a.De=b.right="");if("bottom-center"==f||"center-center"==f||"top-center"==f)g-=a.f.offsetWidth/2;g=Math.round(c[0]+g)+"px";a.a.fe!=g&&(a.a.fe=b.left=g)}if("bottom-left"==f||"bottom-center"==f||"bottom-right"==
+f)""!==a.a.Fe&&(a.a.Fe=b.top=""),c=Math.round(d[1]-c[1]-e)+"px",a.a.Md!=c&&(a.a.Md=b.bottom=c);else{""!==a.a.Md&&(a.a.Md=b.bottom="");if("center-left"==f||"center-center"==f||"center-right"==f)e-=a.f.offsetHeight/2;c=Math.round(c[1]+e)+"px";a.a.Fe!=c&&(a.a.Fe=b.top=c)}$m(a,!0)}else $m(a,!1)};function an(a){a=a?a:{};this.l=void 0!==a.collapsed?a.collapsed:!0;this.o=void 0!==a.collapsible?a.collapsible:!0;this.o||(this.l=!1);var b=void 0!==a.className?a.className:"ol-overviewmap",c=void 0!==a.tipLabel?a.tipLabel:"Overview map",d=void 0!==a.collapseLabel?a.collapseLabel:"\u00ab";"string"===typeof d?(this.j=document.createElement("span"),this.j.textContent=d):this.j=d;d=void 0!==a.label?a.label:"\u00bb";"string"===typeof d?(this.v=document.createElement("span"),this.v.textContent=d):this.v=
+d;var e=this.o&&!this.l?this.j:this.v,d=document.createElement("button");d.setAttribute("type","button");d.title=c;d.appendChild(e);B(d,"click",this.gm,this);c=document.createElement("DIV");c.className="ol-overviewmap-map";var f=this.f=new Q({controls:new le,interactions:new le,target:c,view:a.view});a.layers&&a.layers.forEach(function(a){f.kg(a)},this);e=document.createElement("DIV");e.className="ol-overviewmap-box";e.style.boxSizing="border-box";this.A=new Xm({position:[0,0],positioning:"bottom-left",
+element:e});this.f.lg(this.A);e=document.createElement("div");e.className=b+" ol-unselectable ol-control"+(this.l&&this.o?" ol-collapsed":"")+(this.o?"":" ol-uncollapsible");e.appendChild(c);e.appendChild(d);Xe.call(this,{element:e,render:a.render?a.render:bn,target:a.target})}y(an,Xe);k=an.prototype;
+k.setMap=function(a){var b=this.a;a!==b&&(b&&(b=b.aa())&&Qa(b,gb("rotation"),this.de,this),Xe.prototype.setMap.call(this,a),a&&(this.s.push(B(a,"propertychange",this.Wk,this)),0===this.f.eh().dc()&&this.f.ji(a.xc()),a=a.aa()))&&(B(a,gb("rotation"),this.de,this),Wd(a)&&(this.f.Xc(),cn(this)))};k.Wk=function(a){"view"===a.key&&((a=a.oldValue)&&Qa(a,gb("rotation"),this.de,this),a=this.a.aa(),B(a,gb("rotation"),this.de,this))};k.de=function(){this.f.aa().ie(this.a.aa().La())};
+function bn(){var a=this.a,b=this.f;if(a.f&&b.f){var c=a.Za(),a=a.aa().Kc(c),d=b.Za(),c=b.aa().Kc(d),e=b.Ga(fc(a)),f=b.Ga(dc(a)),b=Math.abs(e[0]-f[0]),e=Math.abs(e[1]-f[1]),f=d[0],d=d[1];b<.1*f||e<.1*d||b>.75*f||e>.75*d?cn(this):Ub(c,a)||(a=this.f,c=this.a.aa(),a.aa().mb(c.ab()))}dn(this)}function cn(a){var b=a.a;a=a.f;var c=b.Za(),b=b.aa().Kc(c),c=a.Za();a=a.aa();oc(b,1/(.1*Math.pow(2,Math.log(7.5)/Math.LN2/2)));a.cf(b,c)}
+function dn(a){var b=a.a,c=a.f;if(b.f&&c.f){var d=b.Za(),e=b.aa(),f=c.aa();c.Za();var c=e.La(),b=a.A,g=a.A.Sd(),e=e.Kc(d),d=f.$(),f=cc(e),e=ec(e),h;if(a=a.a.aa().ab())h=[f[0]-a[0],f[1]-a[1]],Gb(h,c),Bb(h,a);b.uf(h);g&&(g.style.width=Math.abs((f[0]-e[0])/d)+"px",g.style.height=Math.abs((e[1]-f[1])/d)+"px")}}k.gm=function(a){a.preventDefault();en(this)};
+function en(a){a.element.classList.toggle("ol-collapsed");a.l?Te(a.j,a.v):Te(a.v,a.j);a.l=!a.l;var b=a.f;a.l||b.f||(b.Xc(),cn(a),Pa(b,"postrender",function(){dn(this)},a))}k.fm=function(){return this.o};k.im=function(a){this.o!==a&&(this.o=a,this.element.classList.toggle("ol-uncollapsible"),!a&&this.l&&en(this))};k.hm=function(a){this.o&&this.l!==a&&en(this)};k.em=function(){return this.l};k.pk=function(){return this.f};function fn(a){a=a?a:{};var b=void 0!==a.className?a.className:"ol-scale-line";this.o=document.createElement("DIV");this.o.className=b+"-inner";this.f=document.createElement("DIV");this.f.className=b+" ol-unselectable";this.f.appendChild(this.o);this.v=null;this.j=void 0!==a.minWidth?a.minWidth:64;this.l=!1;this.C=void 0;this.A="";Xe.call(this,{element:this.f,render:a.render?a.render:gn,target:a.target});B(this,gb("units"),this.R,this);this.D(a.units||"metric")}y(fn,Xe);var hn=[1,2,5];
+fn.prototype.wb=function(){return this.get("units")};function gn(a){(a=a.frameState)?this.v=a.viewState:this.v=null;jn(this)}fn.prototype.R=function(){jn(this)};fn.prototype.D=function(a){this.set("units",a)};
+function jn(a){var b=a.v;if(b){var c=b.projection,d=c.$b(),b=c.getPointResolution(b.resolution,b.center)*d,d=a.j*b,c="",e=a.wb();"degrees"==e?(c=uc.degrees,b/=c,d<c/60?(c="\u2033",b*=3600):d<c?(c="\u2032",b*=60):c="\u00b0"):"imperial"==e?.9144>d?(c="in",b/=.0254):1609.344>d?(c="ft",b/=.3048):(c="mi",b/=1609.344):"nautical"==e?(b/=1852,c="nm"):"metric"==e?1>d?(c="mm",b*=1E3):1E3>d?c="m":(c="km",b/=1E3):"us"==e&&(.9144>d?(c="in",b*=39.37):1609.344>d?(c="ft",b/=.30480061):(c="mi",b/=1609.3472));for(var e=
+3*Math.floor(Math.log(a.j*b)/Math.log(10)),f;;){f=hn[(e%3+3)%3]*Math.pow(10,Math.floor(e/3));d=Math.round(f/b);if(isNaN(d)){a.f.style.display="none";a.l=!1;return}if(d>=a.j)break;++e}b=f+" "+c;a.A!=b&&(a.o.innerHTML=b,a.A=b);a.C!=d&&(a.o.style.width=d+"px",a.C=d);a.l||(a.f.style.display="",a.l=!0)}else a.l&&(a.f.style.display="none",a.l=!1)};function kn(a){a=a?a:{};this.f=void 0;this.l=ln;this.v=[];this.C=this.j=0;this.T=null;this.ia=!1;this.Y=void 0!==a.duration?a.duration:200;var b=void 0!==a.className?a.className:"ol-zoomslider",c=document.createElement("button");c.setAttribute("type","button");c.className=b+"-thumb ol-unselectable";var d=document.createElement("div");d.className=b+" ol-unselectable ol-control";d.appendChild(c);this.o=new Pg(d);B(this.o,zg,this.Ik,this);B(this.o,Ag,this.Ng,this);B(this.o,Bg,this.Og,this);B(d,"click",
+this.Hk,this);B(c,"click",Ya);Xe.call(this,{element:d,render:a.render?a.render:mn})}y(kn,Xe);kn.prototype.ka=function(){Ta(this.o);Xe.prototype.ka.call(this)};var ln=0;k=kn.prototype;k.setMap=function(a){Xe.prototype.setMap.call(this,a);a&&a.render()};
+function mn(a){if(a.frameState){if(!this.ia){var b=this.element,c=b.offsetWidth,d=b.offsetHeight,e=b.firstElementChild,f=pa.getComputedStyle(e),b=e.offsetWidth+parseFloat(f.marginRight)+parseFloat(f.marginLeft),e=e.offsetHeight+parseFloat(f.marginTop)+parseFloat(f.marginBottom);this.T=[b,e];c>d?(this.l=1,this.C=c-b):(this.l=ln,this.j=d-e);this.ia=!0}a=a.frameState.viewState.resolution;a!==this.f&&(this.f=a,nn(this,a))}}
+k.Hk=function(a){var b=this.a,c=b.aa(),d=c.$();b.Wa(ee({resolution:d,duration:this.Y,easing:Zd}));a=on(this,sa(1===this.l?(a.offsetX-this.T[0]/2)/this.C:(a.offsetY-this.T[1]/2)/this.j,0,1));c.Ub(c.constrainResolution(a))};
+k.Ik=function(a){if(!this.A&&a.b.target===this.element.firstElementChild&&(Xd(this.a.aa(),1),this.D=a.clientX,this.R=a.clientY,this.A=!0,0===this.v.length)){a=this.Ng;var b=this.Og;this.v.push(B(document,"mousemove",a,this),B(document,"touchmove",a,this),B(document,Ag,a,this),B(document,"mouseup",b,this),B(document,"touchend",b,this),B(document,Bg,b,this))}};
+k.Ng=function(a){if(this.A){var b=this.element.firstElementChild;this.f=on(this,sa(1===this.l?(a.clientX-this.D+parseInt(b.style.left,10))/this.C:(a.clientY-this.R+parseInt(b.style.top,10))/this.j,0,1));this.a.aa().Ub(this.f);nn(this,this.f);this.D=a.clientX;this.R=a.clientY}};k.Og=function(){if(this.A){var a=this.a,b=a.aa();Xd(b,-1);a.Wa(ee({resolution:this.f,duration:this.Y,easing:Zd}));a=b.constrainResolution(this.f);b.Ub(a);this.A=!1;this.R=this.D=void 0;this.v.forEach(Ka);this.v.length=0}};
+function nn(a,b){var c;c=1-Vd(a.a.aa())(b);var d=a.element.firstElementChild;1==a.l?d.style.left=a.C*c+"px":d.style.top=a.j*c+"px"}function on(a,b){return Ud(a.a.aa())(1-b)};function pn(a){a=a?a:{};this.f=a.extent?a.extent:null;var b=void 0!==a.className?a.className:"ol-zoom-extent",c=void 0!==a.label?a.label:"E",d=void 0!==a.tipLabel?a.tipLabel:"Fit to extent",e=document.createElement("button");e.setAttribute("type","button");e.title=d;e.appendChild("string"===typeof c?document.createTextNode(c):c);B(e,"click",this.l,this);c=document.createElement("div");c.className=b+" ol-unselectable ol-control";c.appendChild(e);Xe.call(this,{element:c,target:a.target})}y(pn,Xe);
+pn.prototype.l=function(a){a.preventDefault();var b=this.a;a=b.aa();var c=this.f?this.f:a.l.H(),b=b.Za();a.cf(c,b)};function qn(a){eb.call(this);a=a?a:{};this.a=null;B(this,gb("tracking"),this.Il,this);this.rf(void 0!==a.tracking?a.tracking:!1)}y(qn,eb);k=qn.prototype;k.ka=function(){this.rf(!1);eb.prototype.ka.call(this)};
+k.co=function(a){if(null!==a.alpha){var b=wa(a.alpha);this.set("alpha",b);"boolean"===typeof a.absolute&&a.absolute?this.set("heading",b):ea(a.webkitCompassHeading)&&-1!=a.webkitCompassAccuracy&&this.set("heading",wa(a.webkitCompassHeading))}null!==a.beta&&this.set("beta",wa(a.beta));null!==a.gamma&&this.set("gamma",wa(a.gamma));this.u()};k.Oj=function(){return this.get("alpha")};k.Rj=function(){return this.get("beta")};k.Yj=function(){return this.get("gamma")};k.Hl=function(){return this.get("heading")};
+k.$g=function(){return this.get("tracking")};k.Il=function(){if(jg){var a=this.$g();a&&!this.a?this.a=B(pa,"deviceorientation",this.co,this):a||null===this.a||(Ka(this.a),this.a=null)}};k.rf=function(a){this.set("tracking",a)};function rn(){this.defaultDataProjection=null}function sn(a,b,c){var d;c&&(d={dataProjection:c.dataProjection?c.dataProjection:a.Oa(b),featureProjection:c.featureProjection});return tn(a,d)}function tn(a,b){var c;b&&(c={featureProjection:b.featureProjection,dataProjection:b.dataProjection?b.dataProjection:a.defaultDataProjection,rightHanded:b.rightHanded},b.decimals&&(c.decimals=b.decimals));return c}
+function un(a,b,c){var d=c?yc(c.featureProjection):null,e=c?yc(c.dataProjection):null,f;d&&e&&!Oc(d,e)?a instanceof Tc?f=(b?a.clone():a).jb(b?d:e,b?e:d):f=Sc(b?a.slice():a,b?d:e,b?e:d):f=a;if(b&&c&&c.decimals){var g=Math.pow(10,c.decimals);a=function(a){for(var b=0,c=a.length;b<c;++b)a[b]=Math.round(a[b]*g)/g;return a};Array.isArray(f)?a(f):f.rc(a)}return f};function vn(){this.defaultDataProjection=null}y(vn,rn);function wn(a){return fa(a)?a:"string"===typeof a?(a=JSON.parse(a))?a:null:null}k=vn.prototype;k.X=function(){return"json"};k.Rb=function(a,b){return this.Uc(wn(a),sn(this,a,b))};k.Fa=function(a,b){return this.Jf(wn(a),sn(this,a,b))};k.Vc=function(a,b){return this.Rh(wn(a),sn(this,a,b))};k.Oa=function(a){return this.Yh(wn(a))};k.Dd=function(a,b){return JSON.stringify(this.Yc(a,b))};k.Xb=function(a,b){return JSON.stringify(this.Ie(a,b))};
+k.Zc=function(a,b){return JSON.stringify(this.Ke(a,b))};function xn(a,b,c,d,e,f){var g=NaN,h=NaN,l=(c-b)/d;if(0!==l)if(1==l)g=a[b],h=a[b+1];else if(2==l)g=(1-e)*a[b]+e*a[b+d],h=(1-e)*a[b+1]+e*a[b+d+1];else{var h=a[b],l=a[b+1],m=0,g=[0],n;for(n=b+d;n<c;n+=d){var p=a[n],q=a[n+1],m=m+Math.sqrt((p-h)*(p-h)+(q-l)*(q-l));g.push(m);h=p;l=q}c=e*m;l=0;m=g.length;for(n=!1;l<m;)e=l+(m-l>>1),h=+ib(g[e],c),0>h?l=e+1:(m=e,n=!h);e=n?l:~l;0>e?(c=(c-g[-e-2])/(g[-e-1]-g[-e-2]),b+=(-e-2)*d,g=za(a[b],a[b+d],c),h=za(a[b+1],a[b+d+1],c)):(g=a[b+e*d],h=a[b+e*d+1])}return f?(f[0]=
+g,f[1]=h,f):[g,h]}function yn(a,b,c,d,e,f){if(c==b)return null;if(e<a[b+d-1])return f?(c=a.slice(b,b+d),c[d-1]=e,c):null;if(a[c-1]<e)return f?(c=a.slice(c-d,c),c[d-1]=e,c):null;if(e==a[b+d-1])return a.slice(b,b+d);b/=d;for(c/=d;b<c;)f=b+c>>1,e<a[(f+1)*d-1]?c=f:b=f+1;c=a[b*d-1];if(e==c)return a.slice((b-1)*d,(b-1)*d+d);f=(e-c)/(a[(b+1)*d-1]-c);c=[];var g;for(g=0;g<d-1;++g)c.push(za(a[(b-1)*d+g],a[b*d+g],f));c.push(e);return c}
+function zn(a,b,c,d,e,f){var g=0;if(f)return yn(a,g,b[b.length-1],c,d,e);if(d<a[c-1])return e?(a=a.slice(0,c),a[c-1]=d,a):null;if(a[a.length-1]<d)return e?(a=a.slice(a.length-c),a[c-1]=d,a):null;e=0;for(f=b.length;e<f;++e){var h=b[e];if(g!=h){if(d<a[g+c-1])break;if(d<=a[h-1])return yn(a,g,h,c,d,!1);g=h}}return null};function R(a,b){hd.call(this);this.i=null;this.C=this.D=this.j=-1;this.pa(a,b)}y(R,hd);k=R.prototype;k.wj=function(a){this.B?mb(this.B,a):this.B=a.slice();this.u()};k.clone=function(){var a=new R(null);a.ba(this.f,this.B.slice());return a};k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;this.C!=this.g&&(this.D=Math.sqrt(od(this.B,0,this.B.length,this.a,0)),this.C=this.g);return qd(this.B,0,this.B.length,this.a,this.D,!1,a,b,c,d)};
+k.Lj=function(a,b){return Fd(this.B,0,this.B.length,this.a,a,b)};k.lm=function(a,b){return"XYM"!=this.f&&"XYZM"!=this.f?null:yn(this.B,0,this.B.length,this.a,a,void 0!==b?b:!1)};k.Z=function(){return vd(this.B,0,this.B.length,this.a)};k.Bg=function(a,b){return xn(this.B,0,this.B.length,this.a,a,b)};k.mm=function(){var a=this.B,b=this.a,c=a[0],d=a[1],e=0,f;for(f=0+b;f<this.B.length;f+=b)var g=a[f],h=a[f+1],e=e+Math.sqrt((g-c)*(g-c)+(h-d)*(h-d)),c=g,d=h;return e};
+function Fj(a){a.j!=a.g&&(a.i=a.Bg(.5,a.i),a.j=a.g);return a.i}k.Nc=function(a){var b=[];b.length=xd(this.B,0,this.B.length,this.a,a,b,0);a=new R(null);a.ba("XY",b);return a};k.X=function(){return"LineString"};k.Ka=function(a){return Gd(this.B,0,this.B.length,this.a,a)};k.pa=function(a,b){a?(kd(this,b,a,1),this.B||(this.B=[]),this.B.length=td(this.B,0,a,this.a),this.u()):this.ba("XY",null)};k.ba=function(a,b){jd(this,a,b);this.u()};function S(a,b){hd.call(this);this.i=[];this.j=this.C=-1;this.pa(a,b)}y(S,hd);k=S.prototype;k.xj=function(a){this.B?mb(this.B,a.la().slice()):this.B=a.la().slice();this.i.push(this.B.length);this.u()};k.clone=function(){var a=new S(null);a.ba(this.f,this.B.slice(),this.i.slice());return a};k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;this.j!=this.g&&(this.C=Math.sqrt(pd(this.B,0,this.i,this.a,0)),this.j=this.g);return rd(this.B,0,this.i,this.a,this.C,!1,a,b,c,d)};
+k.om=function(a,b,c){return"XYM"!=this.f&&"XYZM"!=this.f||0===this.B.length?null:zn(this.B,this.i,this.a,a,void 0!==b?b:!1,void 0!==c?c:!1)};k.Z=function(){return wd(this.B,0,this.i,this.a)};k.Db=function(){return this.i};k.fk=function(a){if(0>a||this.i.length<=a)return null;var b=new R(null);b.ba(this.f,this.B.slice(0===a?0:this.i[a-1],this.i[a]));return b};
+k.md=function(){var a=this.B,b=this.i,c=this.f,d=[],e=0,f,g;f=0;for(g=b.length;f<g;++f){var h=b[f],l=new R(null);l.ba(c,a.slice(e,h));d.push(l);e=h}return d};function Gj(a){var b=[],c=a.B,d=0,e=a.i;a=a.a;var f,g;f=0;for(g=e.length;f<g;++f){var h=e[f],d=xn(c,d,h,a,.5);mb(b,d);d=h}return b}k.Nc=function(a){var b=[],c=[],d=this.B,e=this.i,f=this.a,g=0,h=0,l,m;l=0;for(m=e.length;l<m;++l){var n=e[l],h=xd(d,g,n,f,a,b,h);c.push(h);g=n}b.length=h;a=new S(null);a.ba("XY",b,c);return a};k.X=function(){return"MultiLineString"};
+k.Ka=function(a){a:{var b=this.B,c=this.i,d=this.a,e=0,f,g;f=0;for(g=c.length;f<g;++f){if(Gd(b,e,c[f],d,a)){a=!0;break a}e=c[f]}a=!1}return a};k.pa=function(a,b){if(a){kd(this,b,a,2);this.B||(this.B=[]);var c=ud(this.B,0,a,this.a,this.i);this.B.length=0===c.length?0:c[c.length-1];this.u()}else this.ba("XY",null,this.i)};k.ba=function(a,b,c){jd(this,a,b);this.i=c;this.u()};
+function An(a,b){var c=a.f,d=[],e=[],f,g;f=0;for(g=b.length;f<g;++f){var h=b[f];0===f&&(c=h.f);mb(d,h.la());e.push(d.length)}a.ba(c,d,e)};function Bn(a,b){hd.call(this);this.pa(a,b)}y(Bn,hd);k=Bn.prototype;k.zj=function(a){this.B?mb(this.B,a.la()):this.B=a.la().slice();this.u()};k.clone=function(){var a=new Bn(null);a.ba(this.f,this.B.slice());return a};k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;var e=this.B,f=this.a,g,h,l;g=0;for(h=e.length;g<h;g+=f)if(l=va(a,b,e[g],e[g+1]),l<d){d=l;for(l=0;l<f;++l)c[l]=e[g+l];c.length=f}return d};k.Z=function(){return vd(this.B,0,this.B.length,this.a)};
+k.rk=function(a){var b=this.B?this.B.length/this.a:0;if(0>a||b<=a)return null;b=new C(null);b.ba(this.f,this.B.slice(a*this.a,(a+1)*this.a));return b};k.je=function(){var a=this.B,b=this.f,c=this.a,d=[],e,f;e=0;for(f=a.length;e<f;e+=c){var g=new C(null);g.ba(b,a.slice(e,e+c));d.push(g)}return d};k.X=function(){return"MultiPoint"};k.Ka=function(a){var b=this.B,c=this.a,d,e,f,g;d=0;for(e=b.length;d<e;d+=c)if(f=b[d],g=b[d+1],Tb(a,f,g))return!0;return!1};
+k.pa=function(a,b){a?(kd(this,b,a,1),this.B||(this.B=[]),this.B.length=td(this.B,0,a,this.a),this.u()):this.ba("XY",null)};k.ba=function(a,b){jd(this,a,b);this.u()};function T(a,b){hd.call(this);this.i=[];this.C=-1;this.D=null;this.T=this.R=this.S=-1;this.j=null;this.pa(a,b)}y(T,hd);k=T.prototype;k.Aj=function(a){if(this.B){var b=this.B.length;mb(this.B,a.la());a=a.Db().slice();var c,d;c=0;for(d=a.length;c<d;++c)a[c]+=b}else this.B=a.la().slice(),a=a.Db().slice(),this.i.push();this.i.push(a);this.u()};k.clone=function(){for(var a=new T(null),b=this.i.length,c=Array(b),d=0;d<b;++d)c[d]=this.i[d].slice();Cn(a,this.f,this.B.slice(),c);return a};
+k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;if(this.R!=this.g){var e=this.i,f=0,g=0,h,l;h=0;for(l=e.length;h<l;++h)var m=e[h],g=pd(this.B,f,m,this.a,g),f=m[m.length-1];this.S=Math.sqrt(g);this.R=this.g}e=Hj(this);f=this.i;g=this.a;h=this.S;l=0;var m=[NaN,NaN],n,p;n=0;for(p=f.length;n<p;++n){var q=f[n];d=rd(e,l,q,g,h,!0,a,b,c,d,m);l=q[q.length-1]}return d};
+k.Bc=function(a,b){var c;a:{c=Hj(this);var d=this.i,e=0;if(0!==d.length){var f,g;f=0;for(g=d.length;f<g;++f){var h=d[f];if(Dd(c,e,h,this.a,a,b)){c=!0;break a}e=h[h.length-1]}}c=!1}return c};k.pm=function(){var a=Hj(this),b=this.i,c=0,d=0,e,f;e=0;for(f=b.length;e<f;++e)var g=b[e],d=d+md(a,c,g,this.a),c=g[g.length-1];return d};
+k.Z=function(a){var b;void 0!==a?(b=Hj(this).slice(),Ld(b,this.i,this.a,a)):b=this.B;a=b;b=this.i;var c=this.a,d=0,e=[],f=0,g,h;g=0;for(h=b.length;g<h;++g){var l=b[g];e[f++]=wd(a,d,l,c,e[f]);d=l[l.length-1]}e.length=f;return e};
+function Ij(a){if(a.C!=a.g){var b=a.B,c=a.i,d=a.a,e=0,f=[],g,h;g=0;for(h=c.length;g<h;++g){var l=c[g],e=Yb(b,e,l[0],d);f.push((e[0]+e[2])/2,(e[1]+e[3])/2);e=l[l.length-1]}b=Hj(a);c=a.i;d=a.a;g=0;h=[];l=0;for(e=c.length;l<e;++l){var m=c[l];h=Ed(b,g,m,d,f,2*l,h);g=m[m.length-1]}a.D=h;a.C=a.g}return a.D}k.ck=function(){var a=new Bn(null);a.ba("XY",Ij(this).slice());return a};
+function Hj(a){if(a.T!=a.g){var b=a.B,c;a:{c=a.i;var d,e;d=0;for(e=c.length;d<e;++d)if(!Jd(b,c[d],a.a,void 0)){c=!1;break a}c=!0}c?a.j=b:(a.j=b.slice(),a.j.length=Ld(a.j,a.i,a.a));a.T=a.g}return a.j}k.Nc=function(a){var b=[],c=[],d=this.B,e=this.i,f=this.a;a=Math.sqrt(a);var g=0,h=0,l,m;l=0;for(m=e.length;l<m;++l){var n=e[l],p=[],h=yd(d,g,n,f,a,b,h,p);c.push(p);g=n[n.length-1]}b.length=h;d=new T(null);Cn(d,"XY",b,c);return d};
+k.tk=function(a){if(0>a||this.i.length<=a)return null;var b;0===a?b=0:(b=this.i[a-1],b=b[b.length-1]);a=this.i[a].slice();var c=a[a.length-1];if(0!==b){var d,e;d=0;for(e=a.length;d<e;++d)a[d]-=b}d=new E(null);d.ba(this.f,this.B.slice(b,c),a);return d};k.Wd=function(){var a=this.f,b=this.B,c=this.i,d=[],e=0,f,g,h,l;f=0;for(g=c.length;f<g;++f){var m=c[f].slice(),n=m[m.length-1];if(0!==e)for(h=0,l=m.length;h<l;++h)m[h]-=e;h=new E(null);h.ba(a,b.slice(e,n),m);d.push(h);e=n}return d};k.X=function(){return"MultiPolygon"};
+k.Ka=function(a){a:{var b=Hj(this),c=this.i,d=this.a,e=0,f,g;f=0;for(g=c.length;f<g;++f){var h=c[f];if(Hd(b,e,h,d,a)){a=!0;break a}e=h[h.length-1]}a=!1}return a};k.pa=function(a,b){if(a){kd(this,b,a,3);this.B||(this.B=[]);var c=this.B,d=this.a,e=this.i,f=0,e=e?e:[],g=0,h,l;h=0;for(l=a.length;h<l;++h)f=ud(c,f,a[h],d,e[g]),e[g++]=f,f=f[f.length-1];e.length=g;0===e.length?this.B.length=0:(c=e[e.length-1],this.B.length=0===c.length?0:c[c.length-1]);this.u()}else Cn(this,"XY",null,this.i)};
+function Cn(a,b,c,d){jd(a,b,c);a.i=d;a.u()}function Dn(a,b){var c=a.f,d=[],e=[],f,g,h;f=0;for(g=b.length;f<g;++f){var l=b[f];0===f&&(c=l.f);var m=d.length;h=l.Db();var n,p;n=0;for(p=h.length;n<p;++n)h[n]+=m;mb(d,l.la());e.push(h)}Cn(a,c,d,e)};function En(a){a=a?a:{};this.defaultDataProjection=null;this.b=a.geometryName}y(En,vn);
+function Fn(a,b){if(!a)return null;var c;if(ea(a.x)&&ea(a.y))c="Point";else if(a.points)c="MultiPoint";else if(a.paths)c=1===a.paths.length?"LineString":"MultiLineString";else if(a.rings){var d=a.rings,e=Gn(a),f=[];c=[];var g,h;g=0;for(h=d.length;g<h;++g){var l=lb(d[g]);Id(l,0,l.length,e.length)?f.push([d[g]]):c.push(d[g])}for(;c.length;){d=c.shift();e=!1;for(g=f.length-1;0<=g;g--)if(Ub((new zd(f[g][0])).H(),(new zd(d)).H())){f[g].push(d);e=!0;break}e||f.push([d.reverse()])}a=Ea({},a);1===f.length?
+(c="Polygon",a.rings=f[0]):(c="MultiPolygon",a.rings=f)}return un((0,Hn[c])(a),!1,b)}function Gn(a){var b="XY";!0===a.hasZ&&!0===a.hasM?b="XYZM":!0===a.hasZ?b="XYZ":!0===a.hasM&&(b="XYM");return b}function In(a){a=a.f;return{hasZ:"XYZ"===a||"XYZM"===a,hasM:"XYM"===a||"XYZM"===a}}
+var Hn={Point:function(a){return void 0!==a.m&&void 0!==a.z?new C([a.x,a.y,a.z,a.m],"XYZM"):void 0!==a.z?new C([a.x,a.y,a.z],"XYZ"):void 0!==a.m?new C([a.x,a.y,a.m],"XYM"):new C([a.x,a.y])},LineString:function(a){return new R(a.paths[0],Gn(a))},Polygon:function(a){return new E(a.rings,Gn(a))},MultiPoint:function(a){return new Bn(a.points,Gn(a))},MultiLineString:function(a){return new S(a.paths,Gn(a))},MultiPolygon:function(a){return new T(a.rings,Gn(a))}},Jn={Point:function(a){var b=a.Z();a=a.f;if("XYZ"===
+a)return{x:b[0],y:b[1],z:b[2]};if("XYM"===a)return{x:b[0],y:b[1],m:b[2]};if("XYZM"===a)return{x:b[0],y:b[1],z:b[2],m:b[3]};if("XY"===a)return{x:b[0],y:b[1]}},LineString:function(a){var b=In(a);return{hasZ:b.hasZ,hasM:b.hasM,paths:[a.Z()]}},Polygon:function(a){var b=In(a);return{hasZ:b.hasZ,hasM:b.hasM,rings:a.Z(!1)}},MultiPoint:function(a){var b=In(a);return{hasZ:b.hasZ,hasM:b.hasM,points:a.Z()}},MultiLineString:function(a){var b=In(a);return{hasZ:b.hasZ,hasM:b.hasM,paths:a.Z()}},MultiPolygon:function(a){var b=
+In(a);a=a.Z(!1);for(var c=[],d=0;d<a.length;d++)for(var e=a[d].length-1;0<=e;e--)c.push(a[d][e]);return{hasZ:b.hasZ,hasM:b.hasM,rings:c}}};k=En.prototype;k.Uc=function(a,b){var c=Fn(a.geometry,b),d=new Ik;this.b&&d.Ec(this.b);d.Ua(c);b&&b.mf&&a.attributes[b.mf]&&d.mc(a.attributes[b.mf]);a.attributes&&d.G(a.attributes);return d};
+k.Jf=function(a,b){var c=b?b:{};if(a.features){var d=[],e=a.features,f,g;c.mf=a.objectIdFieldName;f=0;for(g=e.length;f<g;++f)d.push(this.Uc(e[f],c));return d}return[this.Uc(a,c)]};k.Rh=function(a,b){return Fn(a,b)};k.Yh=function(a){return a.spatialReference&&a.spatialReference.wkid?yc("EPSG:"+a.spatialReference.wkid):null};function Kn(a,b){return(0,Jn[a.X()])(un(a,!0,b),b)}k.Ke=function(a,b){return Kn(a,tn(this,b))};
+k.Yc=function(a,b){b=tn(this,b);var c={},d=a.W();d&&(c.geometry=Kn(d,b));d=a.O();delete d[a.a];c.attributes=Ha(d)?{}:d;b&&b.featureProjection&&(c.spatialReference={wkid:yc(b.featureProjection).cb.split(":").pop()});return c};k.Ie=function(a,b){b=tn(this,b);var c=[],d,e;d=0;for(e=a.length;d<e;++d)c.push(this.Yc(a[d],b));return{features:c}};function Ln(a){Tc.call(this);this.c=a?a:null;Mn(this)}y(Ln,Tc);function Nn(a){var b=[],c,d;c=0;for(d=a.length;c<d;++c)b.push(a[c].clone());return b}function On(a){var b,c;if(a.c)for(b=0,c=a.c.length;b<c;++b)Qa(a.c[b],"change",a.u,a)}function Mn(a){var b,c;if(a.c)for(b=0,c=a.c.length;b<c;++b)B(a.c[b],"change",a.u,a)}k=Ln.prototype;k.clone=function(){var a=new Ln(null);a.hi(this.c);return a};
+k.sb=function(a,b,c,d){if(d<Rb(this.H(),a,b))return d;var e=this.c,f,g;f=0;for(g=e.length;f<g;++f)d=e[f].sb(a,b,c,d);return d};k.Bc=function(a,b){var c=this.c,d,e;d=0;for(e=c.length;d<e;++d)if(c[d].Bc(a,b))return!0;return!1};k.Od=function(a){Wb(Infinity,Infinity,-Infinity,-Infinity,a);for(var b=this.c,c=0,d=b.length;c<d;++c)ac(a,b[c].H());return a};k.ff=function(){return Nn(this.c)};
+k.od=function(a){this.s!=this.g&&(Fa(this.l),this.o=0,this.s=this.g);if(0>a||0!==this.o&&a<this.o)return this;var b=a.toString();if(this.l.hasOwnProperty(b))return this.l[b];var c=[],d=this.c,e=!1,f,g;f=0;for(g=d.length;f<g;++f){var h=d[f],l=h.od(a);c.push(l);l!==h&&(e=!0)}if(e)return a=new Ln(null),On(a),a.c=c,Mn(a),a.u(),this.l[b]=a;this.o=a;return this};k.X=function(){return"GeometryCollection"};k.Ka=function(a){var b=this.c,c,d;c=0;for(d=b.length;c<d;++c)if(b[c].Ka(a))return!0;return!1};
+k.Ya=function(){return 0===this.c.length};k.rotate=function(a,b){for(var c=this.c,d=0,e=c.length;d<e;++d)c[d].rotate(a,b);this.u()};k.hi=function(a){a=Nn(a);On(this);this.c=a;Mn(this);this.u()};k.rc=function(a){var b=this.c,c,d;c=0;for(d=b.length;c<d;++c)b[c].rc(a);this.u()};k.Sc=function(a,b){var c=this.c,d,e;d=0;for(e=c.length;d<e;++d)c[d].Sc(a,b);this.u()};k.ka=function(){On(this);Tc.prototype.ka.call(this)};function Pn(a){a=a?a:{};this.defaultDataProjection=null;this.defaultDataProjection=yc(a.defaultDataProjection?a.defaultDataProjection:"EPSG:4326");this.b=a.geometryName}y(Pn,vn);function Qn(a,b){return a?un((0,Rn[a.type])(a),!1,b):null}function Sn(a,b){return(0,Tn[a.X()])(un(a,!0,b),b)}
+var Rn={Point:function(a){return new C(a.coordinates)},LineString:function(a){return new R(a.coordinates)},Polygon:function(a){return new E(a.coordinates)},MultiPoint:function(a){return new Bn(a.coordinates)},MultiLineString:function(a){return new S(a.coordinates)},MultiPolygon:function(a){return new T(a.coordinates)},GeometryCollection:function(a,b){var c=a.geometries.map(function(a){return Qn(a,b)});return new Ln(c)}},Tn={Point:function(a){return{type:"Point",coordinates:a.Z()}},LineString:function(a){return{type:"LineString",
+coordinates:a.Z()}},Polygon:function(a,b){var c;b&&(c=b.rightHanded);return{type:"Polygon",coordinates:a.Z(c)}},MultiPoint:function(a){return{type:"MultiPoint",coordinates:a.Z()}},MultiLineString:function(a){return{type:"MultiLineString",coordinates:a.Z()}},MultiPolygon:function(a,b){var c;b&&(c=b.rightHanded);return{type:"MultiPolygon",coordinates:a.Z(c)}},GeometryCollection:function(a,b){return{type:"GeometryCollection",geometries:a.c.map(function(a){var d=Ea({},b);delete d.featureProjection;return Sn(a,
+d)})}},Circle:function(){return{type:"GeometryCollection",geometries:[]}}};k=Pn.prototype;k.Uc=function(a,b){var c=Qn(a.geometry,b),d=new Ik;this.b&&d.Ec(this.b);d.Ua(c);void 0!==a.id&&d.mc(a.id);a.properties&&d.G(a.properties);return d};k.Jf=function(a,b){if("Feature"==a.type)return[this.Uc(a,b)];if("FeatureCollection"==a.type){var c=[],d=a.features,e,f;e=0;for(f=d.length;e<f;++e)c.push(this.Uc(d[e],b));return c}return[]};k.Rh=function(a,b){return Qn(a,b)};
+k.Yh=function(a){return(a=a.crs)?"name"==a.type?yc(a.properties.name):"EPSG"==a.type?yc("EPSG:"+a.properties.code):null:this.defaultDataProjection};k.Yc=function(a,b){b=tn(this,b);var c={type:"Feature"},d=a.Xa();void 0!==d&&(c.id=d);(d=a.W())?c.geometry=Sn(d,b):c.geometry=null;d=a.O();delete d[a.a];Ha(d)?c.properties=null:c.properties=d;return c};k.Ie=function(a,b){b=tn(this,b);var c=[],d,e;d=0;for(e=a.length;d<e;++d)c.push(this.Yc(a[d],b));return{type:"FeatureCollection",features:c}};
+k.Ke=function(a,b){return Sn(a,tn(this,b))};function Un(){this.f=new XMLSerializer;this.defaultDataProjection=null}y(Un,rn);k=Un.prototype;k.X=function(){return"xml"};k.Rb=function(a,b){if(Pk(a))return Vn(this,a,b);if(Qk(a))return this.Ph(a,b);if("string"===typeof a){var c=Rk(a);return Vn(this,c,b)}return null};function Vn(a,b,c){a=Wn(a,b,c);return 0<a.length?a[0]:null}k.Fa=function(a,b){if(Pk(a))return Wn(this,a,b);if(Qk(a))return this.lc(a,b);if("string"===typeof a){var c=Rk(a);return Wn(this,c,b)}return[]};
+function Wn(a,b,c){var d=[];for(b=b.firstChild;b;b=b.nextSibling)b.nodeType==Node.ELEMENT_NODE&&mb(d,a.lc(b,c));return d}k.Vc=function(a,b){if(Pk(a))return this.v(a,b);if(Qk(a)){var c=this.ye(a,[sn(this,a,b?b:{})]);return c?c:null}return"string"===typeof a?(c=Rk(a),this.v(c,b)):null};k.Oa=function(a){return Pk(a)?this.Pf(a):Qk(a)?this.Be(a):"string"===typeof a?(a=Rk(a),this.Pf(a)):null};k.Pf=function(){return this.defaultDataProjection};k.Be=function(){return this.defaultDataProjection};
+k.Dd=function(a,b){var c=this.A(a,b);return this.f.serializeToString(c)};k.Xb=function(a,b){var c=this.a(a,b);return this.f.serializeToString(c)};k.Zc=function(a,b){var c=this.s(a,b);return this.f.serializeToString(c)};function Xn(a){a=a?a:{};this.featureType=a.featureType;this.featureNS=a.featureNS;this.srsName=a.srsName;this.schemaLocation="";this.b={};this.b["http://www.opengis.net/gml"]={featureMember:Uk(Xn.prototype.vd),featureMembers:Uk(Xn.prototype.vd)};Un.call(this)}y(Xn,Un);var Yn=/^[\s\xa0]*$/;k=Xn.prototype;
+k.vd=function(a,b){var c=a.localName,d=null;if("FeatureCollection"==c)"http://www.opengis.net/wfs"===a.namespaceURI?d=O([],this.b,a,b,this):d=O(null,this.b,a,b,this);else if("featureMembers"==c||"featureMember"==c){var e=b[0],f=e.featureType,g=e.featureNS,h,l;if(!f&&a.childNodes){f=[];g={};h=0;for(l=a.childNodes.length;h<l;++h){var m=a.childNodes[h];if(1===m.nodeType){var n=m.nodeName.split(":").pop();if(-1===f.indexOf(n)){var p="",q=0,m=m.namespaceURI,r;for(r in g){if(g[r]===m){p=r;break}++q}p||
+(p="p"+q,g[p]=m);f.push(p+":"+n)}}}"featureMember"!=c&&(e.featureType=f,e.featureNS=g)}"string"===typeof g&&(h=g,g={},g.p0=h);var e={},f=Array.isArray(f)?f:[f],u;for(u in g){n={};h=0;for(l=f.length;h<l;++h)(-1===f[h].indexOf(":")?"p0":f[h].split(":")[0])===u&&(n[f[h].split(":").pop()]="featureMembers"==c?Tk(this.If,this):Uk(this.If,this));e[g[u]]=n}"featureMember"==c?d=O(void 0,e,a,b):d=O([],e,a,b)}null===d&&(d=[]);return d};
+k.ye=function(a,b){var c=b[0];c.srsName=a.firstElementChild.getAttribute("srsName");var d=O(null,this.bg,a,b,this);if(d)return un(d,!1,c)};
+k.If=function(a,b){var c,d;(d=a.getAttribute("fid"))||(d=a.getAttributeNS("http://www.opengis.net/gml","id")||"");var e={},f;for(c=a.firstElementChild;c;c=c.nextElementSibling){var g=c.localName;if(0===c.childNodes.length||1===c.childNodes.length&&(3===c.firstChild.nodeType||4===c.firstChild.nodeType)){var h=Nk(c,!1);Yn.test(h)&&(h=void 0);e[g]=h}else"boundedBy"!==g&&(f=g),e[g]=this.ye(c,b)}c=new Ik(e);f&&c.Ec(f);d&&c.mc(d);return c};
+k.Xh=function(a,b){var c=this.xe(a,b);if(c){var d=new C(null);d.ba("XYZ",c);return d}};k.Vh=function(a,b){var c=O([],this.Ui,a,b,this);if(c)return new Bn(c)};k.Uh=function(a,b){var c=O([],this.Ti,a,b,this);if(c){var d=new S(null);An(d,c);return d}};k.Wh=function(a,b){var c=O([],this.Vi,a,b,this);if(c){var d=new T(null);Dn(d,c);return d}};k.Mh=function(a,b){al(this.Yi,a,b,this)};k.Ug=function(a,b){al(this.Ri,a,b,this)};k.Nh=function(a,b){al(this.Zi,a,b,this)};
+k.ze=function(a,b){var c=this.xe(a,b);if(c){var d=new R(null);d.ba("XYZ",c);return d}};k.zo=function(a,b){var c=O(null,this.Fd,a,b,this);if(c)return c};k.Th=function(a,b){var c=this.xe(a,b);if(c){var d=new zd(null);Ad(d,"XYZ",c);return d}};k.Ae=function(a,b){var c=O([null],this.Me,a,b,this);if(c&&c[0]){var d=new E(null),e=c[0],f=[e.length],g,h;g=1;for(h=c.length;g<h;++g)mb(e,c[g]),f.push(e.length);d.ba("XYZ",e,f);return d}};k.xe=function(a,b){return O(null,this.Fd,a,b,this)};
+k.Ui={"http://www.opengis.net/gml":{pointMember:Tk(Xn.prototype.Mh),pointMembers:Tk(Xn.prototype.Mh)}};k.Ti={"http://www.opengis.net/gml":{lineStringMember:Tk(Xn.prototype.Ug),lineStringMembers:Tk(Xn.prototype.Ug)}};k.Vi={"http://www.opengis.net/gml":{polygonMember:Tk(Xn.prototype.Nh),polygonMembers:Tk(Xn.prototype.Nh)}};k.Yi={"http://www.opengis.net/gml":{Point:Tk(Xn.prototype.xe)}};k.Ri={"http://www.opengis.net/gml":{LineString:Tk(Xn.prototype.ze)}};k.Zi={"http://www.opengis.net/gml":{Polygon:Tk(Xn.prototype.Ae)}};
+k.Gd={"http://www.opengis.net/gml":{LinearRing:Uk(Xn.prototype.zo)}};k.lc=function(a,b){var c={featureType:this.featureType,featureNS:this.featureNS};b&&Ea(c,sn(this,a,b));return this.vd(a,[c])||[]};k.Be=function(a){return yc(this.srsName?this.srsName:a.firstElementChild.getAttribute("srsName"))};function Zn(a){a=Nk(a,!1);return $n(a)}function $n(a){if(a=/^\s*(true|1)|(false|0)\s*$/.exec(a))return void 0!==a[1]||!1}
+function ao(a){a=Nk(a,!1);if(a=/^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/.exec(a)){var b=Date.UTC(parseInt(a[1],10),parseInt(a[2],10)-1,parseInt(a[3],10),parseInt(a[4],10),parseInt(a[5],10),parseInt(a[6],10))/1E3;if("Z"!=a[7]){var c="-"==a[8]?-1:1,b=b+60*c*parseInt(a[9],10);void 0!==a[10]&&(b+=3600*c*parseInt(a[10],10))}return b}}function bo(a){a=Nk(a,!1);return co(a)}
+function co(a){if(a=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(a))return parseFloat(a[1])}function eo(a){a=Nk(a,!1);return fo(a)}function fo(a){if(a=/^\s*(\d+)\s*$/.exec(a))return parseInt(a[1],10)}function U(a){return Nk(a,!1).trim()}function go(a,b){ho(a,b?"1":"0")}function io(a,b){a.appendChild(Lk.createTextNode(b.toPrecision()))}function jo(a,b){a.appendChild(Lk.createTextNode(b.toString()))}function ho(a,b){a.appendChild(Lk.createTextNode(b))};function ko(a){a=a?a:{};Xn.call(this,a);this.b["http://www.opengis.net/gml"].featureMember=Tk(Xn.prototype.vd);this.schemaLocation=a.schemaLocation?a.schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd"}y(ko,Xn);k=ko.prototype;
+k.Qh=function(a,b){var c=Nk(a,!1).replace(/^\s*|\s*$/g,""),d=b[0].srsName,e=a.parentNode.getAttribute("srsDimension"),f="enu";d&&(d=yc(d))&&(f=d.b);c=c.split(/[\s,]+/);d=2;a.getAttribute("srsDimension")?d=fo(a.getAttribute("srsDimension")):a.getAttribute("dimension")?d=fo(a.getAttribute("dimension")):e&&(d=fo(e));for(var g,h,l=[],m=0,n=c.length;m<n;m+=d)e=parseFloat(c[m]),g=parseFloat(c[m+1]),h=3===d?parseFloat(c[m+2]):0,"en"===f.substr(0,2)?l.push(e,g,h):l.push(g,e,h);return l};
+k.wo=function(a,b){var c=O([null],this.Ni,a,b,this);return Wb(c[1][0],c[1][1],c[1][3],c[1][4])};k.ml=function(a,b){var c=O(void 0,this.Gd,a,b,this);c&&b[b.length-1].push(c)};k.eo=function(a,b){var c=O(void 0,this.Gd,a,b,this);c&&(b[b.length-1][0]=c)};k.Fd={"http://www.opengis.net/gml":{coordinates:Uk(ko.prototype.Qh)}};k.Me={"http://www.opengis.net/gml":{innerBoundaryIs:ko.prototype.ml,outerBoundaryIs:ko.prototype.eo}};k.Ni={"http://www.opengis.net/gml":{coordinates:Tk(ko.prototype.Qh)}};
+k.bg={"http://www.opengis.net/gml":{Point:Uk(Xn.prototype.Xh),MultiPoint:Uk(Xn.prototype.Vh),LineString:Uk(Xn.prototype.ze),MultiLineString:Uk(Xn.prototype.Uh),LinearRing:Uk(Xn.prototype.Th),Polygon:Uk(Xn.prototype.Ae),MultiPolygon:Uk(Xn.prototype.Wh),Box:Uk(ko.prototype.wo)}};function lo(a){a=a?a:{};Xn.call(this,a);this.j=void 0!==a.surface?a.surface:!1;this.i=void 0!==a.curve?a.curve:!1;this.l=void 0!==a.multiCurve?a.multiCurve:!0;this.o=void 0!==a.multiSurface?a.multiSurface:!0;this.schemaLocation=a.schemaLocation?a.schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd"}y(lo,Xn);k=lo.prototype;k.Do=function(a,b){var c=O([],this.Si,a,b,this);if(c){var d=new S(null);An(d,c);return d}};
+k.Eo=function(a,b){var c=O([],this.Wi,a,b,this);if(c){var d=new T(null);Dn(d,c);return d}};k.vg=function(a,b){al(this.Oi,a,b,this)};k.vi=function(a,b){al(this.cj,a,b,this)};k.Ho=function(a,b){return O([null],this.Xi,a,b,this)};k.Jo=function(a,b){return O([null],this.bj,a,b,this)};k.Io=function(a,b){return O([null],this.Me,a,b,this)};k.Co=function(a,b){return O([null],this.Fd,a,b,this)};k.ol=function(a,b){var c=O(void 0,this.Gd,a,b,this);c&&b[b.length-1].push(c)};
+k.Hj=function(a,b){var c=O(void 0,this.Gd,a,b,this);c&&(b[b.length-1][0]=c)};k.Zh=function(a,b){var c=O([null],this.dj,a,b,this);if(c&&c[0]){var d=new E(null),e=c[0],f=[e.length],g,h;g=1;for(h=c.length;g<h;++g)mb(e,c[g]),f.push(e.length);d.ba("XYZ",e,f);return d}};k.Oh=function(a,b){var c=O([null],this.Pi,a,b,this);if(c){var d=new R(null);d.ba("XYZ",c);return d}};k.yo=function(a,b){var c=O([null],this.Qi,a,b,this);return Wb(c[1][0],c[1][1],c[2][0],c[2][1])};
+k.Ao=function(a,b){for(var c=Nk(a,!1),d=/^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/,e=[],f;f=d.exec(c);)e.push(parseFloat(f[1])),c=c.substr(f[0].length);if(""===c){c=b[0].srsName;d="enu";c&&(d=yc(c).b);if("neu"===d)for(c=0,d=e.length;c<d;c+=3)f=e[c],e[c]=e[c+1],e[c+1]=f;c=e.length;2==c&&e.push(0);return 0===c?void 0:e}};
+k.Mf=function(a,b){var c=Nk(a,!1).replace(/^\s*|\s*$/g,""),d=b[0].srsName,e=a.parentNode.getAttribute("srsDimension"),f="enu";d&&(f=yc(d).b);c=c.split(/\s+/);d=2;a.getAttribute("srsDimension")?d=fo(a.getAttribute("srsDimension")):a.getAttribute("dimension")?d=fo(a.getAttribute("dimension")):e&&(d=fo(e));for(var g,h,l=[],m=0,n=c.length;m<n;m+=d)e=parseFloat(c[m]),g=parseFloat(c[m+1]),h=3===d?parseFloat(c[m+2]):0,"en"===f.substr(0,2)?l.push(e,g,h):l.push(g,e,h);return l};
+k.Fd={"http://www.opengis.net/gml":{pos:Uk(lo.prototype.Ao),posList:Uk(lo.prototype.Mf)}};k.Me={"http://www.opengis.net/gml":{interior:lo.prototype.ol,exterior:lo.prototype.Hj}};
+k.bg={"http://www.opengis.net/gml":{Point:Uk(Xn.prototype.Xh),MultiPoint:Uk(Xn.prototype.Vh),LineString:Uk(Xn.prototype.ze),MultiLineString:Uk(Xn.prototype.Uh),LinearRing:Uk(Xn.prototype.Th),Polygon:Uk(Xn.prototype.Ae),MultiPolygon:Uk(Xn.prototype.Wh),Surface:Uk(lo.prototype.Zh),MultiSurface:Uk(lo.prototype.Eo),Curve:Uk(lo.prototype.Oh),MultiCurve:Uk(lo.prototype.Do),Envelope:Uk(lo.prototype.yo)}};k.Si={"http://www.opengis.net/gml":{curveMember:Tk(lo.prototype.vg),curveMembers:Tk(lo.prototype.vg)}};
+k.Wi={"http://www.opengis.net/gml":{surfaceMember:Tk(lo.prototype.vi),surfaceMembers:Tk(lo.prototype.vi)}};k.Oi={"http://www.opengis.net/gml":{LineString:Tk(Xn.prototype.ze),Curve:Tk(lo.prototype.Oh)}};k.cj={"http://www.opengis.net/gml":{Polygon:Tk(Xn.prototype.Ae),Surface:Tk(lo.prototype.Zh)}};k.dj={"http://www.opengis.net/gml":{patches:Uk(lo.prototype.Ho)}};k.Pi={"http://www.opengis.net/gml":{segments:Uk(lo.prototype.Jo)}};k.Qi={"http://www.opengis.net/gml":{lowerCorner:Tk(lo.prototype.Mf),upperCorner:Tk(lo.prototype.Mf)}};
+k.Xi={"http://www.opengis.net/gml":{PolygonPatch:Uk(lo.prototype.Io)}};k.bj={"http://www.opengis.net/gml":{LineStringSegment:Uk(lo.prototype.Co)}};function mo(a,b,c){c=c[c.length-1].srsName;b=b.Z();for(var d=b.length,e=Array(d),f,g=0;g<d;++g){f=b[g];var h=g,l="enu";c&&(l=yc(c).b);e[h]="en"===l.substr(0,2)?f[0]+" "+f[1]:f[1]+" "+f[0]}ho(a,e.join(" "))}
+k.Ji=function(a,b,c){var d=c[c.length-1].srsName;d&&a.setAttribute("srsName",d);d=Mk(a.namespaceURI,"pos");a.appendChild(d);c=c[c.length-1].srsName;a="enu";c&&(a=yc(c).b);b=b.Z();ho(d,"en"===a.substr(0,2)?b[0]+" "+b[1]:b[1]+" "+b[0])};var no={"http://www.opengis.net/gml":{lowerCorner:L(ho),upperCorner:L(ho)}};k=lo.prototype;k.xp=function(a,b,c){var d=c[c.length-1].srsName;d&&a.setAttribute("srsName",d);bl({node:a},no,Zk,[b[0]+" "+b[1],b[2]+" "+b[3]],c,["lowerCorner","upperCorner"],this)};
+k.Gi=function(a,b,c){var d=c[c.length-1].srsName;d&&a.setAttribute("srsName",d);d=Mk(a.namespaceURI,"posList");a.appendChild(d);mo(d,b,c)};k.aj=function(a,b){var c=b[b.length-1],d=c.node,e=c.exteriorWritten;void 0===e&&(c.exteriorWritten=!0);return Mk(d.namespaceURI,void 0!==e?"interior":"exterior")};
+k.Le=function(a,b,c){var d=c[c.length-1].srsName;"PolygonPatch"!==a.nodeName&&d&&a.setAttribute("srsName",d);"Polygon"===a.nodeName||"PolygonPatch"===a.nodeName?(b=b.Vd(),bl({node:a,srsName:d},oo,this.aj,b,c,void 0,this)):"Surface"===a.nodeName&&(d=Mk(a.namespaceURI,"patches"),a.appendChild(d),a=Mk(d.namespaceURI,"PolygonPatch"),d.appendChild(a),this.Le(a,b,c))};
+k.Ge=function(a,b,c){var d=c[c.length-1].srsName;"LineStringSegment"!==a.nodeName&&d&&a.setAttribute("srsName",d);"LineString"===a.nodeName||"LineStringSegment"===a.nodeName?(d=Mk(a.namespaceURI,"posList"),a.appendChild(d),mo(d,b,c)):"Curve"===a.nodeName&&(d=Mk(a.namespaceURI,"segments"),a.appendChild(d),a=Mk(d.namespaceURI,"LineStringSegment"),d.appendChild(a),this.Ge(a,b,c))};
+k.Ii=function(a,b,c){var d=c[c.length-1],e=d.srsName,d=d.surface;e&&a.setAttribute("srsName",e);b=b.Wd();bl({node:a,srsName:e,surface:d},po,this.c,b,c,void 0,this)};k.yp=function(a,b,c){var d=c[c.length-1].srsName;d&&a.setAttribute("srsName",d);b=b.je();bl({node:a,srsName:d},qo,Xk("pointMember"),b,c,void 0,this)};k.Hi=function(a,b,c){var d=c[c.length-1],e=d.srsName,d=d.curve;e&&a.setAttribute("srsName",e);b=b.md();bl({node:a,srsName:e,curve:d},ro,this.c,b,c,void 0,this)};
+k.Ki=function(a,b,c){var d=Mk(a.namespaceURI,"LinearRing");a.appendChild(d);this.Gi(d,b,c)};k.Li=function(a,b,c){var d=this.g(b,c);d&&(a.appendChild(d),this.Le(d,b,c))};k.zp=function(a,b,c){var d=Mk(a.namespaceURI,"Point");a.appendChild(d);this.Ji(d,b,c)};k.Fi=function(a,b,c){var d=this.g(b,c);d&&(a.appendChild(d),this.Ge(d,b,c))};
+k.Je=function(a,b,c){var d=c[c.length-1],e=Ea({},d);e.node=a;var f;Array.isArray(b)?d.dataProjection?f=Sc(b,d.featureProjection,d.dataProjection):f=b:f=un(b,!0,d);bl(e,so,this.g,[f],c,void 0,this)};
+k.Bi=function(a,b,c){var d=b.Xa();d&&a.setAttribute("fid",d);var d=c[c.length-1],e=d.featureNS,f=b.a;d.Dc||(d.Dc={},d.Dc[e]={});var g=b.O();b=[];var h=[],l;for(l in g){var m=g[l];null!==m&&(b.push(l),h.push(m),l==f||m instanceof Tc?l in d.Dc[e]||(d.Dc[e][l]=L(this.Je,this)):l in d.Dc[e]||(d.Dc[e][l]=L(ho)))}l=Ea({},d);l.node=a;bl(l,d.Dc,Xk(void 0,e),h,c,b)};
+var po={"http://www.opengis.net/gml":{surfaceMember:L(lo.prototype.Li),polygonMember:L(lo.prototype.Li)}},qo={"http://www.opengis.net/gml":{pointMember:L(lo.prototype.zp)}},ro={"http://www.opengis.net/gml":{lineStringMember:L(lo.prototype.Fi),curveMember:L(lo.prototype.Fi)}},oo={"http://www.opengis.net/gml":{exterior:L(lo.prototype.Ki),interior:L(lo.prototype.Ki)}},so={"http://www.opengis.net/gml":{Curve:L(lo.prototype.Ge),MultiCurve:L(lo.prototype.Hi),Point:L(lo.prototype.Ji),MultiPoint:L(lo.prototype.yp),
+LineString:L(lo.prototype.Ge),MultiLineString:L(lo.prototype.Hi),LinearRing:L(lo.prototype.Gi),Polygon:L(lo.prototype.Le),MultiPolygon:L(lo.prototype.Ii),Surface:L(lo.prototype.Le),MultiSurface:L(lo.prototype.Ii),Envelope:L(lo.prototype.xp)}},to={MultiLineString:"lineStringMember",MultiCurve:"curveMember",MultiPolygon:"polygonMember",MultiSurface:"surfaceMember"};lo.prototype.c=function(a,b){return Mk("http://www.opengis.net/gml",to[b[b.length-1].node.nodeName])};
+lo.prototype.g=function(a,b){var c=b[b.length-1],d=c.multiSurface,e=c.surface,f=c.curve,c=c.multiCurve,g;Array.isArray(a)?g="Envelope":(g=a.X(),"MultiPolygon"===g&&!0===d?g="MultiSurface":"Polygon"===g&&!0===e?g="Surface":"LineString"===g&&!0===f?g="Curve":"MultiLineString"===g&&!0===c&&(g="MultiCurve"));return Mk("http://www.opengis.net/gml",g)};
+lo.prototype.s=function(a,b){b=tn(this,b);var c=Mk("http://www.opengis.net/gml","geom"),d={node:c,srsName:this.srsName,curve:this.i,surface:this.j,multiSurface:this.o,multiCurve:this.l};b&&Ea(d,b);this.Je(c,a,[d]);return c};
+lo.prototype.a=function(a,b){b=tn(this,b);var c=Mk("http://www.opengis.net/gml","featureMembers");c.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation",this.schemaLocation);var d={srsName:this.srsName,curve:this.i,surface:this.j,multiSurface:this.o,multiCurve:this.l,featureNS:this.featureNS,featureType:this.featureType};b&&Ea(d,b);var d=[d],e=d[d.length-1],f=e.featureType,g=e.featureNS,h={};h[g]={};h[g][f]=L(this.Bi,this);e=Ea({},e);e.node=c;bl(e,h,Xk(f,g),a,d);return c};function uo(a){a=a?a:{};Un.call(this);this.defaultDataProjection=yc("EPSG:4326");this.b=a.readExtensions}y(uo,Un);var vo=[null,"http://www.topografix.com/GPX/1/0","http://www.topografix.com/GPX/1/1"];function wo(a,b,c){a.push(parseFloat(b.getAttribute("lon")),parseFloat(b.getAttribute("lat")));"ele"in c?(a.push(c.ele),delete c.ele):a.push(0);"time"in c?(a.push(c.time),delete c.time):a.push(0);return a}function xo(a,b){var c=b[b.length-1],d=a.getAttribute("href");null!==d&&(c.link=d);al(yo,a,b)}
+function zo(a,b){b[b.length-1].extensionsNode_=a}function Ao(a,b){var c=b[0],d=O({flatCoordinates:[]},Bo,a,b);if(d){var e=d.flatCoordinates;delete d.flatCoordinates;var f=new R(null);f.ba("XYZM",e);un(f,!1,c);c=new Ik(f);c.G(d);return c}}function Co(a,b){var c=b[0],d=O({flatCoordinates:[],ends:[]},Do,a,b);if(d){var e=d.flatCoordinates;delete d.flatCoordinates;var f=d.ends;delete d.ends;var g=new S(null);g.ba("XYZM",e,f);un(g,!1,c);c=new Ik(g);c.G(d);return c}}
+function Eo(a,b){var c=b[0],d=O({},Fo,a,b);if(d){var e=wo([],a,d),e=new C(e,"XYZM");un(e,!1,c);c=new Ik(e);c.G(d);return c}}
+var Go={rte:Ao,trk:Co,wpt:Eo},Ho=M(vo,{rte:Tk(Ao),trk:Tk(Co),wpt:Tk(Eo)}),yo=M(vo,{text:J(U,"linkText"),type:J(U,"linkType")}),Bo=M(vo,{name:J(U),cmt:J(U),desc:J(U),src:J(U),link:xo,number:J(eo),extensions:zo,type:J(U),rtept:function(a,b){var c=O({},Io,a,b);c&&wo(b[b.length-1].flatCoordinates,a,c)}}),Io=M(vo,{ele:J(bo),time:J(ao)}),Do=M(vo,{name:J(U),cmt:J(U),desc:J(U),src:J(U),link:xo,number:J(eo),type:J(U),extensions:zo,trkseg:function(a,b){var c=b[b.length-1];al(Jo,a,b);c.ends.push(c.flatCoordinates.length)}}),
+Jo=M(vo,{trkpt:function(a,b){var c=O({},Ko,a,b);c&&wo(b[b.length-1].flatCoordinates,a,c)}}),Ko=M(vo,{ele:J(bo),time:J(ao)}),Fo=M(vo,{ele:J(bo),time:J(ao),magvar:J(bo),geoidheight:J(bo),name:J(U),cmt:J(U),desc:J(U),src:J(U),link:xo,sym:J(U),type:J(U),fix:J(U),sat:J(eo),hdop:J(bo),vdop:J(bo),pdop:J(bo),ageofdgpsdata:J(bo),dgpsid:J(eo),extensions:zo});
+function Lo(a,b){b||(b=[]);for(var c=0,d=b.length;c<d;++c){var e=b[c];if(a.b){var f=e.get("extensionsNode_")||null;a.b(e,f)}e.set("extensionsNode_",void 0)}}uo.prototype.Ph=function(a,b){if(!jb(vo,a.namespaceURI))return null;var c=Go[a.localName];if(!c)return null;c=c(a,[sn(this,a,b)]);if(!c)return null;Lo(this,[c]);return c};uo.prototype.lc=function(a,b){if(!jb(vo,a.namespaceURI))return[];if("gpx"==a.localName){var c=O([],Ho,a,[sn(this,a,b)]);if(c)return Lo(this,c),c}return[]};
+function Mo(a,b,c){a.setAttribute("href",b);b=c[c.length-1].properties;bl({node:a},No,Zk,[b.linkText,b.linkType],c,Oo)}function Po(a,b,c){var d=c[c.length-1],e=d.node.namespaceURI,f=d.properties;a.setAttributeNS(null,"lat",b[1]);a.setAttributeNS(null,"lon",b[0]);switch(d.geometryLayout){case "XYZM":0!==b[3]&&(f.time=b[3]);case "XYZ":0!==b[2]&&(f.ele=b[2]);break;case "XYM":0!==b[2]&&(f.time=b[2])}b="rtept"==a.nodeName?Qo[e]:Ro[e];d=$k(f,b);bl({node:a,properties:f},So,Zk,d,c,b)}
+var Oo=["text","type"],No=M(vo,{text:L(ho),type:L(ho)}),To=M(vo,"name cmt desc src link number type rtept".split(" ")),Uo=M(vo,{name:L(ho),cmt:L(ho),desc:L(ho),src:L(ho),link:L(Mo),number:L(jo),type:L(ho),rtept:Wk(L(Po))}),Qo=M(vo,["ele","time"]),Vo=M(vo,"name cmt desc src link number type trkseg".split(" ")),Yo=M(vo,{name:L(ho),cmt:L(ho),desc:L(ho),src:L(ho),link:L(Mo),number:L(jo),type:L(ho),trkseg:Wk(L(function(a,b,c){bl({node:a,geometryLayout:b.f,properties:{}},Wo,Xo,b.Z(),c)}))}),Xo=Xk("trkpt"),
+Wo=M(vo,{trkpt:L(Po)}),Ro=M(vo,"ele time magvar geoidheight name cmt desc src link sym type fix sat hdop vdop pdop ageofdgpsdata dgpsid".split(" ")),So=M(vo,{ele:L(io),time:L(function(a,b){var c=new Date(1E3*b);a.appendChild(Lk.createTextNode(c.getUTCFullYear()+"-"+zb(c.getUTCMonth()+1)+"-"+zb(c.getUTCDate())+"T"+zb(c.getUTCHours())+":"+zb(c.getUTCMinutes())+":"+zb(c.getUTCSeconds())+"Z"))}),magvar:L(io),geoidheight:L(io),name:L(ho),cmt:L(ho),desc:L(ho),src:L(ho),link:L(Mo),sym:L(ho),type:L(ho),fix:L(ho),
+sat:L(jo),hdop:L(io),vdop:L(io),pdop:L(io),ageofdgpsdata:L(io),dgpsid:L(jo)}),Zo={Point:"wpt",LineString:"rte",MultiLineString:"trk"};function $o(a,b){var c=a.W();if(c&&(c=Zo[c.X()]))return Mk(b[b.length-1].node.namespaceURI,c)}
+var ap=M(vo,{rte:L(function(a,b,c){var d=c[0],e=b.O();a={node:a,properties:e};if(b=b.W())b=un(b,!0,d),a.geometryLayout=b.f,e.rtept=b.Z();d=To[c[c.length-1].node.namespaceURI];e=$k(e,d);bl(a,Uo,Zk,e,c,d)}),trk:L(function(a,b,c){var d=c[0],e=b.O();a={node:a,properties:e};if(b=b.W())b=un(b,!0,d),e.trkseg=b.md();d=Vo[c[c.length-1].node.namespaceURI];e=$k(e,d);bl(a,Yo,Zk,e,c,d)}),wpt:L(function(a,b,c){var d=c[0],e=c[c.length-1];e.properties=b.O();if(b=b.W())b=un(b,!0,d),e.geometryLayout=b.f,Po(a,b.Z(),
+c)})});uo.prototype.a=function(a,b){b=tn(this,b);var c=Mk("http://www.topografix.com/GPX/1/1","gpx");c.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");c.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation","http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd");c.setAttribute("version","1.1");c.setAttribute("creator","OpenLayers 3");bl({node:c},ap,$o,a,[b]);return c};function bp(){this.defaultDataProjection=null}y(bp,rn);function cp(a){return"string"===typeof a?a:""}k=bp.prototype;k.X=function(){return"text"};k.Rb=function(a,b){return this.ud(cp(a),tn(this,b))};k.Fa=function(a,b){return this.Kf(cp(a),tn(this,b))};k.Vc=function(a,b){return this.wd(cp(a),tn(this,b))};k.Oa=function(a){cp(a);return this.defaultDataProjection};k.Dd=function(a,b){return this.He(a,tn(this,b))};k.Xb=function(a,b){return this.Ci(a,tn(this,b))};
+k.Zc=function(a,b){return this.Ed(a,tn(this,b))};function dp(a){a=a?a:{};this.defaultDataProjection=null;this.defaultDataProjection=yc("EPSG:4326");this.b=a.altitudeMode?a.altitudeMode:"none"}y(dp,bp);var ep=/^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/,fp=/^H.([A-Z]{3}).*?:(.*)/,gp=/^HFDTE(\d{2})(\d{2})(\d{2})/,hp=/\r\n|\r|\n/;
+dp.prototype.ud=function(a,b){var c=this.b,d=a.split(hp),e={},f=[],g=2E3,h=0,l=1,m=-1,n,p;n=0;for(p=d.length;n<p;++n){var q=d[n],r;if("B"==q.charAt(0)){if(r=ep.exec(q)){var q=parseInt(r[1],10),u=parseInt(r[2],10),x=parseInt(r[3],10),v=parseInt(r[4],10)+parseInt(r[5],10)/6E4;"S"==r[6]&&(v=-v);var D=parseInt(r[7],10)+parseInt(r[8],10)/6E4;"W"==r[9]&&(D=-D);f.push(D,v);"none"!=c&&f.push("gps"==c?parseInt(r[11],10):"barometric"==c?parseInt(r[12],10):0);r=Date.UTC(g,h,l,q,u,x);r<m&&(r=Date.UTC(g,h,l+1,
+q,u,x));f.push(r/1E3);m=r}}else"H"==q.charAt(0)&&((r=gp.exec(q))?(l=parseInt(r[1],10),h=parseInt(r[2],10)-1,g=2E3+parseInt(r[3],10)):(r=fp.exec(q))&&(e[r[1]]=r[2].trim()))}if(0===f.length)return null;d=new R(null);d.ba("none"==c?"XYM":"XYZM",f);c=new Ik(un(d,!1,b));c.G(e);return c};dp.prototype.Kf=function(a,b){var c=this.ud(a,b);return c?[c]:[]};function ip(a,b){this.a={};this.b=[];this.g=0;var c=arguments.length;if(1<c){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a){var e;if(a instanceof ip)e=a.N(),d=a.zc();else{var c=[],f=0;for(e in a)c[f++]=e;e=c;c=[];f=0;for(d in a)c[f++]=a[d];d=c}for(c=0;c<e.length;c++)this.set(e[c],d[c])}}k=ip.prototype;k.wc=function(){return this.g};k.zc=function(){jp(this);for(var a=[],b=0;b<this.b.length;b++)a.push(this.a[this.b[b]]);return a};
+k.N=function(){jp(this);return this.b.concat()};k.Ya=function(){return 0==this.g};k.clear=function(){this.a={};this.g=this.b.length=0};k.remove=function(a){return kp(this.a,a)?(delete this.a[a],this.g--,this.b.length>2*this.g&&jp(this),!0):!1};function jp(a){if(a.g!=a.b.length){for(var b=0,c=0;b<a.b.length;){var d=a.b[b];kp(a.a,d)&&(a.b[c++]=d);b++}a.b.length=c}if(a.g!=a.b.length){for(var e={},c=b=0;b<a.b.length;)d=a.b[b],kp(e,d)||(a.b[c++]=d,e[d]=1),b++;a.b.length=c}}
+k.get=function(a,b){return kp(this.a,a)?this.a[a]:b};k.set=function(a,b){kp(this.a,a)||(this.g++,this.b.push(a));this.a[a]=b};k.forEach=function(a,b){for(var c=this.N(),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};k.clone=function(){return new ip(this)};function kp(a,b){return Object.prototype.hasOwnProperty.call(a,b)};var lp=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;function mp(a,b){if(a)for(var c=a.split("&"),d=0;d<c.length;d++){var e=c[d].indexOf("="),f,g=null;0<=e?(f=c[d].substring(0,e),g=c[d].substring(e+1)):f=c[d];b(f,g?decodeURIComponent(g.replace(/\+/g," ")):"")}};function np(a,b){this.a=this.l=this.g="";this.o=null;this.f=this.b="";this.c=!1;var c;a instanceof np?(this.c=void 0!==b?b:a.c,op(this,a.g),this.l=a.l,this.a=a.a,pp(this,a.o),this.b=a.b,qp(this,a.i.clone()),this.f=a.f):a&&(c=String(a).match(lp))?(this.c=!!b,op(this,c[1]||"",!0),this.l=rp(c[2]||""),this.a=rp(c[3]||"",!0),pp(this,c[4]),this.b=rp(c[5]||"",!0),qp(this,c[6]||"",!0),this.f=rp(c[7]||"")):(this.c=!!b,this.i=new sp(null,0,this.c))}
+np.prototype.toString=function(){var a=[],b=this.g;b&&a.push(tp(b,up,!0),":");var c=this.a;if(c||"file"==b)a.push("//"),(b=this.l)&&a.push(tp(b,up,!0),"@"),a.push(encodeURIComponent(String(c)).replace(/%25([0-9a-fA-F]{2})/g,"%$1")),c=this.o,null!=c&&a.push(":",String(c));if(c=this.b)this.a&&"/"!=c.charAt(0)&&a.push("/"),a.push(tp(c,"/"==c.charAt(0)?vp:wp,!0));(c=this.i.toString())&&a.push("?",c);(c=this.f)&&a.push("#",tp(c,xp));return a.join("")};np.prototype.clone=function(){return new np(this)};
+function op(a,b,c){a.g=c?rp(b,!0):b;a.g&&(a.g=a.g.replace(/:$/,""))}function pp(a,b){if(b){b=Number(b);if(isNaN(b)||0>b)throw Error("Bad port number "+b);a.o=b}else a.o=null}function qp(a,b,c){b instanceof sp?(a.i=b,yp(a.i,a.c)):(c||(b=tp(b,zp)),a.i=new sp(b,0,a.c))}function Ap(a){return a instanceof np?a.clone():new np(a,void 0)}
+function Bp(a,b){a instanceof np||(a=Ap(a));b instanceof np||(b=Ap(b));var c=a,d=b,e=c.clone(),f=!!d.g;f?op(e,d.g):f=!!d.l;f?e.l=d.l:f=!!d.a;f?e.a=d.a:f=null!=d.o;var g=d.b;if(f)pp(e,d.o);else if(f=!!d.b)if("/"!=g.charAt(0)&&(c.a&&!c.b?g="/"+g:(c=e.b.lastIndexOf("/"),-1!=c&&(g=e.b.substr(0,c+1)+g))),c=g,".."==c||"."==c)g="";else if(-1!=c.indexOf("./")||-1!=c.indexOf("/.")){for(var g=0==c.lastIndexOf("/",0),c=c.split("/"),h=[],l=0;l<c.length;){var m=c[l++];"."==m?g&&l==c.length&&h.push(""):".."==m?
+((1<h.length||1==h.length&&""!=h[0])&&h.pop(),g&&l==c.length&&h.push("")):(h.push(m),g=!0)}g=h.join("/")}else g=c;f?e.b=g:f=""!==d.i.toString();f?qp(e,rp(d.i.toString())):f=!!d.f;f&&(e.f=d.f);return e}function rp(a,b){return a?b?decodeURI(a.replace(/%25/g,"%2525")):decodeURIComponent(a):""}function tp(a,b,c){return da(a)?(a=encodeURI(a).replace(b,Cp),c&&(a=a.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),a):null}function Cp(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)}
+var up=/[#\/\?@]/g,wp=/[\#\?:]/g,vp=/[\#\?]/g,zp=/[\#\?@]/g,xp=/#/g;function sp(a,b,c){this.a=this.b=null;this.g=a||null;this.f=!!c}function Dp(a){a.b||(a.b=new ip,a.a=0,a.g&&mp(a.g,function(b,c){a.add(decodeURIComponent(b.replace(/\+/g," ")),c)}))}k=sp.prototype;k.wc=function(){Dp(this);return this.a};k.add=function(a,b){Dp(this);this.g=null;a=Ep(this,a);var c=this.b.get(a);c||this.b.set(a,c=[]);c.push(b);this.a=this.a+1;return this};
+k.remove=function(a){Dp(this);a=Ep(this,a);return kp(this.b.a,a)?(this.g=null,this.a=this.a-this.b.get(a).length,this.b.remove(a)):!1};k.clear=function(){this.b=this.g=null;this.a=0};k.Ya=function(){Dp(this);return 0==this.a};function Fp(a,b){Dp(a);b=Ep(a,b);return kp(a.b.a,b)}k.N=function(){Dp(this);for(var a=this.b.zc(),b=this.b.N(),c=[],d=0;d<b.length;d++)for(var e=a[d],f=0;f<e.length;f++)c.push(b[d]);return c};
+k.zc=function(a){Dp(this);var b=[];if(da(a))Fp(this,a)&&(b=ne(b,this.b.get(Ep(this,a))));else{a=this.b.zc();for(var c=0;c<a.length;c++)b=ne(b,a[c])}return b};k.set=function(a,b){Dp(this);this.g=null;a=Ep(this,a);Fp(this,a)&&(this.a=this.a-this.b.get(a).length);this.b.set(a,[b]);this.a=this.a+1;return this};k.get=function(a,b){var c=a?this.zc(a):[];return 0<c.length?String(c[0]):b};
+k.toString=function(){if(this.g)return this.g;if(!this.b)return"";for(var a=[],b=this.b.N(),c=0;c<b.length;c++)for(var d=b[c],e=encodeURIComponent(String(d)),d=this.zc(d),f=0;f<d.length;f++){var g=e;""!==d[f]&&(g+="="+encodeURIComponent(String(d[f])));a.push(g)}return this.g=a.join("&")};k.clone=function(){var a=new sp;a.g=this.g;this.b&&(a.b=this.b.clone(),a.a=this.a);return a};function Ep(a,b){var c=String(b);a.f&&(c=c.toLowerCase());return c}
+function yp(a,b){b&&!a.f&&(Dp(a),a.g=null,a.b.forEach(function(a,b){var e=b.toLowerCase();b!=e&&(this.remove(b),this.remove(e),0<a.length&&(this.g=null,this.b.set(Ep(this,e),oe(a)),this.a=this.a+a.length))},a));a.f=b};function Gp(a){a=a||{};this.g=a.font;this.i=a.rotation;this.a=a.scale;this.s=a.text;this.o=a.textAlign;this.j=a.textBaseline;this.b=void 0!==a.fill?a.fill:new ij({color:"#333"});this.l=void 0!==a.stroke?a.stroke:null;this.f=void 0!==a.offsetX?a.offsetX:0;this.c=void 0!==a.offsetY?a.offsetY:0}k=Gp.prototype;k.Xj=function(){return this.g};k.kk=function(){return this.f};k.lk=function(){return this.c};k.Un=function(){return this.b};k.Vn=function(){return this.i};k.Wn=function(){return this.a};k.Xn=function(){return this.l};
+k.Ha=function(){return this.s};k.yk=function(){return this.o};k.zk=function(){return this.j};k.bp=function(a){this.g=a};k.mi=function(a){this.f=a};k.ni=function(a){this.c=a};k.ap=function(a){this.b=a};k.Yn=function(a){this.i=a};k.Zn=function(a){this.a=a};k.ip=function(a){this.l=a};k.pi=function(a){this.s=a};k.ri=function(a){this.o=a};k.jp=function(a){this.j=a};function Hp(a){a=a?a:{};Un.call(this);this.defaultDataProjection=yc("EPSG:4326");this.g=a.defaultStyle?a.defaultStyle:Ip;this.c=void 0!==a.extractStyles?a.extractStyles:!0;this.l=void 0!==a.writeStyles?a.writeStyles:!0;this.b={};this.i=void 0!==a.showPointNames?a.showPointNames:!0}y(Hp,Un);
+var Jp=["http://www.google.com/kml/ext/2.2"],Kp=[null,"http://earth.google.com/kml/2.0","http://earth.google.com/kml/2.1","http://earth.google.com/kml/2.2","http://www.opengis.net/kml/2.2"],Lp=[255,255,255,1],Mp=new ij({color:Lp}),Np=[20,2],Op=[64,64],Pp=new Dh({anchor:Np,anchorOrigin:"bottom-left",anchorXUnits:"pixels",anchorYUnits:"pixels",crossOrigin:"anonymous",rotation:0,scale:.5,size:Op,src:"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"}),Qp=new oj({color:Lp,width:1}),Rp=new Gp({font:"bold 16px Helvetica",
+fill:Mp,stroke:new oj({color:[51,51,51,1],width:2}),scale:.8}),Ip=[new rj({fill:Mp,image:Pp,text:Rp,stroke:Qp,zIndex:0})],Sp={fraction:"fraction",pixels:"pixels"};function Tp(a,b){var c,d=[0,0],e="start";if(a.a){var f=a.a.ld();f&&2==f.length&&(d[0]=a.a.i*f[0]/2,d[1]=-a.a.i*f[1]/2,e="left")}if(Ha(a.Ha()))c=new Gp({text:b,offsetX:d[0],offsetY:d[1],textAlign:e});else{var f=a.Ha(),g={};for(c in f)g[c]=f[c];c=g;c.pi(b);c.ri(e);c.mi(d[0]);c.ni(d[1])}return new rj({text:c})}
+function Up(a,b,c,d,e){return function(){var f=e,g="";f&&this.W()&&(f="Point"===this.W().X());f&&(g=this.get("name"),f=f&&g);if(a)return f?(f=Tp(a[0],g),a.concat(f)):a;if(b){var h=Vp(b,c,d);return f?(f=Tp(h[0],g),h.concat(f)):h}return f?(f=Tp(c[0],g),c.concat(f)):c}}function Vp(a,b,c){return Array.isArray(a)?a:"string"===typeof a?(!(a in c)&&"#"+a in c&&(a="#"+a),Vp(c[a],b,c)):b}
+function Wp(a){a=Nk(a,!1);if(a=/^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(a))return a=a[1],[parseInt(a.substr(6,2),16),parseInt(a.substr(4,2),16),parseInt(a.substr(2,2),16),parseInt(a.substr(0,2),16)/255]}function Xp(a){a=Nk(a,!1);for(var b=[],c=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i,d;d=c.exec(a);)b.push(parseFloat(d[1]),parseFloat(d[2]),d[3]?parseFloat(d[3]):0),a=a.substr(d[0].length);return""!==a?void 0:b}
+function Yp(a){var b=Nk(a,!1);return a.baseURI?Bp(a.baseURI,b.trim()).toString():b.trim()}function Zp(a){a=bo(a);if(void 0!==a)return Math.sqrt(a)}function $p(a,b){return O(null,aq,a,b)}function bq(a,b){var c=O({B:[],zi:[]},cq,a,b);if(c){var d=c.B,c=c.zi,e,f;e=0;for(f=Math.min(d.length,c.length);e<f;++e)d[4*e+3]=c[e];c=new R(null);c.ba("XYZM",d);return c}}function dq(a,b){var c=O({},eq,a,b),d=O(null,fq,a,b);if(d){var e=new R(null);e.ba("XYZ",d);e.G(c);return e}}
+function gq(a,b){var c=O({},eq,a,b),d=O(null,fq,a,b);if(d){var e=new E(null);e.ba("XYZ",d,[d.length]);e.G(c);return e}}
+function hq(a,b){var c=O([],iq,a,b);if(!c)return null;if(0===c.length)return new Ln(c);var d=!0,e=c[0].X(),f,g,h;g=1;for(h=c.length;g<h;++g)if(f=c[g],f.X()!=e){d=!1;break}if(d){if("Point"==e){f=c[0];d=f.f;e=f.la();g=1;for(h=c.length;g<h;++g)f=c[g],mb(e,f.la());f=new Bn(null);f.ba(d,e);jq(f,c);return f}return"LineString"==e?(f=new S(null),An(f,c),jq(f,c),f):"Polygon"==e?(f=new T(null),Dn(f,c),jq(f,c),f):"GeometryCollection"==e?new Ln(c):null}return new Ln(c)}
+function kq(a,b){var c=O({},eq,a,b),d=O(null,fq,a,b);if(d){var e=new C(null);e.ba("XYZ",d);e.G(c);return e}}function lq(a,b){var c=O({},eq,a,b),d=O([null],mq,a,b);if(d&&d[0]){var e=new E(null),f=d[0],g=[f.length],h,l;h=1;for(l=d.length;h<l;++h)mb(f,d[h]),g.push(f.length);e.ba("XYZ",f,g);e.G(c);return e}}
+function nq(a,b){var c=O({},oq,a,b);if(!c)return null;var d="fillStyle"in c?c.fillStyle:Mp,e=c.fill;void 0===e||e||(d=null);var e="imageStyle"in c?c.imageStyle:Pp,f="textStyle"in c?c.textStyle:Rp,g="strokeStyle"in c?c.strokeStyle:Qp,c=c.outline;void 0===c||c||(g=null);return[new rj({fill:d,image:e,stroke:g,text:f,zIndex:void 0})]}
+function jq(a,b){var c=b.length,d=Array(b.length),e=Array(b.length),f,g,h,l;h=l=!1;for(g=0;g<c;++g)f=b[g],d[g]=f.get("extrude"),e[g]=f.get("altitudeMode"),h=h||void 0!==d[g],l=l||e[g];h&&a.set("extrude",d);l&&a.set("altitudeMode",e)}function pq(a,b){al(qq,a,b)}
+var rq=M(Kp,{value:Uk(U)}),qq=M(Kp,{Data:function(a,b){var c=a.getAttribute("name");if(null!==c){var d=O(void 0,rq,a,b);d&&(b[b.length-1][c]=d)}},SchemaData:function(a,b){al(sq,a,b)}}),eq=M(Kp,{extrude:J(Zn),altitudeMode:J(U)}),aq=M(Kp,{coordinates:Uk(Xp)}),mq=M(Kp,{innerBoundaryIs:function(a,b){var c=O(void 0,tq,a,b);c&&b[b.length-1].push(c)},outerBoundaryIs:function(a,b){var c=O(void 0,uq,a,b);c&&(b[b.length-1][0]=c)}}),cq=M(Kp,{when:function(a,b){var c=b[b.length-1].zi,d=Nk(a,!1);if(d=/^\s*(\d{4})($|-(\d{2})($|-(\d{2})($|T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?)))))\s*$/.exec(d)){var e=
+Date.UTC(parseInt(d[1],10),d[3]?parseInt(d[3],10)-1:0,d[5]?parseInt(d[5],10):1,d[7]?parseInt(d[7],10):0,d[8]?parseInt(d[8],10):0,d[9]?parseInt(d[9],10):0);if(d[10]&&"Z"!=d[10]){var f="-"==d[11]?-1:1,e=e+60*f*parseInt(d[12],10);d[13]&&(e+=3600*f*parseInt(d[13],10))}c.push(e)}else c.push(0)}},M(Jp,{coord:function(a,b){var c=b[b.length-1].B,d=Nk(a,!1);(d=/^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i.exec(d))?c.push(parseFloat(d[1]),
+parseFloat(d[2]),parseFloat(d[3]),0):c.push(0,0,0,0)}})),fq=M(Kp,{coordinates:Uk(Xp)}),vq=M(Kp,{href:J(Yp)},M(Jp,{x:J(bo),y:J(bo),w:J(bo),h:J(bo)})),wq=M(Kp,{Icon:J(function(a,b){var c=O({},vq,a,b);return c?c:null}),heading:J(bo),hotSpot:J(function(a){var b=a.getAttribute("xunits"),c=a.getAttribute("yunits");return{x:parseFloat(a.getAttribute("x")),$f:Sp[b],y:parseFloat(a.getAttribute("y")),ag:Sp[c]}}),scale:J(Zp)}),tq=M(Kp,{LinearRing:Uk($p)}),xq=M(Kp,{color:J(Wp),scale:J(Zp)}),yq=M(Kp,{color:J(Wp),
+width:J(bo)}),iq=M(Kp,{LineString:Tk(dq),LinearRing:Tk(gq),MultiGeometry:Tk(hq),Point:Tk(kq),Polygon:Tk(lq)}),zq=M(Jp,{Track:Tk(bq)}),Bq=M(Kp,{ExtendedData:pq,Link:function(a,b){al(Aq,a,b)},address:J(U),description:J(U),name:J(U),open:J(Zn),phoneNumber:J(U),visibility:J(Zn)}),Aq=M(Kp,{href:J(Yp)}),uq=M(Kp,{LinearRing:Uk($p)}),Cq=M(Kp,{Style:J(nq),key:J(U),styleUrl:J(function(a){var b=Nk(a,!1).trim();return a.baseURI?Bp(a.baseURI,b).toString():b})}),Eq=M(Kp,{ExtendedData:pq,MultiGeometry:J(hq,"geometry"),
+LineString:J(dq,"geometry"),LinearRing:J(gq,"geometry"),Point:J(kq,"geometry"),Polygon:J(lq,"geometry"),Style:J(nq),StyleMap:function(a,b){var c=O(void 0,Dq,a,b);if(c){var d=b[b.length-1];Array.isArray(c)?d.Style=c:"string"===typeof c&&(d.styleUrl=c)}},address:J(U),description:J(U),name:J(U),open:J(Zn),phoneNumber:J(U),styleUrl:J(Yp),visibility:J(Zn)},M(Jp,{MultiTrack:J(function(a,b){var c=O([],zq,a,b);if(c){var d=new S(null);An(d,c);return d}},"geometry"),Track:J(bq,"geometry")})),Fq=M(Kp,{color:J(Wp),
+fill:J(Zn),outline:J(Zn)}),sq=M(Kp,{SimpleData:function(a,b){var c=a.getAttribute("name");if(null!==c){var d=U(a);b[b.length-1][c]=d}}}),oq=M(Kp,{IconStyle:function(a,b){var c=O({},wq,a,b);if(c){var d=b[b.length-1],e="Icon"in c?c.Icon:{},f;f=(f=e.href)?f:"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png";var g,h,l,m=c.hotSpot;m?(g=[m.x,m.y],h=m.$f,l=m.ag):"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"===f?(g=Np,l=h="pixels"):/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(f)&&
+(g=[.5,0],l=h="fraction");var n,m=e.x,p=e.y;void 0!==m&&void 0!==p&&(n=[m,p]);var q,m=e.w,e=e.h;void 0!==m&&void 0!==e&&(q=[m,e]);var r,e=c.heading;void 0!==e&&(r=wa(e));c=c.scale;"https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"==f&&(q=Op,void 0===c&&(c=.5));g=new Dh({anchor:g,anchorOrigin:"bottom-left",anchorXUnits:h,anchorYUnits:l,crossOrigin:"anonymous",offset:n,offsetOrigin:"bottom-left",rotation:r,scale:c,size:q,src:f});d.imageStyle=g}},LabelStyle:function(a,b){var c=O({},xq,a,
+b);c&&(b[b.length-1].textStyle=new Gp({fill:new ij({color:"color"in c?c.color:Lp}),scale:c.scale}))},LineStyle:function(a,b){var c=O({},yq,a,b);c&&(b[b.length-1].strokeStyle=new oj({color:"color"in c?c.color:Lp,width:"width"in c?c.width:1}))},PolyStyle:function(a,b){var c=O({},Fq,a,b);if(c){var d=b[b.length-1];d.fillStyle=new ij({color:"color"in c?c.color:Lp});var e=c.fill;void 0!==e&&(d.fill=e);c=c.outline;void 0!==c&&(d.outline=c)}}}),Dq=M(Kp,{Pair:function(a,b){var c=O({},Cq,a,b);if(c){var d=c.key;
+d&&"normal"==d&&((d=c.styleUrl)&&(b[b.length-1]=d),(c=c.Style)&&(b[b.length-1]=c))}}});k=Hp.prototype;k.Gf=function(a,b){var c=M(Kp,{Document:Sk(this.Gf,this),Folder:Sk(this.Gf,this),Placemark:Tk(this.Of,this),Style:this.Lo.bind(this),StyleMap:this.Ko.bind(this)});if(c=O([],c,a,b,this))return c};
+k.Of=function(a,b){var c=O({geometry:null},Eq,a,b);if(c){var d=new Ik,e=a.getAttribute("id");null!==e&&d.mc(e);var e=b[0],f=c.geometry;f&&un(f,!1,e);d.Ua(f);delete c.geometry;this.c&&d.sf(Up(c.Style,c.styleUrl,this.g,this.b,this.i));delete c.Style;d.G(c);return d}};k.Lo=function(a,b){var c=a.getAttribute("id");if(null!==c){var d=nq(a,b);d&&(c=a.baseURI?Bp(a.baseURI,"#"+c).toString():"#"+c,this.b[c]=d)}};
+k.Ko=function(a,b){var c=a.getAttribute("id");if(null!==c){var d=O(void 0,Dq,a,b);d&&(c=a.baseURI?Bp(a.baseURI,"#"+c).toString():"#"+c,this.b[c]=d)}};k.Ph=function(a,b){if(!jb(Kp,a.namespaceURI))return null;var c=this.Of(a,[sn(this,a,b)]);return c?c:null};
+k.lc=function(a,b){if(!jb(Kp,a.namespaceURI))return[];var c;c=a.localName;if("Document"==c||"Folder"==c)return(c=this.Gf(a,[sn(this,a,b)]))?c:[];if("Placemark"==c)return(c=this.Of(a,[sn(this,a,b)]))?[c]:[];if("kml"==c){c=[];var d;for(d=a.firstElementChild;d;d=d.nextElementSibling){var e=this.lc(d,b);e&&mb(c,e)}return c}return[]};k.Fo=function(a){if(Pk(a))return Gq(this,a);if(Qk(a))return Hq(this,a);if("string"===typeof a)return a=Rk(a),Gq(this,a)};
+function Gq(a,b){var c;for(c=b.firstChild;c;c=c.nextSibling)if(c.nodeType==Node.ELEMENT_NODE){var d=Hq(a,c);if(d)return d}}function Hq(a,b){var c;for(c=b.firstElementChild;c;c=c.nextElementSibling)if(jb(Kp,c.namespaceURI)&&"name"==c.localName)return U(c);for(c=b.firstElementChild;c;c=c.nextElementSibling){var d=c.localName;if(jb(Kp,c.namespaceURI)&&("Document"==d||"Folder"==d||"Placemark"==d||"kml"==d)&&(d=Hq(a,c)))return d}}
+k.Go=function(a){var b=[];Pk(a)?mb(b,Iq(this,a)):Qk(a)?mb(b,Jq(this,a)):"string"===typeof a&&(a=Rk(a),mb(b,Iq(this,a)));return b};function Iq(a,b){var c,d=[];for(c=b.firstChild;c;c=c.nextSibling)c.nodeType==Node.ELEMENT_NODE&&mb(d,Jq(a,c));return d}
+function Jq(a,b){var c,d=[];for(c=b.firstElementChild;c;c=c.nextElementSibling)if(jb(Kp,c.namespaceURI)&&"NetworkLink"==c.localName){var e=O({},Bq,c,[]);d.push(e)}for(c=b.firstElementChild;c;c=c.nextElementSibling)e=c.localName,!jb(Kp,c.namespaceURI)||"Document"!=e&&"Folder"!=e&&"kml"!=e||mb(d,Jq(a,c));return d}function Kq(a,b){var c=te(b),c=[255*(4==c.length?c[3]:1),c[2],c[1],c[0]],d;for(d=0;4>d;++d){var e=parseInt(c[d],10).toString(16);c[d]=1==e.length?"0"+e:e}ho(a,c.join(""))}
+function Lq(a,b,c){a={node:a};var d=b.X(),e,f;"GeometryCollection"==d?(e=b.ff(),f=Mq):"MultiPoint"==d?(e=b.je(),f=Nq):"MultiLineString"==d?(e=b.md(),f=Oq):"MultiPolygon"==d&&(e=b.Wd(),f=Pq);bl(a,Qq,f,e,c)}function Rq(a,b,c){bl({node:a},Sq,Tq,[b],c)}
+function Uq(a,b,c){var d={node:a};b.Xa()&&a.setAttribute("id",b.Xa());a=b.O();var e=b.ec();e&&(e=e.call(b,0))&&(e=Array.isArray(e)?e[0]:e,this.l&&(a.Style=e),(e=e.Ha())&&(a.name=e.Ha()));e=Vq[c[c.length-1].node.namespaceURI];a=$k(a,e);bl(d,Wq,Zk,a,c,e);a=c[0];(b=b.W())&&(b=un(b,!0,a));bl(d,Wq,Mq,[b],c)}function Xq(a,b,c){var d=b.la();a={node:a};a.layout=b.f;a.stride=b.va();bl(a,Yq,Zq,[d],c)}function $q(a,b,c){b=b.Vd();var d=b.shift();a={node:a};bl(a,ar,br,b,c);bl(a,ar,cr,[d],c)}
+function dr(a,b){io(a,Math.round(b*b*1E6)/1E6)}
+var er=M(Kp,["Document","Placemark"]),hr=M(Kp,{Document:L(function(a,b,c){bl({node:a},fr,gr,b,c,void 0,this)}),Placemark:L(Uq)}),fr=M(Kp,{Placemark:L(Uq)}),ir={Point:"Point",LineString:"LineString",LinearRing:"LinearRing",Polygon:"Polygon",MultiPoint:"MultiGeometry",MultiLineString:"MultiGeometry",MultiPolygon:"MultiGeometry",GeometryCollection:"MultiGeometry"},jr=M(Kp,["href"],M(Jp,["x","y","w","h"])),kr=M(Kp,{href:L(ho)},M(Jp,{x:L(io),y:L(io),w:L(io),h:L(io)})),lr=M(Kp,["scale","heading","Icon",
+"hotSpot"]),nr=M(Kp,{Icon:L(function(a,b,c){a={node:a};var d=jr[c[c.length-1].node.namespaceURI],e=$k(b,d);bl(a,kr,Zk,e,c,d);d=jr[Jp[0]];e=$k(b,d);bl(a,kr,mr,e,c,d)}),heading:L(io),hotSpot:L(function(a,b){a.setAttribute("x",b.x);a.setAttribute("y",b.y);a.setAttribute("xunits",b.$f);a.setAttribute("yunits",b.ag)}),scale:L(dr)}),or=M(Kp,["color","scale"]),pr=M(Kp,{color:L(Kq),scale:L(dr)}),qr=M(Kp,["color","width"]),rr=M(Kp,{color:L(Kq),width:L(io)}),Sq=M(Kp,{LinearRing:L(Xq)}),Qq=M(Kp,{LineString:L(Xq),
+Point:L(Xq),Polygon:L($q),GeometryCollection:L(Lq)}),Vq=M(Kp,"name open visibility address phoneNumber description styleUrl Style".split(" ")),Wq=M(Kp,{MultiGeometry:L(Lq),LineString:L(Xq),LinearRing:L(Xq),Point:L(Xq),Polygon:L($q),Style:L(function(a,b,c){a={node:a};var d={},e=b.c,f=b.f,g=b.a;b=b.Ha();g instanceof Dh&&(d.IconStyle=g);b&&(d.LabelStyle=b);f&&(d.LineStyle=f);e&&(d.PolyStyle=e);b=sr[c[c.length-1].node.namespaceURI];d=$k(d,b);bl(a,tr,Zk,d,c,b)}),address:L(ho),description:L(ho),name:L(ho),
+open:L(go),phoneNumber:L(ho),styleUrl:L(ho),visibility:L(go)}),Yq=M(Kp,{coordinates:L(function(a,b,c){c=c[c.length-1];var d=c.layout;c=c.stride;var e;"XY"==d||"XYM"==d?e=2:("XYZ"==d||"XYZM"==d)&&(e=3);var f,g=b.length,h="";if(0<g){h+=b[0];for(d=1;d<e;++d)h+=","+b[d];for(f=c;f<g;f+=c)for(h+=" "+b[f],d=1;d<e;++d)h+=","+b[f+d]}ho(a,h)})}),ar=M(Kp,{outerBoundaryIs:L(Rq),innerBoundaryIs:L(Rq)}),ur=M(Kp,{color:L(Kq)}),sr=M(Kp,["IconStyle","LabelStyle","LineStyle","PolyStyle"]),tr=M(Kp,{IconStyle:L(function(a,
+b,c){a={node:a};var d={},e=b.Fb(),f=b.ld(),g={href:b.b.j};if(e){g.w=e[0];g.h=e[1];var h=b.Yb(),l=b.Ia();l&&f&&0!==l[0]&&l[1]!==e[1]&&(g.x=l[0],g.y=f[1]-(l[1]+e[1]));h&&0!==h[0]&&h[1]!==e[1]&&(d.hotSpot={x:h[0],$f:"pixels",y:e[1]-h[1],ag:"pixels"})}d.Icon=g;e=b.i;1!==e&&(d.scale=e);b=b.j;0!==b&&(d.heading=b);b=lr[c[c.length-1].node.namespaceURI];d=$k(d,b);bl(a,nr,Zk,d,c,b)}),LabelStyle:L(function(a,b,c){a={node:a};var d={},e=b.b;e&&(d.color=e.b);(b=b.a)&&1!==b&&(d.scale=b);b=or[c[c.length-1].node.namespaceURI];
+d=$k(d,b);bl(a,pr,Zk,d,c,b)}),LineStyle:L(function(a,b,c){a={node:a};var d=qr[c[c.length-1].node.namespaceURI];b=$k({color:b.b,width:b.a},d);bl(a,rr,Zk,b,c,d)}),PolyStyle:L(function(a,b,c){bl({node:a},ur,vr,[b.b],c)})});function mr(a,b,c){return Mk(Jp[0],"gx:"+c)}function gr(a,b){return Mk(b[b.length-1].node.namespaceURI,"Placemark")}function Mq(a,b){if(a)return Mk(b[b.length-1].node.namespaceURI,ir[a.X()])}
+var vr=Xk("color"),Zq=Xk("coordinates"),br=Xk("innerBoundaryIs"),Nq=Xk("Point"),Oq=Xk("LineString"),Tq=Xk("LinearRing"),Pq=Xk("Polygon"),cr=Xk("outerBoundaryIs");
+Hp.prototype.a=function(a,b){b=tn(this,b);var c=Mk(Kp[4],"kml");c.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:gx",Jp[0]);c.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");c.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation","http://www.opengis.net/kml/2.2 https://developers.google.com/kml/schema/kml22gx.xsd");var d={node:c},e={};1<a.length?e.Document=a:1==a.length&&(e.Placemark=a[0]);var f=er[c.namespaceURI],
+e=$k(e,f);bl(d,hr,Zk,e,[b],f,this);return c};(function(){var a={},b={ja:a};(function(c){if("object"===typeof a&&"undefined"!==typeof b)b.ja=c();else{var d;"undefined"!==typeof window?d=window:"undefined"!==typeof global?d=global:"undefined"!==typeof self?d=self:d=this;d.Rp=c()}})(function(){return function d(a,b,g){function h(m,p){if(!b[m]){if(!a[m]){var q="function"==typeof require&&require;if(!p&&q)return q(m,!0);if(l)return l(m,!0);q=Error("Cannot find module '"+m+"'");throw q.code="MODULE_NOT_FOUND",q;}q=b[m]={ja:{}};a[m][0].call(q.ja,function(b){var d=
+a[m][1][b];return h(d?d:b)},q,q.ja,d,a,b,g)}return b[m].ja}for(var l="function"==typeof require&&require,m=0;m<g.length;m++)h(g[m]);return h}({1:[function(a,b){function f(a){var b;a&&a.length&&(b=a,a=b.length);a=new Uint8Array(a||0);b&&a.set(b);a.$h=l.$h;a.Zf=l.Zf;a.Sh=l.Sh;a.Ei=l.Ei;a.Nf=l.Nf;a.Di=l.Di;a.Hf=l.Hf;a.Ai=l.Ai;a.toString=l.toString;a.write=l.write;a.slice=l.slice;a.tg=l.tg;a.nj=!0;return a}function g(a){for(var b=a.length,d=[],e=0,f,g;e<b;e++){f=a.charCodeAt(e);if(55295<f&&57344>f)if(g)if(56320>
+f){d.push(239,191,189);g=f;continue}else f=g-55296<<10|f-56320|65536,g=null;else{56319<f||e+1===b?d.push(239,191,189):g=f;continue}else g&&(d.push(239,191,189),g=null);128>f?d.push(f):2048>f?d.push(f>>6|192,f&63|128):65536>f?d.push(f>>12|224,f>>6&63|128,f&63|128):d.push(f>>18|240,f>>12&63|128,f>>6&63|128,f&63|128)}return d}b.ja=f;var h=a("ieee754"),l,m,n;l={$h:function(a){return(this[a]|this[a+1]<<8|this[a+2]<<16)+16777216*this[a+3]},Zf:function(a,b){this[b]=a;this[b+1]=a>>>8;this[b+2]=a>>>16;this[b+
+3]=a>>>24},Sh:function(a){return(this[a]|this[a+1]<<8|this[a+2]<<16)+(this[a+3]<<24)},Nf:function(a){return h.read(this,a,!0,23,4)},Hf:function(a){return h.read(this,a,!0,52,8)},Di:function(a,b){return h.write(this,a,b,!0,23,4)},Ai:function(a,b){return h.write(this,a,b,!0,52,8)},toString:function(a,b,d){var e=a="";d=Math.min(this.length,d||this.length);for(b=b||0;b<d;b++){var f=this[b];127>=f?(a+=decodeURIComponent(e)+String.fromCharCode(f),e=""):e+="%"+f.toString(16)}return a+=decodeURIComponent(e)},
+write:function(a,b){for(var d=a===m?n:g(a),e=0;e<d.length;e++)this[b+e]=d[e]},slice:function(a,b){return this.subarray(a,b)},tg:function(a,b){b=b||0;for(var d=0;d<this.length;d++)a[b+d]=this[d]}};l.Ei=l.Zf;f.byteLength=function(a){m=a;n=g(a);return n.length};f.isBuffer=function(a){return!(!a||!a.nj)}},{ieee754:3}],2:[function(a,b){(function(f){function g(a){this.Cb=l.isBuffer(a)?a:new l(a||0);this.da=0;this.length=this.Cb.length}function h(a,b){var d=b.Cb,e;e=d[b.da++];a+=268435456*(e&127);if(128>
+e)return a;e=d[b.da++];a+=34359738368*(e&127);if(128>e)return a;e=d[b.da++];a+=4398046511104*(e&127);if(128>e)return a;e=d[b.da++];a+=562949953421312*(e&127);if(128>e)return a;e=d[b.da++];a+=72057594037927936*(e&127);if(128>e)return a;e=d[b.da++];if(128>e)return a+0x7fffffffffffffff*(e&127);throw Error("Expected varint not more than 10 bytes");}b.ja=g;var l=f.Ap||a("./buffer");g.f=0;g.g=1;g.b=2;g.a=5;var m=Math.pow(2,63);g.prototype={Lf:function(a,b,d){for(d=d||this.length;this.da<d;){var e=this.Da(),
+f=this.da;a(e>>3,b,this);this.da===f&&this.op(e)}return b},Bo:function(){var a=this.Cb.Nf(this.da);this.da+=4;return a},xo:function(){var a=this.Cb.Hf(this.da);this.da+=8;return a},Da:function(){var a=this.Cb,b,d;d=a[this.da++];b=d&127;if(128>d)return b;d=a[this.da++];b|=(d&127)<<7;if(128>d)return b;d=a[this.da++];b|=(d&127)<<14;if(128>d)return b;d=a[this.da++];b|=(d&127)<<21;return 128>d?b:h(b,this)},Mo:function(){var a=this.da,b=this.Da();if(b<m)return b;for(var d=this.da-2;255===this.Cb[d];)d--;
+d<a&&(d=a);for(var e=b=0;e<d-a+1;e++)var f=~this.Cb[a+e]&127,b=b+(4>e?f<<7*e:f*Math.pow(2,7*e));return-b-1},xd:function(){var a=this.Da();return 1===a%2?(a+1)/-2:a/2},vo:function(){return!!this.Da()},Qf:function(){var a=this.Da()+this.da,b=this.Cb.toString("utf8",this.da,a);this.da=a;return b},op:function(a){a&=7;if(a===g.f)for(;127<this.Cb[this.da++];);else if(a===g.b)this.da=this.Da()+this.da;else if(a===g.a)this.da+=4;else if(a===g.g)this.da+=8;else throw Error("Unimplemented type: "+a);}}}).call(this,
+"undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{})},{"./buffer":1}],3:[function(a,b,f){f.read=function(a,b,d,e,f){var p;p=8*f-e-1;var q=(1<<p)-1,r=q>>1,u=-7;f=d?f-1:0;var x=d?-1:1,v=a[b+f];f+=x;d=v&(1<<-u)-1;v>>=-u;for(u+=p;0<u;d=256*d+a[b+f],f+=x,u-=8);p=d&(1<<-u)-1;d>>=-u;for(u+=e;0<u;p=256*p+a[b+f],f+=x,u-=8);if(0===d)d=1-r;else{if(d===q)return p?NaN:Infinity*(v?-1:1);p+=Math.pow(2,e);d-=r}return(v?-1:1)*p*Math.pow(2,d-e)};f.write=function(a,
+b,d,e,f,p){var q,r=8*p-f-1,u=(1<<r)-1,x=u>>1,v=23===f?Math.pow(2,-24)-Math.pow(2,-77):0;p=e?0:p-1;var D=e?1:-1,A=0>b||0===b&&0>1/b?1:0;b=Math.abs(b);isNaN(b)||Infinity===b?(b=isNaN(b)?1:0,e=u):(e=Math.floor(Math.log(b)/Math.LN2),1>b*(q=Math.pow(2,-e))&&(e--,q*=2),b=1<=e+x?b+v/q:b+v*Math.pow(2,1-x),2<=b*q&&(e++,q/=2),e+x>=u?(b=0,e=u):1<=e+x?(b=(b*q-1)*Math.pow(2,f),e+=x):(b=b*Math.pow(2,x-1)*Math.pow(2,f),e=0));for(;8<=f;a[d+p]=b&255,p+=D,b/=256,f-=8);e=e<<f|b;for(r+=f;0<r;a[d+p]=e&255,p+=D,e/=256,
+r-=8);a[d+p-D]|=128*A}},{}]},{},[2])(2)});hl=b.ja})();(function(){var a={},b={ja:a};(function(c){if("object"===typeof a&&"undefined"!==typeof b)b.ja=c();else{var d;"undefined"!==typeof window?d=window:"undefined"!==typeof global?d=global:"undefined"!==typeof self?d=self:d=this;d.Up=c()}})(function(){return function d(a,b,g){function h(m,p){if(!b[m]){if(!a[m]){var q="function"==typeof require&&require;if(!p&&q)return q(m,!0);if(l)return l(m,!0);q=Error("Cannot find module '"+m+"'");throw q.code="MODULE_NOT_FOUND",q;}q=b[m]={ja:{}};a[m][0].call(q.ja,function(b){var d=
+a[m][1][b];return h(d?d:b)},q,q.ja,d,a,b,g)}return b[m].ja}for(var l="function"==typeof require&&require,m=0;m<g.length;m++)h(g[m]);return h}({1:[function(a,b){b.ja.ej=a("./lib/vectortile.js");b.ja.Np=a("./lib/vectortilefeature.js");b.ja.Op=a("./lib/vectortilelayer.js")},{"./lib/vectortile.js":2,"./lib/vectortilefeature.js":3,"./lib/vectortilelayer.js":4}],2:[function(a,b){function f(a,b,d){3===a&&(a=new g(d,d.Da()+d.da),a.length&&(b[a.name]=a))}var g=a("./vectortilelayer");b.ja=function(a,b){this.layers=
+a.Lf(f,{},b)}},{"./vectortilelayer":4}],3:[function(a,b){function f(a,b,d,e,f){this.properties={};this.extent=d;this.type=0;this.qc=a;this.Qe=-1;this.Id=e;this.Kd=f;a.Lf(g,this,b)}function g(a,b,d){if(1==a)b.Qp=d.Da();else if(2==a)for(a=d.Da()+d.da;d.da<a;){var e=b.Id[d.Da()],f=b.Kd[d.Da()];b.properties[e]=f}else 3==a?b.type=d.Da():4==a&&(b.Qe=d.da)}var h=a("point-geometry");b.ja=f;f.b=["Unknown","Point","LineString","Polygon"];f.prototype.Vg=function(){var a=this.qc;a.da=this.Qe;for(var b=a.Da()+
+a.da,d=1,e=0,f=0,g=0,u=[],x;a.da<b;)if(e||(e=a.Da(),d=e&7,e>>=3),e--,1===d||2===d)f+=a.xd(),g+=a.xd(),1===d&&(x&&u.push(x),x=[]),x.push(new h(f,g));else if(7===d)x&&x.push(x[0].clone());else throw Error("unknown command "+d);x&&u.push(x);return u};f.prototype.bbox=function(){var a=this.qc;a.da=this.Qe;for(var b=a.Da()+a.da,d=1,e=0,f=0,g=0,h=Infinity,x=-Infinity,v=Infinity,D=-Infinity;a.da<b;)if(e||(e=a.Da(),d=e&7,e>>=3),e--,1===d||2===d)f+=a.xd(),g+=a.xd(),f<h&&(h=f),f>x&&(x=f),g<v&&(v=g),g>D&&(D=
+g);else if(7!==d)throw Error("unknown command "+d);return[h,v,x,D]}},{"point-geometry":5}],4:[function(a,b){function f(a,b){this.version=1;this.name=null;this.extent=4096;this.length=0;this.qc=a;this.Id=[];this.Kd=[];this.Hd=[];a.Lf(g,this,b);this.length=this.Hd.length}function g(a,b,d){15===a?b.version=d.Da():1===a?b.name=d.Qf():5===a?b.extent=d.Da():2===a?b.Hd.push(d.da):3===a?b.Id.push(d.Qf()):4===a&&b.Kd.push(h(d))}function h(a){for(var b=null,d=a.Da()+a.da;a.da<d;)b=a.Da()>>3,b=1===b?a.Qf():
+2===b?a.Bo():3===b?a.xo():4===b?a.Mo():5===b?a.Da():6===b?a.xd():7===b?a.vo():null;return b}var l=a("./vectortilefeature.js");b.ja=f;f.prototype.feature=function(a){if(0>a||a>=this.Hd.length)throw Error("feature index out of bounds");this.qc.da=this.Hd[a];a=this.qc.Da()+this.qc.da;return new l(this.qc,a,this.extent,this.Id,this.Kd)}},{"./vectortilefeature.js":3}],5:[function(a,b){function f(a,b){this.x=a;this.y=b}b.ja=f;f.prototype={clone:function(){return new f(this.x,this.y)},add:function(a){return this.clone().fj(a)},
+rotate:function(a){return this.clone().qj(a)},round:function(){return this.clone().rj()},angle:function(){return Math.atan2(this.y,this.x)},fj:function(a){this.x+=a.x;this.y+=a.y;return this},qj:function(a){var b=Math.cos(a);a=Math.sin(a);var d=a*this.x+b*this.y;this.x=b*this.x-a*this.y;this.y=d;return this},rj:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this}};f.b=function(a){return a instanceof f?a:Array.isArray(a)?new f(a[0],a[1]):a}},{}]},{},[1])(1)});il=b.ja})();function wr(a){this.defaultDataProjection=null;a=a?a:{};this.defaultDataProjection=new vc({code:"",units:"tile-pixels"});this.b=a.featureClass?a.featureClass:hk;this.g=a.geometryName?a.geometryName:"geometry";this.a=a.layerName?a.layerName:"layer";this.f=a.layers?a.layers:null}y(wr,rn);wr.prototype.X=function(){return"arraybuffer"};
+wr.prototype.Fa=function(a,b){var c=this.f,d=new hl(a),d=new il.ej(d),e=[],f=this.b,g,h,l;for(l in d.layers)if(!c||-1!=c.indexOf(l)){g=d.layers[l];for(var m=0,n=g.length;m<n;++m){if(f===hk){var p=g.feature(m);h=l;var q=p.Vg(),r=[],u=[];xr(q,u,r);var x=p.type,v=void 0;1===x?v=1===q.length?"Point":"MultiPoint":2===x?v=1===q.length?"LineString":"MultiLineString":3===x&&(v="Polygon");p=p.properties;p[this.a]=h;h=new this.b(v,u,r,p)}else{p=g.feature(m);v=l;u=b;h=new this.b;r=p.properties;r[this.a]=v;v=
+p.type;if(0===v)v=null;else{p=p.Vg();q=[];x=[];xr(p,x,q);var D=void 0;1===v?D=1===p.length?new C(null):new Bn(null):2===v?1===p.length?D=new R(null):D=new S(null):3===v&&(D=new E(null));D.ba("XY",x,q);v=D}(u=un(v,!1,tn(this,u)))&&(r[this.g]=u);h.G(r);h.Ec(this.g)}e.push(h)}}return e};wr.prototype.Oa=function(){return this.defaultDataProjection};wr.prototype.c=function(a){this.f=a};
+function xr(a,b,c){for(var d=0,e=0,f=a.length;e<f;++e){var g=a[e],h,l;h=0;for(l=g.length;h<l;++h){var m=g[h];b.push(m.x,m.y)}d+=2*h;c.push(d)}};function yr(a,b){return new zr(a,b)}function Ar(a,b,c){return new Br(a,b,c)}function Cr(a){this.Wb=a}function Dr(a){this.Wb=a}y(Dr,Cr);function Er(a,b,c){this.Wb=a;this.b=b;this.a=c}y(Er,Dr);function zr(a,b){Er.call(this,"And",a,b)}y(zr,Er);function Fr(a,b){Er.call(this,"Or",a,b)}y(Fr,Er);function Gr(a){this.Wb="Not";this.condition=a}y(Gr,Dr);function Br(a,b,c){this.Wb="BBOX";this.geometryName=a;this.extent=b;this.srsName=c}y(Br,Cr);function Hr(a,b){this.Wb=a;this.b=b}y(Hr,Cr);
+function Ir(a,b,c,d){Hr.call(this,a,b);this.g=c;this.a=d}y(Ir,Hr);function Jr(a,b,c){Ir.call(this,"PropertyIsEqualTo",a,b,c)}y(Jr,Ir);function Kr(a,b,c){Ir.call(this,"PropertyIsNotEqualTo",a,b,c)}y(Kr,Ir);function Lr(a,b){Ir.call(this,"PropertyIsLessThan",a,b)}y(Lr,Ir);function Mr(a,b){Ir.call(this,"PropertyIsLessThanOrEqualTo",a,b)}y(Mr,Ir);function Nr(a,b){Ir.call(this,"PropertyIsGreaterThan",a,b)}y(Nr,Ir);function Or(a,b){Ir.call(this,"PropertyIsGreaterThanOrEqualTo",a,b)}y(Or,Ir);
+function Pr(a){Hr.call(this,"PropertyIsNull",a)}y(Pr,Hr);function Qr(a,b,c){Hr.call(this,"PropertyIsBetween",a);this.a=b;this.g=c}y(Qr,Hr);function Rr(a,b,c,d,e,f){Hr.call(this,"PropertyIsLike",a);this.f=b;this.i=void 0!==c?c:"*";this.c=void 0!==d?d:".";this.g=void 0!==e?e:"!";this.a=f}y(Rr,Hr);function Sr(){Un.call(this);this.defaultDataProjection=yc("EPSG:4326")}y(Sr,Un);function Tr(a,b){b[b.length-1].Cd[a.getAttribute("k")]=a.getAttribute("v")}
+var Ur=[null],Vr=M(Ur,{nd:function(a,b){b[b.length-1].Rc.push(a.getAttribute("ref"))},tag:Tr}),Xr=M(Ur,{node:function(a,b){var c=b[0],d=b[b.length-1],e=a.getAttribute("id"),f=[parseFloat(a.getAttribute("lon")),parseFloat(a.getAttribute("lat"))];d.Zg[e]=f;var g=O({Cd:{}},Wr,a,b);Ha(g.Cd)||(f=new C(f),un(f,!1,c),c=new Ik(f),c.mc(e),c.G(g.Cd),d.features.push(c))},way:function(a,b){for(var c=b[0],d=a.getAttribute("id"),e=O({Rc:[],Cd:{}},Vr,a,b),f=b[b.length-1],g=[],h=0,l=e.Rc.length;h<l;h++)mb(g,f.Zg[e.Rc[h]]);
+e.Rc[0]==e.Rc[e.Rc.length-1]?(h=new E(null),h.ba("XY",g,[g.length])):(h=new R(null),h.ba("XY",g));un(h,!1,c);c=new Ik(h);c.mc(d);c.G(e.Cd);f.features.push(c)}}),Wr=M(Ur,{tag:Tr});Sr.prototype.lc=function(a,b){var c=sn(this,a,b);return"osm"==a.localName&&(c=O({Zg:{},features:[]},Xr,a,[c]),c.features)?c.features:[]};function Yr(a){return a.getAttributeNS("http://www.w3.org/1999/xlink","href")};function Zr(){}Zr.prototype.read=function(a){return Pk(a)?this.a(a):Qk(a)?this.b(a):"string"===typeof a?(a=Rk(a),this.a(a)):null};function $r(){}y($r,Zr);$r.prototype.a=function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType==Node.ELEMENT_NODE)return this.b(a);return null};$r.prototype.b=function(a){return(a=O({},as,a,[]))?a:null};
+var bs=[null,"http://www.opengis.net/ows/1.1"],as=M(bs,{ServiceIdentification:J(function(a,b){return O({},cs,a,b)}),ServiceProvider:J(function(a,b){return O({},ds,a,b)}),OperationsMetadata:J(function(a,b){return O({},es,a,b)})}),fs=M(bs,{DeliveryPoint:J(U),City:J(U),AdministrativeArea:J(U),PostalCode:J(U),Country:J(U),ElectronicMailAddress:J(U)}),gs=M(bs,{Value:Vk(function(a){return U(a)})}),hs=M(bs,{AllowedValues:J(function(a,b){return O({},gs,a,b)})}),js=M(bs,{Phone:J(function(a,b){return O({},
+is,a,b)}),Address:J(function(a,b){return O({},fs,a,b)})}),ls=M(bs,{HTTP:J(function(a,b){return O({},ks,a,b)})}),ks=M(bs,{Get:Vk(function(a,b){var c=Yr(a);return c?O({href:c},ms,a,b):void 0}),Post:void 0}),ns=M(bs,{DCP:J(function(a,b){return O({},ls,a,b)})}),es=M(bs,{Operation:function(a,b){var c=a.getAttribute("name"),d=O({},ns,a,b);d&&(b[b.length-1][c]=d)}}),is=M(bs,{Voice:J(U),Facsimile:J(U)}),ms=M(bs,{Constraint:Vk(function(a,b){var c=a.getAttribute("name");return c?O({name:c},hs,a,b):void 0})}),
+os=M(bs,{IndividualName:J(U),PositionName:J(U),ContactInfo:J(function(a,b){return O({},js,a,b)})}),cs=M(bs,{Title:J(U),ServiceTypeVersion:J(U),ServiceType:J(U)}),ds=M(bs,{ProviderName:J(U),ProviderSite:J(Yr),ServiceContact:J(function(a,b){return O({},os,a,b)})});function ps(a,b,c,d){var e;void 0!==d?e=d:e=[];for(var f=d=0;f<b;){var g=a[f++];e[d++]=a[f++];e[d++]=g;for(g=2;g<c;++g)e[d++]=a[f++]}e.length=d};function qs(a){a=a?a:{};this.defaultDataProjection=null;this.defaultDataProjection=yc("EPSG:4326");this.b=a.factor?a.factor:1E5;this.a=a.geometryLayout?a.geometryLayout:"XY"}y(qs,bp);function rs(a,b,c){var d,e=Array(b);for(d=0;d<b;++d)e[d]=0;var f,g;f=0;for(g=a.length;f<g;)for(d=0;d<b;++d,++f){var h=a[f],l=h-e[d];e[d]=h;a[f]=l}return ss(a,c?c:1E5)}
+function ts(a,b,c){var d,e=Array(b);for(d=0;d<b;++d)e[d]=0;a=us(a,c?c:1E5);var f;c=0;for(f=a.length;c<f;)for(d=0;d<b;++d,++c)e[d]+=a[c],a[c]=e[d];return a}function ss(a,b){var c=b?b:1E5,d,e;d=0;for(e=a.length;d<e;++d)a[d]=Math.round(a[d]*c);c=0;for(d=a.length;c<d;++c)e=a[c],a[c]=0>e?~(e<<1):e<<1;c="";d=0;for(e=a.length;d<e;++d){for(var f=a[d],g,h="";32<=f;)g=(32|f&31)+63,h+=String.fromCharCode(g),f>>=5;h+=String.fromCharCode(f+63);c+=h}return c}
+function us(a,b){var c=b?b:1E5,d=[],e=0,f=0,g,h;g=0;for(h=a.length;g<h;++g){var l=a.charCodeAt(g)-63,e=e|(l&31)<<f;32>l?(d.push(e),f=e=0):f+=5}e=0;for(f=d.length;e<f;++e)g=d[e],d[e]=g&1?~(g>>1):g>>1;e=0;for(f=d.length;e<f;++e)d[e]/=c;return d}k=qs.prototype;k.ud=function(a,b){var c=this.wd(a,b);return new Ik(c)};k.Kf=function(a,b){return[this.ud(a,b)]};k.wd=function(a,b){var c=id(this.a),d=ts(a,c,this.b);ps(d,d.length,c,d);c=vd(d,0,d.length,c);return un(new R(c,this.a),!1,tn(this,b))};
+k.He=function(a,b){var c=a.W();return c?this.Ed(c,b):""};k.Ci=function(a,b){return this.He(a[0],b)};k.Ed=function(a,b){a=un(a,!0,tn(this,b));var c=a.la(),d=a.va();ps(c,c.length,d,c);return rs(c,d,this.b)};function ws(a){a=a?a:{};this.defaultDataProjection=null;this.defaultDataProjection=yc(a.defaultDataProjection?a.defaultDataProjection:"EPSG:4326")}y(ws,vn);function xs(a,b){var c=[],d,e,f,g;f=0;for(g=a.length;f<g;++f)d=a[f],0<f&&c.pop(),0<=d?e=b[d]:e=b[~d].slice().reverse(),c.push.apply(c,e);d=0;for(e=c.length;d<e;++d)c[d]=c[d].slice();return c}function ys(a,b,c,d,e){a=a.geometries;var f=[],g,h;g=0;for(h=a.length;g<h;++g)f[g]=zs(a[g],b,c,d,e);return f}
+function zs(a,b,c,d,e){var f=a.type,g=As[f];b="Point"===f||"MultiPoint"===f?g(a,c,d):g(a,b);c=new Ik;c.Ua(un(b,!1,e));void 0!==a.id&&c.mc(a.id);a.properties&&c.G(a.properties);return c}
+ws.prototype.Jf=function(a,b){if("Topology"==a.type){var c,d=null,e=null;a.transform&&(c=a.transform,d=c.scale,e=c.translate);var f=a.arcs;if(c){c=d;var g=e,h,l;h=0;for(l=f.length;h<l;++h){var m=f[h],n=c,p=g,q=0,r=0,u,x,v;x=0;for(v=m.length;x<v;++x)u=m[x],q+=u[0],r+=u[1],u[0]=q,u[1]=r,Bs(u,n,p)}}c=[];g=Ga(a.objects);h=0;for(l=g.length;h<l;++h)"GeometryCollection"===g[h].type?(m=g[h],c.push.apply(c,ys(m,f,d,e,b))):(m=g[h],c.push(zs(m,f,d,e,b)));return c}return[]};
+function Bs(a,b,c){a[0]=a[0]*b[0]+c[0];a[1]=a[1]*b[1]+c[1]}ws.prototype.Oa=function(){return this.defaultDataProjection};
+var As={Point:function(a,b,c){a=a.coordinates;b&&c&&Bs(a,b,c);return new C(a)},LineString:function(a,b){var c=xs(a.arcs,b);return new R(c)},Polygon:function(a,b){var c=[],d,e;d=0;for(e=a.arcs.length;d<e;++d)c[d]=xs(a.arcs[d],b);return new E(c)},MultiPoint:function(a,b,c){a=a.coordinates;var d,e;if(b&&c)for(d=0,e=a.length;d<e;++d)Bs(a[d],b,c);return new Bn(a)},MultiLineString:function(a,b){var c=[],d,e;d=0;for(e=a.arcs.length;d<e;++d)c[d]=xs(a.arcs[d],b);return new S(c)},MultiPolygon:function(a,b){var c=
+[],d,e,f,g,h,l;h=0;for(l=a.arcs.length;h<l;++h){d=a.arcs[h];e=[];f=0;for(g=d.length;f<g;++f)e[f]=xs(d[f],b);c[h]=e}return new T(c)}};function Cs(a){a=a?a:{};this.i=a.featureType;this.g=a.featureNS;this.b=a.gmlFormat?a.gmlFormat:new lo;this.c=a.schemaLocation?a.schemaLocation:"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd";Un.call(this)}y(Cs,Un);Cs.prototype.lc=function(a,b){var c={featureType:this.i,featureNS:this.g};Ea(c,sn(this,a,b?b:{}));c=[c];this.b.b["http://www.opengis.net/gml"].featureMember=Tk(Xn.prototype.vd);(c=O([],this.b.b,a,c,this.b))||(c=[]);return c};
+Cs.prototype.o=function(a){if(Pk(a))return Ds(a);if(Qk(a))return O({},Es,a,[]);if("string"===typeof a)return a=Rk(a),Ds(a)};Cs.prototype.l=function(a){if(Pk(a))return Fs(this,a);if(Qk(a))return Gs(this,a);if("string"===typeof a)return a=Rk(a),Fs(this,a)};function Fs(a,b){for(var c=b.firstChild;c;c=c.nextSibling)if(c.nodeType==Node.ELEMENT_NODE)return Gs(a,c)}var Hs={"http://www.opengis.net/gml":{boundedBy:J(Xn.prototype.ye,"bounds")}};
+function Gs(a,b){var c={},d=fo(b.getAttribute("numberOfFeatures"));c.numberOfFeatures=d;return O(c,Hs,b,[],a.b)}
+var Is={"http://www.opengis.net/wfs":{totalInserted:J(eo),totalUpdated:J(eo),totalDeleted:J(eo)}},Js={"http://www.opengis.net/ogc":{FeatureId:Tk(function(a){return a.getAttribute("fid")})}},Ks={"http://www.opengis.net/wfs":{Feature:function(a,b){al(Js,a,b)}}},Es={"http://www.opengis.net/wfs":{TransactionSummary:J(function(a,b){return O({},Is,a,b)},"transactionSummary"),InsertResults:J(function(a,b){return O([],Ks,a,b)},"insertIds")}};
+function Ds(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType==Node.ELEMENT_NODE)return O({},Es,a,[])}var Ls={"http://www.opengis.net/wfs":{PropertyName:L(ho)}};function Ms(a,b){var c=Mk("http://www.opengis.net/ogc","Filter"),d=Mk("http://www.opengis.net/ogc","FeatureId");c.appendChild(d);d.setAttribute("fid",b);a.appendChild(c)}
+var Ns={"http://www.opengis.net/wfs":{Insert:L(function(a,b,c){var d=c[c.length-1],d=Mk(d.featureNS,d.featureType);a.appendChild(d);lo.prototype.Bi(d,b,c)}),Update:L(function(a,b,c){var d=c[c.length-1],e=d.featureType,f=d.featurePrefix,f=f?f:"feature",g=d.featureNS;a.setAttribute("typeName",f+":"+e);a.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:"+f,g);e=b.Xa();if(void 0!==e){for(var f=b.N(),g=[],h=0,l=f.length;h<l;h++){var m=b.get(f[h]);void 0!==m&&g.push({name:f[h],value:m})}bl({node:a,
+srsName:d.srsName},Ns,Xk("Property"),g,c);Ms(a,e)}}),Delete:L(function(a,b,c){var d=c[c.length-1];c=d.featureType;var e=d.featurePrefix,e=e?e:"feature",d=d.featureNS;a.setAttribute("typeName",e+":"+c);a.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:"+e,d);b=b.Xa();void 0!==b&&Ms(a,b)}),Property:L(function(a,b,c){var d=Mk("http://www.opengis.net/wfs","Name");a.appendChild(d);ho(d,b.name);void 0!==b.value&&null!==b.value&&(d=Mk("http://www.opengis.net/wfs","Value"),a.appendChild(d),b.value instanceof
+Tc?lo.prototype.Je(d,b.value,c):ho(d,b.value))}),Native:L(function(a,b){b.wp&&a.setAttribute("vendorId",b.wp);void 0!==b.Yo&&a.setAttribute("safeToIgnore",b.Yo);void 0!==b.value&&ho(a,b.value)})}};function Os(a,b,c){a={node:a};var d=b.b;bl(a,Ps,Xk(d.Wb),[d],c);b=b.a;bl(a,Ps,Xk(b.Wb),[b],c)}function Qs(a,b){void 0!==b.a&&a.setAttribute("matchCase",b.a.toString());Rs(a,b.b);Ss("Literal",a,""+b.g)}function Ss(a,b,c){a=Mk("http://www.opengis.net/ogc",a);ho(a,c);b.appendChild(a)}
+function Rs(a,b){Ss("PropertyName",a,b)}
+var Ps={"http://www.opengis.net/wfs":{Query:L(function(a,b,c){var d=c[c.length-1],e=d.featurePrefix,f=d.featureNS,g=d.propertyNames,h=d.srsName;a.setAttribute("typeName",(e?e+":":"")+b);h&&a.setAttribute("srsName",h);f&&a.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:"+e,f);b=Ea({},d);b.node=a;bl(b,Ls,Xk("PropertyName"),g,c);if(d=d.filter)g=Mk("http://www.opengis.net/ogc","Filter"),a.appendChild(g),bl({node:g},Ps,Xk(d.Wb),[d],c)})},"http://www.opengis.net/ogc":{And:L(Os),Or:L(Os),Not:L(function(a,
+b,c){b=b.condition;bl({node:a},Ps,Xk(b.Wb),[b],c)}),BBOX:L(function(a,b,c){c[c.length-1].srsName=b.srsName;Rs(a,b.geometryName);lo.prototype.Je(a,b.extent,c)}),PropertyIsEqualTo:L(Qs),PropertyIsNotEqualTo:L(Qs),PropertyIsLessThan:L(Qs),PropertyIsLessThanOrEqualTo:L(Qs),PropertyIsGreaterThan:L(Qs),PropertyIsGreaterThanOrEqualTo:L(Qs),PropertyIsNull:L(function(a,b){Rs(a,b.b)}),PropertyIsBetween:L(function(a,b){Rs(a,b.b);Ss("LowerBoundary",a,""+b.a);Ss("UpperBoundary",a,""+b.g)}),PropertyIsLike:L(function(a,
+b){a.setAttribute("wildCard",b.i);a.setAttribute("singleChar",b.c);a.setAttribute("escapeChar",b.g);void 0!==b.a&&a.setAttribute("matchCase",b.a.toString());Rs(a,b.b);Ss("Literal",a,""+b.f)})}};
+Cs.prototype.j=function(a){var b=Mk("http://www.opengis.net/wfs","GetFeature");b.setAttribute("service","WFS");b.setAttribute("version","1.1.0");var c;if(a&&(a.handle&&b.setAttribute("handle",a.handle),a.outputFormat&&b.setAttribute("outputFormat",a.outputFormat),void 0!==a.maxFeatures&&b.setAttribute("maxFeatures",a.maxFeatures),a.resultType&&b.setAttribute("resultType",a.resultType),void 0!==a.startIndex&&b.setAttribute("startIndex",a.startIndex),void 0!==a.count&&b.setAttribute("count",a.count),
+c=a.filter,a.bbox)){var d=Ar(a.geometryName,a.bbox,a.srsName);c?c=yr(c,d):c=d}b.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation",this.c);d=a.featureTypes;a=[{node:b,srsName:a.srsName,featureNS:a.featureNS?a.featureNS:this.g,featurePrefix:a.featurePrefix,geometryName:a.geometryName,filter:c,propertyNames:a.propertyNames?a.propertyNames:[]}];c=Ea({},a[a.length-1]);c.node=b;bl(c,Ps,Xk("Query"),d,a);return b};
+Cs.prototype.U=function(a,b,c,d){var e=[],f=Mk("http://www.opengis.net/wfs","Transaction");f.setAttribute("service","WFS");f.setAttribute("version","1.1.0");var g,h;d&&(g=d.gmlOptions?d.gmlOptions:{},d.handle&&f.setAttribute("handle",d.handle));f.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance","xsi:schemaLocation",this.c);a&&(h={node:f,featureNS:d.featureNS,featureType:d.featureType,featurePrefix:d.featurePrefix,srsName:d.srsName},Ea(h,g),bl(h,Ns,Xk("Insert"),a,e));b&&(h={node:f,featureNS:d.featureNS,
+featureType:d.featureType,featurePrefix:d.featurePrefix,srsName:d.srsName},Ea(h,g),bl(h,Ns,Xk("Update"),b,e));c&&bl({node:f,featureNS:d.featureNS,featureType:d.featureType,featurePrefix:d.featurePrefix,srsName:d.srsName},Ns,Xk("Delete"),c,e);d.nativeElements&&bl({node:f,featureNS:d.featureNS,featureType:d.featureType,featurePrefix:d.featurePrefix,srsName:d.srsName},Ns,Xk("Native"),d.nativeElements,e);return f};
+Cs.prototype.Pf=function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType==Node.ELEMENT_NODE)return this.Be(a);return null};Cs.prototype.Be=function(a){if(a.firstElementChild&&a.firstElementChild.firstElementChild)for(a=a.firstElementChild.firstElementChild,a=a.firstElementChild;a;a=a.nextElementSibling)if(0!==a.childNodes.length&&(1!==a.childNodes.length||3!==a.firstChild.nodeType)){var b=[{}];this.b.ye(a,b);return yc(b.pop().srsName)}return null};function Ts(a){a=a?a:{};this.defaultDataProjection=null;this.b=void 0!==a.splitCollection?a.splitCollection:!1}y(Ts,bp);function Us(a){a=a.Z();return 0===a.length?"":a[0]+" "+a[1]}function Vs(a){a=a.Z();for(var b=[],c=0,d=a.length;c<d;++c)b.push(a[c][0]+" "+a[c][1]);return b.join(",")}function Ws(a){var b=[];a=a.Vd();for(var c=0,d=a.length;c<d;++c)b.push("("+Vs(a[c])+")");return b.join(",")}function Xs(a){var b=a.X();a=(0,Ys[b])(a);b=b.toUpperCase();return 0===a.length?b+" EMPTY":b+"("+a+")"}
+var Ys={Point:Us,LineString:Vs,Polygon:Ws,MultiPoint:function(a){var b=[];a=a.je();for(var c=0,d=a.length;c<d;++c)b.push("("+Us(a[c])+")");return b.join(",")},MultiLineString:function(a){var b=[];a=a.md();for(var c=0,d=a.length;c<d;++c)b.push("("+Vs(a[c])+")");return b.join(",")},MultiPolygon:function(a){var b=[];a=a.Wd();for(var c=0,d=a.length;c<d;++c)b.push("("+Ws(a[c])+")");return b.join(",")},GeometryCollection:function(a){var b=[];a=a.ff();for(var c=0,d=a.length;c<d;++c)b.push(Xs(a[c]));return b.join(",")}};
+k=Ts.prototype;k.ud=function(a,b){var c=this.wd(a,b);if(c){var d=new Ik;d.Ua(c);return d}return null};k.Kf=function(a,b){var c=[],d=this.wd(a,b);this.b&&"GeometryCollection"==d.X()?c=d.c:c=[d];for(var e=[],f=0,g=c.length;f<g;++f)d=new Ik,d.Ua(c[f]),e.push(d);return e};k.wd=function(a,b){var c;c=new Zs(new $s(a));c.b=at(c.a);return(c=bt(c))?un(c,!1,b):null};k.He=function(a,b){var c=a.W();return c?this.Ed(c,b):""};
+k.Ci=function(a,b){if(1==a.length)return this.He(a[0],b);for(var c=[],d=0,e=a.length;d<e;++d)c.push(a[d].W());c=new Ln(c);return this.Ed(c,b)};k.Ed=function(a,b){return Xs(un(a,!0,b))};function $s(a){this.a=a;this.b=-1}
+function at(a){var b=a.a.charAt(++a.b),c={position:a.b,value:b};if("("==b)c.type=2;else if(","==b)c.type=5;else if(")"==b)c.type=3;else if("0"<=b&&"9">=b||"."==b||"-"==b){c.type=4;var d,b=a.b,e=!1,f=!1;do{if("."==d)e=!0;else if("e"==d||"E"==d)f=!0;d=a.a.charAt(++a.b)}while("0"<=d&&"9">=d||"."==d&&(void 0===e||!e)||!f&&("e"==d||"E"==d)||f&&("-"==d||"+"==d));a=parseFloat(a.a.substring(b,a.b--));c.value=a}else if("a"<=b&&"z">=b||"A"<=b&&"Z">=b){c.type=1;b=a.b;do d=a.a.charAt(++a.b);while("a"<=d&&"z">=
+d||"A"<=d&&"Z">=d);a=a.a.substring(b,a.b--).toUpperCase();c.value=a}else{if(" "==b||"\t"==b||"\r"==b||"\n"==b)return at(a);if(""===b)c.type=6;else throw Error("Unexpected character: "+b);}return c}function Zs(a){this.a=a}k=Zs.prototype;k.match=function(a){if(a=this.b.type==a)this.b=at(this.a);return a};
+function bt(a){var b=a.b;if(a.match(1)){var c=b.value;if("GEOMETRYCOLLECTION"==c){a:{if(a.match(2)){b=[];do b.push(bt(a));while(a.match(5));if(a.match(3)){a=b;break a}}else if(ct(a)){a=[];break a}throw Error(dt(a));}return new Ln(a)}var d=et[c],b=ft[c];if(!d||!b)throw Error("Invalid geometry type: "+c);a=d.call(a);return new b(a)}throw Error(dt(a));}k.Ef=function(){if(this.match(2)){var a=gt(this);if(this.match(3))return a}else if(ct(this))return null;throw Error(dt(this));};
+k.Df=function(){if(this.match(2)){var a=ht(this);if(this.match(3))return a}else if(ct(this))return[];throw Error(dt(this));};k.Ff=function(){if(this.match(2)){var a=it(this);if(this.match(3))return a}else if(ct(this))return[];throw Error(dt(this));};k.io=function(){if(this.match(2)){var a;if(2==this.b.type)for(a=[this.Ef()];this.match(5);)a.push(this.Ef());else a=ht(this);if(this.match(3))return a}else if(ct(this))return[];throw Error(dt(this));};
+k.ho=function(){if(this.match(2)){var a=it(this);if(this.match(3))return a}else if(ct(this))return[];throw Error(dt(this));};k.jo=function(){if(this.match(2)){for(var a=[this.Ff()];this.match(5);)a.push(this.Ff());if(this.match(3))return a}else if(ct(this))return[];throw Error(dt(this));};function gt(a){for(var b=[],c=0;2>c;++c){var d=a.b;if(a.match(4))b.push(d.value);else break}if(2==b.length)return b;throw Error(dt(a));}function ht(a){for(var b=[gt(a)];a.match(5);)b.push(gt(a));return b}
+function it(a){for(var b=[a.Df()];a.match(5);)b.push(a.Df());return b}function ct(a){var b=1==a.b.type&&"EMPTY"==a.b.value;b&&(a.b=at(a.a));return b}function dt(a){return"Unexpected `"+a.b.value+"` at position "+a.b.position+" in `"+a.a.a+"`"}var ft={POINT:C,LINESTRING:R,POLYGON:E,MULTIPOINT:Bn,MULTILINESTRING:S,MULTIPOLYGON:T},et={POINT:Zs.prototype.Ef,LINESTRING:Zs.prototype.Df,POLYGON:Zs.prototype.Ff,MULTIPOINT:Zs.prototype.io,MULTILINESTRING:Zs.prototype.ho,MULTIPOLYGON:Zs.prototype.jo};function jt(){this.version=void 0}y(jt,Zr);jt.prototype.a=function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType==Node.ELEMENT_NODE)return this.b(a);return null};jt.prototype.b=function(a){this.version=a.getAttribute("version").trim();return(a=O({version:this.version},kt,a,[]))?a:null};function lt(a,b){return O({},mt,a,b)}function nt(a,b){return O({},ot,a,b)}function pt(a,b){var c=lt(a,b);if(c){var d=[fo(a.getAttribute("width")),fo(a.getAttribute("height"))];c.size=d;return c}}
+function qt(a,b){return O([],rt,a,b)}
+var st=[null,"http://www.opengis.net/wms"],kt=M(st,{Service:J(function(a,b){return O({},tt,a,b)}),Capability:J(function(a,b){return O({},ut,a,b)})}),ut=M(st,{Request:J(function(a,b){return O({},vt,a,b)}),Exception:J(function(a,b){return O([],wt,a,b)}),Layer:J(function(a,b){return O({},xt,a,b)})}),tt=M(st,{Name:J(U),Title:J(U),Abstract:J(U),KeywordList:J(qt),OnlineResource:J(Yr),ContactInformation:J(function(a,b){return O({},yt,a,b)}),Fees:J(U),AccessConstraints:J(U),LayerLimit:J(eo),MaxWidth:J(eo),
+MaxHeight:J(eo)}),yt=M(st,{ContactPersonPrimary:J(function(a,b){return O({},zt,a,b)}),ContactPosition:J(U),ContactAddress:J(function(a,b){return O({},At,a,b)}),ContactVoiceTelephone:J(U),ContactFacsimileTelephone:J(U),ContactElectronicMailAddress:J(U)}),zt=M(st,{ContactPerson:J(U),ContactOrganization:J(U)}),At=M(st,{AddressType:J(U),Address:J(U),City:J(U),StateOrProvince:J(U),PostCode:J(U),Country:J(U)}),wt=M(st,{Format:Tk(U)}),xt=M(st,{Name:J(U),Title:J(U),Abstract:J(U),KeywordList:J(qt),CRS:Vk(U),
+EX_GeographicBoundingBox:J(function(a,b){var c=O({},Bt,a,b);if(c){var d=c.westBoundLongitude,e=c.southBoundLatitude,f=c.eastBoundLongitude,c=c.northBoundLatitude;return void 0===d||void 0===e||void 0===f||void 0===c?void 0:[d,e,f,c]}}),BoundingBox:Vk(function(a){var b=[co(a.getAttribute("minx")),co(a.getAttribute("miny")),co(a.getAttribute("maxx")),co(a.getAttribute("maxy"))],c=[co(a.getAttribute("resx")),co(a.getAttribute("resy"))];return{crs:a.getAttribute("CRS"),extent:b,res:c}}),Dimension:Vk(function(a){return{name:a.getAttribute("name"),
+units:a.getAttribute("units"),unitSymbol:a.getAttribute("unitSymbol"),"default":a.getAttribute("default"),multipleValues:$n(a.getAttribute("multipleValues")),nearestValue:$n(a.getAttribute("nearestValue")),current:$n(a.getAttribute("current")),values:U(a)}}),Attribution:J(function(a,b){return O({},Ct,a,b)}),AuthorityURL:Vk(function(a,b){var c=lt(a,b);if(c)return c.name=a.getAttribute("name"),c}),Identifier:Vk(U),MetadataURL:Vk(function(a,b){var c=lt(a,b);if(c)return c.type=a.getAttribute("type"),
+c}),DataURL:Vk(lt),FeatureListURL:Vk(lt),Style:Vk(function(a,b){return O({},Dt,a,b)}),MinScaleDenominator:J(bo),MaxScaleDenominator:J(bo),Layer:Vk(function(a,b){var c=b[b.length-1],d=O({},xt,a,b);if(d){var e=$n(a.getAttribute("queryable"));void 0===e&&(e=c.queryable);d.queryable=void 0!==e?e:!1;e=fo(a.getAttribute("cascaded"));void 0===e&&(e=c.cascaded);d.cascaded=e;e=$n(a.getAttribute("opaque"));void 0===e&&(e=c.opaque);d.opaque=void 0!==e?e:!1;e=$n(a.getAttribute("noSubsets"));void 0===e&&(e=c.noSubsets);
+d.noSubsets=void 0!==e?e:!1;(e=co(a.getAttribute("fixedWidth")))||(e=c.fixedWidth);d.fixedWidth=e;(e=co(a.getAttribute("fixedHeight")))||(e=c.fixedHeight);d.fixedHeight=e;["Style","CRS","AuthorityURL"].forEach(function(a){a in c&&(d[a]=(d[a]||[]).concat(c[a]))});"EX_GeographicBoundingBox BoundingBox Dimension Attribution MinScaleDenominator MaxScaleDenominator".split(" ").forEach(function(a){a in d||(d[a]=c[a])});return d}})}),Ct=M(st,{Title:J(U),OnlineResource:J(Yr),LogoURL:J(pt)}),Bt=M(st,{westBoundLongitude:J(bo),
+eastBoundLongitude:J(bo),southBoundLatitude:J(bo),northBoundLatitude:J(bo)}),vt=M(st,{GetCapabilities:J(nt),GetMap:J(nt),GetFeatureInfo:J(nt)}),ot=M(st,{Format:Vk(U),DCPType:Vk(function(a,b){return O({},Et,a,b)})}),Et=M(st,{HTTP:J(function(a,b){return O({},Ft,a,b)})}),Ft=M(st,{Get:J(lt),Post:J(lt)}),Dt=M(st,{Name:J(U),Title:J(U),Abstract:J(U),LegendURL:Vk(pt),StyleSheetURL:J(lt),StyleURL:J(lt)}),mt=M(st,{Format:J(U),OnlineResource:J(Yr)}),rt=M(st,{Keyword:Tk(U)});function Gt(a){a=a?a:{};this.g="http://mapserver.gis.umn.edu/mapserver";this.b=new ko;this.c=a.layers?a.layers:null;Un.call(this)}y(Gt,Un);
+Gt.prototype.lc=function(a,b){var c={};b&&Ea(c,sn(this,a,b));var d=[c];a.setAttribute("namespaceURI",this.g);var e=a.localName,c=[];if(0!==a.childNodes.length){if("msGMLOutput"==e)for(var f=0,g=a.childNodes.length;f<g;f++){var h=a.childNodes[f];if(h.nodeType===Node.ELEMENT_NODE){var l=d[0],m=h.localName.replace("_layer","");if(!this.c||jb(this.c,m)){m+="_feature";l.featureType=m;l.featureNS=this.g;var n={};n[m]=Tk(this.b.If,this.b);l=M([l.featureNS,null],n);h.setAttribute("namespaceURI",this.g);(h=
+O([],l,h,d,this.b))&&mb(c,h)}}}"FeatureCollection"==e&&(d=O([],this.b.b,a,[{}],this.b))&&(c=d)}return c};function Ht(){this.g=new $r}y(Ht,Zr);Ht.prototype.a=function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType==Node.ELEMENT_NODE)return this.b(a);return null};Ht.prototype.b=function(a){var b=a.getAttribute("version").trim(),c=this.g.b(a);if(!c)return null;c.version=b;return(c=O(c,It,a,[]))?c:null};function Jt(a){var b=U(a).split(" ");if(b&&2==b.length)return a=+b[0],b=+b[1],isNaN(a)||isNaN(b)?void 0:[a,b]}
+var Kt=[null,"http://www.opengis.net/wmts/1.0"],Lt=[null,"http://www.opengis.net/ows/1.1"],It=M(Kt,{Contents:J(function(a,b){return O({},Mt,a,b)})}),Mt=M(Kt,{Layer:Vk(function(a,b){return O({},Nt,a,b)}),TileMatrixSet:Vk(function(a,b){return O({},Ot,a,b)})}),Nt=M(Kt,{Style:Vk(function(a,b){var c=O({},Pt,a,b);if(c){var d="true"===a.getAttribute("isDefault");c.isDefault=d;return c}}),Format:Vk(U),TileMatrixSetLink:Vk(function(a,b){return O({},Qt,a,b)}),Dimension:Vk(function(a,b){return O({},Rt,a,b)}),
+ResourceURL:Vk(function(a){var b=a.getAttribute("format"),c=a.getAttribute("template");a=a.getAttribute("resourceType");var d={};b&&(d.format=b);c&&(d.template=c);a&&(d.resourceType=a);return d})},M(Lt,{Title:J(U),Abstract:J(U),WGS84BoundingBox:J(function(a,b){var c=O([],St,a,b);return 2!=c.length?void 0:Kb(c)}),Identifier:J(U)})),Pt=M(Kt,{LegendURL:Vk(function(a){var b={};b.format=a.getAttribute("format");b.href=Yr(a);return b})},M(Lt,{Title:J(U),Identifier:J(U)})),Qt=M(Kt,{TileMatrixSet:J(U)}),
+Rt=M(Kt,{Default:J(U),Value:Vk(U)},M(Lt,{Identifier:J(U)})),St=M(Lt,{LowerCorner:Tk(Jt),UpperCorner:Tk(Jt)}),Ot=M(Kt,{WellKnownScaleSet:J(U),TileMatrix:Vk(function(a,b){return O({},Tt,a,b)})},M(Lt,{SupportedCRS:J(U),Identifier:J(U)})),Tt=M(Kt,{TopLeftCorner:J(Jt),ScaleDenominator:J(bo),TileWidth:J(eo),TileHeight:J(eo),MatrixWidth:J(eo),MatrixHeight:J(eo)},M(Lt,{Identifier:J(U)}));function Ut(a){eb.call(this);a=a||{};this.a=null;this.c=Qc;this.f=void 0;B(this,gb("projection"),this.Nl,this);B(this,gb("tracking"),this.Ol,this);void 0!==a.projection&&this.dh(yc(a.projection));void 0!==a.trackingOptions&&this.si(a.trackingOptions);this.ge(void 0!==a.tracking?a.tracking:!1)}y(Ut,eb);k=Ut.prototype;k.ka=function(){this.ge(!1);eb.prototype.ka.call(this)};k.Nl=function(){var a=this.ah();a&&(this.c=Bc(yc("EPSG:4326"),a),this.a&&this.set("position",this.c(this.a)))};
+k.Ol=function(){if(kg){var a=this.bh();a&&void 0===this.f?this.f=pa.navigator.geolocation.watchPosition(this.qo.bind(this),this.ro.bind(this),this.Mg()):a||void 0===this.f||(pa.navigator.geolocation.clearWatch(this.f),this.f=void 0)}};
+k.qo=function(a){a=a.coords;this.set("accuracy",a.accuracy);this.set("altitude",null===a.altitude?void 0:a.altitude);this.set("altitudeAccuracy",null===a.altitudeAccuracy?void 0:a.altitudeAccuracy);this.set("heading",null===a.heading?void 0:wa(a.heading));this.a?(this.a[0]=a.longitude,this.a[1]=a.latitude):this.a=[a.longitude,a.latitude];var b=this.c(this.a);this.set("position",b);this.set("speed",null===a.speed?void 0:a.speed);a=Nd(Yi,this.a,a.accuracy);a.rc(this.c);this.set("accuracyGeometry",a);
+this.u()};k.ro=function(a){a.type="error";this.ge(!1);this.b(a)};k.Mj=function(){return this.get("accuracy")};k.Nj=function(){return this.get("accuracyGeometry")||null};k.Pj=function(){return this.get("altitude")};k.Qj=function(){return this.get("altitudeAccuracy")};k.Ll=function(){return this.get("heading")};k.Ml=function(){return this.get("position")};k.ah=function(){return this.get("projection")};k.wk=function(){return this.get("speed")};k.bh=function(){return this.get("tracking")};k.Mg=function(){return this.get("trackingOptions")};
+k.dh=function(a){this.set("projection",a)};k.ge=function(a){this.set("tracking",a)};k.si=function(a){this.set("trackingOptions",a)};function Vt(a,b,c){hd.call(this);this.Vf(a,b?b:0,c)}y(Vt,hd);k=Vt.prototype;k.clone=function(){var a=new Vt(null),b=this.B.slice();jd(a,this.f,b);a.u();return a};k.sb=function(a,b,c,d){var e=this.B;a-=e[0];var f=b-e[1];b=a*a+f*f;if(b<d){if(0===b)for(d=0;d<this.a;++d)c[d]=e[d];else for(d=this.wf()/Math.sqrt(b),c[0]=e[0]+d*a,c[1]=e[1]+d*f,d=2;d<this.a;++d)c[d]=e[d];c.length=this.a;return b}return d};k.Bc=function(a,b){var c=this.B,d=a-c[0],c=b-c[1];return d*d+c*c<=Wt(this)};
+k.rd=function(){return this.B.slice(0,this.a)};k.Od=function(a){var b=this.B,c=b[this.a]-b[0];return Wb(b[0]-c,b[1]-c,b[0]+c,b[1]+c,a)};k.wf=function(){return Math.sqrt(Wt(this))};function Wt(a){var b=a.B[a.a]-a.B[0];a=a.B[a.a+1]-a.B[1];return b*b+a*a}k.X=function(){return"Circle"};k.Ka=function(a){var b=this.H();return nc(a,b)?(b=this.rd(),a[0]<=b[0]&&a[2]>=b[0]||a[1]<=b[1]&&a[3]>=b[1]?!0:bc(a,this.sg,this)):!1};
+k.jm=function(a){var b=this.a,c=this.B[b]-this.B[0],d=a.slice();d[b]=d[0]+c;for(c=1;c<b;++c)d[b+c]=a[c];jd(this,this.f,d);this.u()};k.Vf=function(a,b,c){if(a){kd(this,c,a,0);this.B||(this.B=[]);c=this.B;a=sd(c,a);c[a++]=c[0]+b;var d;b=1;for(d=this.a;b<d;++b)c[a++]=c[b];c.length=a}else jd(this,"XY",null);this.u()};k.km=function(a){this.B[this.a]=this.B[0]+a;this.u()};function Xt(a,b,c){for(var d=[],e=a(0),f=a(1),g=b(e),h=b(f),l=[f,e],m=[h,g],n=[1,0],p={},q=1E5,r,u,x,v,D;0<--q&&0<n.length;)x=n.pop(),e=l.pop(),g=m.pop(),f=x.toString(),f in p||(d.push(g[0],g[1]),p[f]=!0),v=n.pop(),f=l.pop(),h=m.pop(),D=(x+v)/2,r=a(D),u=b(r),ua(u[0],u[1],g[0],g[1],h[0],h[1])<c?(d.push(h[0],h[1]),f=v.toString(),p[f]=!0):(n.push(v,D,D,x),m.push(h,u,u,g),l.push(f,r,r,e));return d}function Yt(a,b,c,d,e){var f=yc("EPSG:4326");return Xt(function(d){return[a,b+(c-b)*d]},Pc(f,d),e)}
+function Zt(a,b,c,d,e){var f=yc("EPSG:4326");return Xt(function(d){return[b+(c-b)*d,a]},Pc(f,d),e)};function $t(a){a=a||{};this.c=this.o=null;this.g=this.i=Infinity;this.f=this.l=-Infinity;this.A=this.U=Infinity;this.D=this.C=-Infinity;this.Ba=void 0!==a.targetSize?a.targetSize:100;this.R=void 0!==a.maxLines?a.maxLines:100;this.b=[];this.a=[];this.ya=void 0!==a.strokeStyle?a.strokeStyle:au;this.v=this.j=void 0;this.s=null;this.setMap(void 0!==a.map?a.map:null)}var au=new oj({color:"rgba(0,0,0,0.2)"}),bu=[90,45,30,20,10,5,2,1,.5,.2,.1,.05,.01,.005,.002,.001];
+function cu(a,b,c,d,e,f,g){var h=g;b=Yt(b,c,d,a.c,e);h=void 0!==a.b[h]?a.b[h]:new R(null);h.ba("XY",b);nc(h.H(),f)&&(a.b[g++]=h);return g}function du(a,b,c,d,e){var f=e;b=Zt(b,a.f,a.g,a.c,c);f=void 0!==a.a[f]?a.a[f]:new R(null);f.ba("XY",b);nc(f.H(),d)&&(a.a[e++]=f);return e}k=$t.prototype;k.Pl=function(){return this.o};k.ik=function(){return this.b};k.qk=function(){return this.a};
+k.Rg=function(a){var b=a.vectorContext,c=a.frameState,d=c.extent;a=c.viewState;var e=a.center,f=a.projection,g=a.resolution;a=c.pixelRatio;a=g*g/(4*a*a);if(!this.c||!Oc(this.c,f)){var h=yc("EPSG:4326"),l=f.H(),m=f.i,n=Sc(m,h,f),p=m[2],q=m[1],r=m[0],u=n[3],x=n[2],v=n[1],n=n[0];this.i=m[3];this.g=p;this.l=q;this.f=r;this.U=u;this.A=x;this.C=v;this.D=n;this.j=Pc(h,f);this.v=Pc(f,h);this.s=this.v(kc(l));this.c=f}f.a&&(f=f.H(),h=ic(f),c=c.focus[0],c<f[0]||c>f[2])&&(c=h*Math.ceil((f[0]-c)/h),d=[d[0]+c,
+d[1],d[2]+c,d[3]]);c=this.s[0];f=this.s[1];h=-1;m=Math.pow(this.Ba*g,2);p=[];q=[];g=0;for(l=bu.length;g<l;++g){r=bu[g]/2;p[0]=c-r;p[1]=f-r;q[0]=c+r;q[1]=f+r;this.j(p,p);this.j(q,q);r=Math.pow(q[0]-p[0],2)+Math.pow(q[1]-p[1],2);if(r<=m)break;h=bu[g]}g=h;if(-1==g)this.b.length=this.a.length=0;else{c=this.v(e);e=c[0];c=c[1];f=this.R;h=[Math.max(d[0],this.D),Math.max(d[1],this.C),Math.min(d[2],this.A),Math.min(d[3],this.U)];h=Sc(h,this.c,"EPSG:4326");m=h[3];q=h[1];e=Math.floor(e/g)*g;p=sa(e,this.f,this.g);
+l=cu(this,p,q,m,a,d,0);for(h=0;p!=this.f&&h++<f;)p=Math.max(p-g,this.f),l=cu(this,p,q,m,a,d,l);p=sa(e,this.f,this.g);for(h=0;p!=this.g&&h++<f;)p=Math.min(p+g,this.g),l=cu(this,p,q,m,a,d,l);this.b.length=l;c=Math.floor(c/g)*g;e=sa(c,this.l,this.i);l=du(this,e,a,d,0);for(h=0;e!=this.l&&h++<f;)e=Math.max(e-g,this.l),l=du(this,e,a,d,l);e=sa(c,this.l,this.i);for(h=0;e!=this.i&&h++<f;)e=Math.min(e+g,this.i),l=du(this,e,a,d,l);this.a.length=l}b.Sb(null,this.ya);a=0;for(e=this.b.length;a<e;++a)g=this.b[a],
+b.hd(g,null);a=0;for(e=this.a.length;a<e;++a)g=this.a[a],b.hd(g,null)};k.setMap=function(a){this.o&&(this.o.J("postcompose",this.Rg,this),this.o.render());a&&(a.I("postcompose",this.Rg,this),a.render());this.o=a};function eu(a,b,c,d,e,f,g){oh.call(this,a,b,c,0,d);this.j=e;this.g=new Image;null!==f&&(this.g.crossOrigin=f);this.i={};this.c=null;this.state=0;this.o=g}y(eu,oh);eu.prototype.a=function(a){if(void 0!==a){var b;a=w(a);if(a in this.i)return this.i[a];Ha(this.i)?b=this.g:b=this.g.cloneNode(!1);return this.i[a]=b}return this.g};eu.prototype.s=function(){this.state=3;this.c.forEach(Ka);this.c=null;ph(this)};
+eu.prototype.v=function(){void 0===this.resolution&&(this.resolution=jc(this.extent)/this.g.height);this.state=2;this.c.forEach(Ka);this.c=null;ph(this)};eu.prototype.load=function(){if(0==this.state||3==this.state)this.state=1,ph(this),this.c=[Pa(this.g,"error",this.s,this),Pa(this.g,"load",this.v,this)],this.o(this,this.j)};function fu(a,b,c,d,e){df.call(this,a,b);this.s=c;this.g=new Image;null!==d&&(this.g.crossOrigin=d);this.c={};this.j=null;this.v=e}y(fu,df);k=fu.prototype;k.ka=function(){1==this.state&&gu(this);this.a&&Ta(this.a);this.state=5;ef(this);df.prototype.ka.call(this)};k.$a=function(a){if(void 0!==a){var b=w(a);if(b in this.c)return this.c[b];a=Ha(this.c)?this.g:this.g.cloneNode(!1);return this.c[b]=a}return this.g};k.ib=function(){return this.s};k.Ql=function(){this.state=3;gu(this);ef(this)};
+k.Rl=function(){this.state=this.g.naturalWidth&&this.g.naturalHeight?2:4;gu(this);ef(this)};k.load=function(){if(0==this.state||3==this.state)this.state=1,ef(this),this.j=[Pa(this.g,"error",this.Ql,this),Pa(this.g,"load",this.Rl,this)],this.v(this,this.s)};function gu(a){a.j.forEach(Ka);a.j=null};function hu(a){a=a?a:{};Vh.call(this,{handleEvent:qc});this.c=a.formatConstructors?a.formatConstructors:[];this.j=a.projection?yc(a.projection):null;this.a=null;this.target=a.target?a.target:null}y(hu,Vh);function iu(a){a=a.dataTransfer.files;var b,c,d;b=0;for(c=a.length;b<c;++b){d=a.item(b);var e=new FileReader;e.addEventListener("load",this.o.bind(this,d));e.readAsText(d)}}function ju(a){a.stopPropagation();a.preventDefault();a.dataTransfer.dropEffect="copy"}
+hu.prototype.o=function(a,b){var c=b.target.result,d=this.v,e=this.j;e||(e=d.aa().l);var d=this.c,f=[],g,h;g=0;for(h=d.length;g<h;++g){var l=new d[g];var m={featureProjection:e};try{f=l.Fa(c,m)}catch(n){f=null}if(f&&0<f.length)break}this.b(new ku(lu,this,a,f,e))};hu.prototype.setMap=function(a){this.a&&(this.a.forEach(Ka),this.a=null);Vh.prototype.setMap.call(this,a);a&&(a=this.target?this.target:a.a,this.a=[B(a,"drop",iu,this),B(a,"dragenter",ju,this),B(a,"dragover",ju,this),B(a,"drop",ju,this)])};
+var lu="addfeatures";function ku(a,b,c,d,e){Wa.call(this,a,b);this.features=d;this.file=c;this.projection=e}y(ku,Wa);function mu(a){a=a?a:{};ji.call(this,{handleDownEvent:nu,handleDragEvent:ou,handleUpEvent:pu});this.s=a.condition?a.condition:fi;this.a=this.c=void 0;this.j=0;this.A=void 0!==a.duration?a.duration:400}y(mu,ji);
+function ou(a){if(hi(a)){var b=a.map,c=b.Za(),d=a.pixel;a=d[0]-c[0]/2;d=c[1]/2-d[1];c=Math.atan2(d,a);a=Math.sqrt(a*a+d*d);d=b.aa();b.render();if(void 0!==this.c){var e=c-this.c;Wh(b,d,d.La()-e)}this.c=c;void 0!==this.a&&(c=this.a*(d.$()/a),Yh(b,d,c));void 0!==this.a&&(this.j=this.a/a);this.a=a}}
+function pu(a){if(!hi(a))return!0;a=a.map;var b=a.aa();Xd(b,-1);var c=this.j-1,d=b.La(),d=b.constrainRotation(d,0);Wh(a,b,d,void 0,void 0);var d=b.$(),e=this.A,d=b.constrainResolution(d,0,c);Yh(a,b,d,void 0,e);this.j=0;return!1}function nu(a){return hi(a)&&this.s(a)?(Xd(a.map.aa(),1),this.a=this.c=void 0,!0):!1};function qu(a,b){Wa.call(this,a);this.feature=b}y(qu,Wa);
+function ru(a){ji.call(this,{handleDownEvent:su,handleEvent:tu,handleUpEvent:uu});this.za=null;this.S=!1;this.Hc=a.source?a.source:null;this.qb=a.features?a.features:null;this.Cj=a.snapTolerance?a.snapTolerance:12;this.Y=a.type;this.c=vu(this.Y);this.Sa=a.minPoints?a.minPoints:this.c===wu?3:2;this.Aa=a.maxPoints?a.maxPoints:Infinity;this.Ne=a.finishCondition?a.finishCondition:qc;var b=a.geometryFunction;if(!b)if("Circle"===this.Y)b=function(a,b){var c=b?b:new Vt([NaN,NaN]);c.Vf(a[0],Math.sqrt(Hb(a[0],
+a[1])));return c};else{var c,b=this.c;b===xu?c=C:b===yu?c=R:b===wu&&(c=E);b=function(a,b){var f=b;f?f.pa(a):f=new c(a);return f}}this.D=b;this.T=this.A=this.a=this.R=this.j=this.s=null;this.Fj=a.clickTolerance?a.clickTolerance*a.clickTolerance:36;this.qa=new G({source:new P({useSpatialIndex:!1,wrapX:a.wrapX?a.wrapX:!1}),style:a.style?a.style:zu()});this.Hb=a.geometryName;this.Bj=a.condition?a.condition:ei;this.ta=a.freehandCondition?a.freehandCondition:fi;B(this,gb("active"),this.yi,this)}y(ru,ji);
+function zu(){var a=wj();return function(b){return a[b.W().X()]}}k=ru.prototype;k.setMap=function(a){ji.prototype.setMap.call(this,a);this.yi()};function tu(a){this.c!==yu&&this.c!==wu||!this.ta(a)||(this.S=!0);var b=!this.S;this.S&&a.type===gh?(Au(this,a),b=!1):a.type===fh?b=Bu(this,a):a.type===$g&&(b=!1);return ki.call(this,a)&&b}function su(a){return this.Bj(a)?(this.za=a.pixel,!0):this.S?(this.za=a.pixel,this.s||Cu(this,a),!0):!1}
+function uu(a){this.S=!1;var b=this.za,c=a.pixel,d=b[0]-c[0],b=b[1]-c[1],c=!0;d*d+b*b<=this.Fj&&(Bu(this,a),this.s?this.c===Du?this.jd():Eu(this,a)?this.Ne(a)&&this.jd():Au(this,a):(Cu(this,a),this.c===xu&&this.jd()),c=!1);return c}
+function Bu(a,b){if(a.s){var c=b.coordinate,d=a.j.W(),e;a.c===xu?e=a.a:a.c===wu?(e=a.a[0],e=e[e.length-1],Eu(a,b)&&(c=a.s.slice())):(e=a.a,e=e[e.length-1]);e[0]=c[0];e[1]=c[1];a.D(a.a,d);a.R&&a.R.W().pa(c);d instanceof E&&a.c!==wu?(a.A||(a.A=new Ik(new R(null))),d=d.Hg(0),c=a.A.W(),c.ba(d.f,d.la())):a.T&&(c=a.A.W(),c.pa(a.T));Fu(a)}else c=b.coordinate.slice(),a.R?a.R.W().pa(c):(a.R=new Ik(new C(c)),Fu(a));return!0}
+function Eu(a,b){var c=!1;if(a.j){var d=!1,e=[a.s];a.c===yu?d=a.a.length>a.Sa:a.c===wu&&(d=a.a[0].length>a.Sa,e=[a.a[0][0],a.a[0][a.a[0].length-2]]);if(d)for(var d=b.map,f=0,g=e.length;f<g;f++){var h=e[f],l=d.Ga(h),m=b.pixel,c=m[0]-l[0],l=m[1]-l[1],m=a.S&&a.ta(b)?1:a.Cj;if(c=Math.sqrt(c*c+l*l)<=m){a.s=h;break}}}return c}
+function Cu(a,b){var c=b.coordinate;a.s=c;a.c===xu?a.a=c.slice():a.c===wu?(a.a=[[c.slice(),c.slice()]],a.T=a.a[0]):(a.a=[c.slice(),c.slice()],a.c===Du&&(a.T=a.a));a.T&&(a.A=new Ik(new R(a.T)));c=a.D(a.a);a.j=new Ik;a.Hb&&a.j.Ec(a.Hb);a.j.Ua(c);Fu(a);a.b(new qu("drawstart",a.j))}
+function Au(a,b){var c=b.coordinate,d=a.j.W(),e,f;if(a.c===yu)a.s=c.slice(),f=a.a,f.push(c.slice()),e=f.length>a.Aa,a.D(f,d);else if(a.c===wu){f=a.a[0];f.push(c.slice());if(e=f.length>a.Aa)a.s=f[0];a.D(a.a,d)}Fu(a);e&&a.jd()}k.Qo=function(){var a=this.j.W(),b,c;this.c===yu?(b=this.a,b.splice(-2,1),this.D(b,a)):this.c===wu&&(b=this.a[0],b.splice(-2,1),c=this.A.W(),c.pa(b),this.D(this.a,a));0===b.length&&(this.s=null);Fu(this)};
+k.jd=function(){var a=Gu(this),b=this.a,c=a.W();this.c===yu?(b.pop(),this.D(b,c)):this.c===wu&&(b[0].pop(),b[0].push(b[0][0]),this.D(b,c));"MultiPoint"===this.Y?a.Ua(new Bn([b])):"MultiLineString"===this.Y?a.Ua(new S([b])):"MultiPolygon"===this.Y&&a.Ua(new T([b]));this.b(new qu("drawend",a));this.qb&&this.qb.push(a);this.Hc&&this.Hc.rb(a)};function Gu(a){a.s=null;var b=a.j;b&&(a.j=null,a.R=null,a.A=null,a.qa.ha().clear(!0));return b}
+k.rm=function(a){var b=a.W();this.j=a;this.a=b.Z();a=this.a[this.a.length-1];this.s=a.slice();this.a.push(a.slice());Fu(this);this.b(new qu("drawstart",this.j))};k.Gc=rc;function Fu(a){var b=[];a.j&&b.push(a.j);a.A&&b.push(a.A);a.R&&b.push(a.R);a=a.qa.ha();a.clear(!0);a.Jc(b)}k.yi=function(){var a=this.v,b=this.f();a&&b||Gu(this);this.qa.setMap(b?a:null)};
+function vu(a){var b;"Point"===a||"MultiPoint"===a?b=xu:"LineString"===a||"MultiLineString"===a?b=yu:"Polygon"===a||"MultiPolygon"===a?b=wu:"Circle"===a&&(b=Du);return b}var xu="Point",yu="LineString",wu="Polygon",Du="Circle";function Hu(a,b,c){Wa.call(this,a);this.features=b;this.mapBrowserEvent=c}y(Hu,Wa);
+function Iu(a){ji.call(this,{handleDownEvent:Ju,handleDragEvent:Ku,handleEvent:Lu,handleUpEvent:Mu});this.Hb=a.condition?a.condition:ii;this.Sa=function(a){return ei(a)&&di(a)};this.qb=a.deleteCondition?a.deleteCondition:this.Sa;this.Aa=this.c=null;this.qa=[0,0];this.D=this.T=!1;this.a=new kl;this.R=void 0!==a.pixelTolerance?a.pixelTolerance:10;this.s=this.ta=!1;this.j=[];this.S=new G({source:new P({useSpatialIndex:!1,wrapX:!!a.wrapX}),style:a.style?a.style:Nu(),updateWhileAnimating:!0,updateWhileInteracting:!0});
+this.za={Point:this.ym,LineString:this.kh,LinearRing:this.kh,Polygon:this.zm,MultiPoint:this.wm,MultiLineString:this.vm,MultiPolygon:this.xm,GeometryCollection:this.um};this.A=a.features;this.A.forEach(this.xf,this);B(this.A,"add",this.sm,this);B(this.A,"remove",this.tm,this);this.Y=null}y(Iu,ji);k=Iu.prototype;k.xf=function(a){var b=a.W();b.X()in this.za&&this.za[b.X()].call(this,a,b);(b=this.v)&&Ou(this,this.qa,b);B(a,"change",this.jh,this)};
+function Pu(a,b){a.D||(a.D=!0,a.b(new Hu("modifystart",a.A,b)))}function Qu(a,b){Ru(a,b);a.c&&0===a.A.dc()&&(a.S.ha().nb(a.c),a.c=null);Qa(b,"change",a.jh,a)}function Ru(a,b){var c=a.a,d=[];c.forEach(function(a){b===a.feature&&d.push(a)});for(var e=d.length-1;0<=e;--e)c.remove(d[e])}k.setMap=function(a){this.S.setMap(a);ji.prototype.setMap.call(this,a)};k.sm=function(a){this.xf(a.element)};k.jh=function(a){this.s||(a=a.target,Qu(this,a),this.xf(a))};k.tm=function(a){Qu(this,a.element)};
+k.ym=function(a,b){var c=b.Z(),c={feature:a,geometry:b,na:[c,c]};this.a.Ca(b.H(),c)};k.wm=function(a,b){var c=b.Z(),d,e,f;e=0;for(f=c.length;e<f;++e)d=c[e],d={feature:a,geometry:b,depth:[e],index:e,na:[d,d]},this.a.Ca(b.H(),d)};k.kh=function(a,b){var c=b.Z(),d,e,f,g;d=0;for(e=c.length-1;d<e;++d)f=c.slice(d,d+2),g={feature:a,geometry:b,index:d,na:f},this.a.Ca(Kb(f),g)};
+k.vm=function(a,b){var c=b.Z(),d,e,f,g,h,l,m;g=0;for(h=c.length;g<h;++g)for(d=c[g],e=0,f=d.length-1;e<f;++e)l=d.slice(e,e+2),m={feature:a,geometry:b,depth:[g],index:e,na:l},this.a.Ca(Kb(l),m)};k.zm=function(a,b){var c=b.Z(),d,e,f,g,h,l,m;g=0;for(h=c.length;g<h;++g)for(d=c[g],e=0,f=d.length-1;e<f;++e)l=d.slice(e,e+2),m={feature:a,geometry:b,depth:[g],index:e,na:l},this.a.Ca(Kb(l),m)};
+k.xm=function(a,b){var c=b.Z(),d,e,f,g,h,l,m,n,p,q;l=0;for(m=c.length;l<m;++l)for(n=c[l],g=0,h=n.length;g<h;++g)for(d=n[g],e=0,f=d.length-1;e<f;++e)p=d.slice(e,e+2),q={feature:a,geometry:b,depth:[g,l],index:e,na:p},this.a.Ca(Kb(p),q)};k.um=function(a,b){var c,d=b.c;for(c=0;c<d.length;++c)this.za[d[c].X()].call(this,a,d[c])};function Su(a,b){var c=a.c;c?c.W().pa(b):(c=new Ik(new C(b)),a.c=c,a.S.ha().rb(c))}function Tu(a,b){return a.index-b.index}
+function Ju(a){if(!this.Hb(a))return!1;Ou(this,a.pixel,a.map);this.j.length=0;this.D=!1;var b=this.c;if(b){var c=[],b=b.W().Z(),d=Kb([b]),d=nl(this.a,d),e={};d.sort(Tu);for(var f=0,g=d.length;f<g;++f){var h=d[f],l=h.na,m=w(h.feature),n=h.depth;n&&(m+="-"+n.join("-"));e[m]||(e[m]=Array(2));if(Fb(l[0],b)&&!e[m][0])this.j.push([h,0]),e[m][0]=h;else if(Fb(l[1],b)&&!e[m][1]){if("LineString"!==h.geometry.X()&&"MultiLineString"!==h.geometry.X()||!e[m][0]||0!==e[m][0].index)this.j.push([h,1]),e[m][1]=h}else w(l)in
+this.Aa&&!e[m][0]&&!e[m][1]&&c.push([h,b])}c.length&&Pu(this,a);for(a=c.length-1;0<=a;--a)this.nl.apply(this,c[a])}return!!this.c}
+function Ku(a){this.T=!1;Pu(this,a);a=a.coordinate;for(var b=0,c=this.j.length;b<c;++b){for(var d=this.j[b],e=d[0],f=e.depth,g=e.geometry,h=g.Z(),l=e.na,d=d[1];a.length<g.va();)a.push(0);switch(g.X()){case "Point":h=a;l[0]=l[1]=a;break;case "MultiPoint":h[e.index]=a;l[0]=l[1]=a;break;case "LineString":h[e.index+d]=a;l[d]=a;break;case "MultiLineString":h[f[0]][e.index+d]=a;l[d]=a;break;case "Polygon":h[f[0]][e.index+d]=a;l[d]=a;break;case "MultiPolygon":h[f[1]][f[0]][e.index+d]=a,l[d]=a}e=g;this.s=
+!0;e.pa(h);this.s=!1}Su(this,a)}function Mu(a){for(var b,c=this.j.length-1;0<=c;--c)b=this.j[c][0],ll(this.a,Kb(b.na),b);this.D&&(this.b(new Hu("modifyend",this.A,a)),this.D=!1);return!1}function Lu(a){if(!(a instanceof Wg))return!0;this.Y=a;var b;Sd(a.map.aa())[1]||a.type!=fh||this.C||(this.qa=a.pixel,Ou(this,a.pixel,a.map));this.c&&this.qb(a)&&(a.type==ah&&this.T?b=!0:(this.c.W(),b=this.ai()));a.type==ah&&(this.T=!1);return ki.call(this,a)&&!b}
+function Ou(a,b,c){function d(a,b){return Ib(e,a.na)-Ib(e,b.na)}var e=c.Ma(b),f=c.Ma([b[0]-a.R,b[1]+a.R]),g=c.Ma([b[0]+a.R,b[1]-a.R]),f=Kb([f,g]),f=nl(a.a,f);if(0<f.length){f.sort(d);var g=f[0].na,h=Cb(e,g),l=c.Ga(h);if(Math.sqrt(Hb(b,l))<=a.R){b=c.Ga(g[0]);c=c.Ga(g[1]);b=Hb(l,b);c=Hb(l,c);a.ta=Math.sqrt(Math.min(b,c))<=a.R;a.ta&&(h=b>c?g[1]:g[0]);Su(a,h);c={};c[w(g)]=!0;b=1;for(l=f.length;b<l;++b)if(h=f[b].na,Fb(g[0],h[0])&&Fb(g[1],h[1])||Fb(g[0],h[1])&&Fb(g[1],h[0]))c[w(h)]=!0;else break;a.Aa=c;
+return}}a.c&&(a.S.ha().nb(a.c),a.c=null)}
+k.nl=function(a,b){for(var c=a.na,d=a.feature,e=a.geometry,f=a.depth,g=a.index,h;b.length<e.va();)b.push(0);switch(e.X()){case "MultiLineString":h=e.Z();h[f[0]].splice(g+1,0,b);break;case "Polygon":h=e.Z();h[f[0]].splice(g+1,0,b);break;case "MultiPolygon":h=e.Z();h[f[1]][f[0]].splice(g+1,0,b);break;case "LineString":h=e.Z();h.splice(g+1,0,b);break;default:return}this.s=!0;e.pa(h);this.s=!1;h=this.a;h.remove(a);Uu(this,e,g,f,1);var l={na:[c[0],b],feature:d,geometry:e,depth:f,index:g};h.Ca(Kb(l.na),
+l);this.j.push([l,1]);c={na:[b,c[1]],feature:d,geometry:e,depth:f,index:g+1};h.Ca(Kb(c.na),c);this.j.push([c,0]);this.T=!0};
+k.ai=function(){var a=!1;if(this.Y&&this.Y.type!=gh){var b=this.Y;Pu(this,b);var c=this.j,a={},d,e,f,g,h,l,m,n,p;for(g=c.length-1;0<=g;--g)f=c[g],m=f[0],n=w(m.feature),m.depth&&(n+="-"+m.depth.join("-")),n in a||(a[n]={}),0===f[1]?(a[n].right=m,a[n].index=m.index):1==f[1]&&(a[n].left=m,a[n].index=m.index+1);for(n in a){l=a[n].right;g=a[n].left;f=a[n].index;h=f-1;m=void 0!==g?g:l;0>h&&(h=0);c=m.geometry;d=e=c.Z();p=!1;switch(c.X()){case "MultiLineString":2<e[m.depth[0]].length&&(e[m.depth[0]].splice(f,
+1),p=!0);break;case "LineString":2<e.length&&(e.splice(f,1),p=!0);break;case "MultiPolygon":d=d[m.depth[1]];case "Polygon":d=d[m.depth[0]],4<d.length&&(f==d.length-1&&(f=0),d.splice(f,1),p=!0,0===f&&(d.pop(),d.push(d[0]),h=d.length-1))}p&&(d=c,this.s=!0,d.pa(e),this.s=!1,e=[],void 0!==g&&(this.a.remove(g),e.push(g.na[0])),void 0!==l&&(this.a.remove(l),e.push(l.na[1])),void 0!==g&&void 0!==l&&(g={depth:m.depth,feature:m.feature,geometry:m.geometry,index:h,na:e},this.a.Ca(Kb(g.na),g)),Uu(this,c,f,m.depth,
+-1),this.c&&(this.S.ha().nb(this.c),this.c=null))}a=!0;this.b(new Hu("modifyend",this.A,b));this.D=!1}return a};function Uu(a,b,c,d,e){ql(a.a,b.H(),function(a){a.geometry===b&&(void 0===d||void 0===a.depth||pb(a.depth,d))&&a.index>c&&(a.index+=e)})}function Nu(){var a=wj();return function(){return a.Point}};function Vu(a,b,c,d){Wa.call(this,a);this.selected=b;this.deselected=c;this.mapBrowserEvent=d}y(Vu,Wa);
+function Wu(a){Vh.call(this,{handleEvent:Xu});var b=a?a:{};this.C=b.condition?b.condition:di;this.A=b.addCondition?b.addCondition:rc;this.D=b.removeCondition?b.removeCondition:rc;this.R=b.toggleCondition?b.toggleCondition:fi;this.j=b.multi?b.multi:!1;this.o=b.filter?b.filter:qc;this.c=new G({source:new P({useSpatialIndex:!1,features:b.features,wrapX:b.wrapX}),style:b.style?b.style:Yu(),updateWhileAnimating:!0,updateWhileInteracting:!0});if(b.layers)if("function"===typeof b.layers)a=function(a){return b.layers(a)};
+else{var c=b.layers;a=function(a){return jb(c,a)}}else a=qc;this.s=a;this.a={};a=this.c.ha().c;B(a,"add",this.Am,this);B(a,"remove",this.Dm,this)}y(Wu,Vh);k=Wu.prototype;k.Bm=function(){return this.c.ha().c};k.Cm=function(a){a=w(a);return this.a[a]};
+function Xu(a){if(!this.C(a))return!0;var b=this.A(a),c=this.D(a),d=this.R(a),e=!b&&!c&&!d,f=a.map,g=this.c.ha().c,h=[],l=[];if(e)Fa(this.a),f.kd(a.pixel,function(a,b){if(this.o(a,b)){l.push(a);var c=w(a);this.a[c]=b;return!this.j}},this,this.s),0<l.length&&1==g.dc()&&g.item(0)==l[0]?l.length=0:(0!==g.dc()&&(h=Array.prototype.concat(g.a),g.clear()),g.qf(l));else{f.kd(a.pixel,function(a,e){if(this.o(a,e)){if(!b&&!d||jb(g.a,a))(c||d)&&jb(g.a,a)&&(h.push(a),f=w(a),delete this.a[f]);else{l.push(a);var f=
+w(a);this.a[f]=e}return!this.j}},this,this.s);for(e=h.length-1;0<=e;--e)g.remove(h[e]);g.qf(l)}(0<l.length||0<h.length)&&this.b(new Vu("select",l,h,a));return ci(a)}k.setMap=function(a){var b=this.v,c=this.c.ha().c;b&&c.forEach(b.wi,b);Vh.prototype.setMap.call(this,a);this.c.setMap(a);a&&c.forEach(a.ti,a)};function Yu(){var a=wj();mb(a.Polygon,a.LineString);mb(a.GeometryCollection,a.LineString);return function(b){return a[b.W().X()]}}k.Am=function(a){a=a.element;var b=this.v;b&&b.ti(a)};
+k.Dm=function(a){a=a.element;var b=this.v;b&&b.wi(a)};function Zu(a){ji.call(this,{handleEvent:$u,handleDownEvent:qc,handleUpEvent:av});a=a?a:{};this.s=a.source?a.source:null;this.qa=void 0!==a.vertex?a.vertex:!0;this.T=void 0!==a.edge?a.edge:!0;this.j=a.features?a.features:null;this.ta=[];this.D={};this.R={};this.Y={};this.A={};this.S=null;this.c=void 0!==a.pixelTolerance?a.pixelTolerance:10;this.Aa=bv.bind(this);this.a=new kl;this.za={Point:this.Jm,LineString:this.nh,LinearRing:this.nh,Polygon:this.Km,MultiPoint:this.Hm,MultiLineString:this.Gm,MultiPolygon:this.Im,
+GeometryCollection:this.Fm}}y(Zu,ji);k=Zu.prototype;k.rb=function(a,b){var c=void 0!==b?b:!0,d=w(a),e=a.W();if(e){var f=this.za[e.X()];f&&(this.Y[d]=e.H(Lb()),f.call(this,a,e),c&&(this.R[d]=B(e,"change",this.Kk.bind(this,a),this)))}c&&(this.D[d]=B(a,gb(a.a),this.Em,this))};k.Jj=function(a){this.rb(a)};k.Kj=function(a){this.nb(a)};k.lh=function(a){var b;a instanceof vl?b=a.feature:a instanceof ke&&(b=a.element);this.rb(b)};
+k.mh=function(a){var b;a instanceof vl?b=a.feature:a instanceof ke&&(b=a.element);this.nb(b)};k.Em=function(a){a=a.target;this.nb(a,!0);this.rb(a,!0)};k.Kk=function(a){if(this.C){var b=w(a);b in this.A||(this.A[b]=a)}else this.xi(a)};k.nb=function(a,b){var c=void 0!==b?b:!0,d=w(a),e=this.Y[d];if(e){var f=this.a,g=[];ql(f,e,function(b){a===b.feature&&g.push(b)});for(e=g.length-1;0<=e;--e)f.remove(g[e]);c&&(cb(this.R[d]),delete this.R[d])}c&&(cb(this.D[d]),delete this.D[d])};
+k.setMap=function(a){var b=this.v,c=this.ta,d;this.j?d=this.j:this.s&&(d=this.s.oe());b&&(c.forEach(cb),c.length=0,d.forEach(this.Kj,this));ji.prototype.setMap.call(this,a);a&&(this.j?c.push(B(this.j,"add",this.lh,this),B(this.j,"remove",this.mh,this)):this.s&&c.push(B(this.s,"addfeature",this.lh,this),B(this.s,"removefeature",this.mh,this)),d.forEach(this.Jj,this))};k.Gc=rc;k.xi=function(a){this.nb(a,!1);this.rb(a,!1)};
+k.Fm=function(a,b){var c,d=b.c;for(c=0;c<d.length;++c)this.za[d[c].X()].call(this,a,d[c])};k.nh=function(a,b){var c=b.Z(),d,e,f,g;d=0;for(e=c.length-1;d<e;++d)f=c.slice(d,d+2),g={feature:a,na:f},this.a.Ca(Kb(f),g)};k.Gm=function(a,b){var c=b.Z(),d,e,f,g,h,l,m;g=0;for(h=c.length;g<h;++g)for(d=c[g],e=0,f=d.length-1;e<f;++e)l=d.slice(e,e+2),m={feature:a,na:l},this.a.Ca(Kb(l),m)};k.Hm=function(a,b){var c=b.Z(),d,e,f;e=0;for(f=c.length;e<f;++e)d=c[e],d={feature:a,na:[d,d]},this.a.Ca(b.H(),d)};
+k.Im=function(a,b){var c=b.Z(),d,e,f,g,h,l,m,n,p,q;l=0;for(m=c.length;l<m;++l)for(n=c[l],g=0,h=n.length;g<h;++g)for(d=n[g],e=0,f=d.length-1;e<f;++e)p=d.slice(e,e+2),q={feature:a,na:p},this.a.Ca(Kb(p),q)};k.Jm=function(a,b){var c=b.Z(),c={feature:a,na:[c,c]};this.a.Ca(b.H(),c)};k.Km=function(a,b){var c=b.Z(),d,e,f,g,h,l,m;g=0;for(h=c.length;g<h;++g)for(d=c[g],e=0,f=d.length-1;e<f;++e)l=d.slice(e,e+2),m={feature:a,na:l},this.a.Ca(Kb(l),m)};
+function $u(a){var b,c,d=a.pixel,e=a.coordinate;b=a.map;var f=b.Ma([d[0]-this.c,d[1]+this.c]);c=b.Ma([d[0]+this.c,d[1]-this.c]);var f=Kb([f,c]),g=nl(this.a,f),h,f=!1,l=null;c=null;if(0<g.length){this.S=e;g.sort(this.Aa);g=g[0].na;if(this.qa&&!this.T){if(e=b.Ga(g[0]),h=b.Ga(g[1]),e=Hb(d,e),d=Hb(d,h),h=Math.sqrt(Math.min(e,d)),h=h<=this.c)f=!0,l=e>d?g[1]:g[0],c=b.Ga(l)}else this.T&&(l=Cb(e,g),c=b.Ga(l),Math.sqrt(Hb(d,c))<=this.c&&(f=!0,this.qa&&(e=b.Ga(g[0]),h=b.Ga(g[1]),e=Hb(c,e),d=Hb(c,h),h=Math.sqrt(Math.min(e,
+d)),h=h<=this.c)))&&(l=e>d?g[1]:g[0],c=b.Ga(l));f&&(c=[Math.round(c[0]),Math.round(c[1])])}b=l;f&&(a.coordinate=b.slice(0,2),a.pixel=c);return ki.call(this,a)}function av(){var a=Ga(this.A);a.length&&(a.forEach(this.xi,this),this.A={});return!1}function bv(a,b){return Ib(this.S,a.na)-Ib(this.S,b.na)};function cv(a,b,c){Wa.call(this,a);this.features=b;this.coordinate=c}y(cv,Wa);function dv(a){ji.call(this,{handleDownEvent:ev,handleDragEvent:fv,handleMoveEvent:gv,handleUpEvent:hv});this.s=void 0;this.a=null;this.c=void 0!==a.features?a.features:null;var b;if(a.layers)if("function"===typeof a.layers)b=function(b){return a.layers(b)};else{var c=a.layers;b=function(a){return jb(c,a)}}else b=qc;this.A=b;this.j=null}y(dv,ji);
+function ev(a){this.j=iv(this,a.pixel,a.map);return!this.a&&this.j?(this.a=a.coordinate,gv.call(this,a),this.b(new cv("translatestart",this.c,a.coordinate)),!0):!1}function hv(a){return this.a?(this.a=null,gv.call(this,a),this.b(new cv("translateend",this.c,a.coordinate)),!0):!1}
+function fv(a){if(this.a){a=a.coordinate;var b=a[0]-this.a[0],c=a[1]-this.a[1];if(this.c)this.c.forEach(function(a){var d=a.W();d.Sc(b,c);a.Ua(d)});else if(this.j){var d=this.j.W();d.Sc(b,c);this.j.Ua(d)}this.a=a;this.b(new cv("translating",this.c,a))}}
+function gv(a){var b=a.map.yc();if(a=a.map.kd(a.pixel,function(a){return a})){var c=!1;this.c&&jb(this.c.a,a)&&(c=!0);this.s=b.style.cursor;b.style.cursor=this.a?"-webkit-grabbing":c?"-webkit-grab":"pointer";b.style.cursor=this.a?c?"grab":"pointer":"grabbing"}else b.style.cursor=void 0!==this.s?this.s:"",this.s=void 0}function iv(a,b,c){var d=null;b=c.kd(b,function(a){return a},a,a.A);a.c&&jb(a.c.a,b)&&(d=b);return d};function V(a){a=a?a:{};var b=Ea({},a);delete b.gradient;delete b.radius;delete b.blur;delete b.shadow;delete b.weight;G.call(this,b);this.f=null;this.ia=void 0!==a.shadow?a.shadow:250;this.Y=void 0;this.c=null;B(this,gb("gradient"),this.Lk,this);this.ii(a.gradient?a.gradient:jv);this.di(void 0!==a.blur?a.blur:15);this.qh(void 0!==a.radius?a.radius:8);B(this,gb("blur"),this.lf,this);B(this,gb("radius"),this.lf,this);this.lf();var c=a.weight?a.weight:"weight",d;"string"===typeof c?d=function(a){return a.get(c)}:
+d=c;this.l(function(a){a=d(a);a=void 0!==a?sa(a,0,1):1;var b=255*a|0,c=this.c[b];c||(c=[new rj({image:new Dh({opacity:a,src:this.Y})})],this.c[b]=c);return c}.bind(this));this.set("renderOrder",null);B(this,"render",this.dl,this)}y(V,G);var jv=["#00f","#0ff","#0f0","#ff0","#f00"];k=V.prototype;k.zg=function(){return this.get("blur")};k.Gg=function(){return this.get("gradient")};k.ph=function(){return this.get("radius")};
+k.Lk=function(){for(var a=this.Gg(),b=Oe(1,256),c=b.createLinearGradient(0,0,1,256),d=1/(a.length-1),e=0,f=a.length;e<f;++e)c.addColorStop(e*d,a[e]);b.fillStyle=c;b.fillRect(0,0,1,256);this.f=b.getImageData(0,0,1,256).data};k.lf=function(){var a=this.ph(),b=this.zg(),c=a+b+1,d=2*c,d=Oe(d,d);d.shadowOffsetX=d.shadowOffsetY=this.ia;d.shadowBlur=b;d.shadowColor="#000";d.beginPath();b=c-this.ia;d.arc(b,b,a,0,2*Math.PI,!0);d.fill();this.Y=d.canvas.toDataURL();this.c=Array(256);this.u()};
+k.dl=function(a){a=a.context;var b=a.canvas,b=a.getImageData(0,0,b.width,b.height),c=b.data,d,e,f;d=0;for(e=c.length;d<e;d+=4)if(f=4*c[d+3])c[d]=this.f[f],c[d+1]=this.f[f+1],c[d+2]=this.f[f+2];a.putImageData(b,0,0)};k.di=function(a){this.set("blur",a)};k.ii=function(a){this.set("gradient",a)};k.qh=function(a){this.set("radius",a)};function kv(a,b,c,d){function e(){delete pa[g];f.parentNode.removeChild(f)}var f=pa.document.createElement("script"),g="olc_"+w(b);f.async=!0;f.src=a+(-1==a.indexOf("?")?"?":"&")+(d||"callback")+"="+g;var h=pa.setTimeout(function(){e();c&&c()},1E4);pa[g]=function(a){pa.clearTimeout(h);e();b(a)};pa.document.getElementsByTagName("head")[0].appendChild(f)};function lv(a,b,c,d,e,f,g,h,l,m,n){df.call(this,e,0);this.R=void 0!==n?n:!1;this.D=g;this.C=h;this.l=null;this.c={};this.j=b;this.v=d;this.U=f?f:e;this.g=[];this.Wc=null;this.s=0;f=d.Ea(this.U);h=this.v.H();e=this.j.H();f=h?mc(f,h):f;if(0===gc(f))this.state=4;else if((h=a.H())&&(e?e=mc(e,h):e=h),d=d.$(this.U[0]),d=tk(a,c,kc(f),d),!isFinite(d)||0>=d)this.state=4;else if(this.A=new wk(a,c,f,e,d*(void 0!==m?m:.5)),0===this.A.f.length)this.state=4;else if(this.s=b.Lb(d),c=yk(this.A),e&&(a.a?(c[1]=sa(c[1],
+e[1],e[3]),c[3]=sa(c[3],e[1],e[3])):c=mc(c,e)),gc(c))if(a=pf(b,c,this.s),100>(a.ea-a.ca+1)*(a.ga-a.fa+1)){for(b=a.ca;b<=a.ea;b++)for(c=a.fa;c<=a.ga;c++)(m=l(this.s,b,c,g))&&this.g.push(m);0===this.g.length&&(this.state=4)}else this.state=3;else this.state=4}y(lv,df);lv.prototype.ka=function(){1==this.state&&(this.Wc.forEach(Ka),this.Wc=null);df.prototype.ka.call(this)};
+lv.prototype.$a=function(a){if(void 0!==a){var b=w(a);if(b in this.c)return this.c[b];a=Ha(this.c)?this.l:this.l.cloneNode(!1);return this.c[b]=a}return this.l};
+lv.prototype.zd=function(){var a=[];this.g.forEach(function(b){b&&2==b.V()&&a.push({extent:this.j.Ea(b.ma),image:b.$a()})},this);this.g.length=0;if(0===a.length)this.state=3;else{var b=this.U[0],c=this.v.Ja(b),d=ea(c)?c:c[0],c=ea(c)?c:c[1],b=this.v.$(b),e=this.j.$(this.s),f=this.v.Ea(this.U);this.l=vk(d,c,this.D,e,this.j.H(),b,f,this.A,a,this.C,this.R);this.state=2}ef(this)};
+lv.prototype.load=function(){if(0==this.state){this.state=1;ef(this);var a=0;this.Wc=[];this.g.forEach(function(b){var c=b.V();if(0==c||1==c){a++;var d;d=B(b,"change",function(){var c=b.V();if(2==c||3==c||4==c)Ka(d),a--,0===a&&(this.Wc.forEach(Ka),this.Wc=null,this.zd())},this);this.Wc.push(d)}},this);this.g.forEach(function(a){0==a.V()&&a.load()});0===a&&pa.setTimeout(this.zd.bind(this),0)}};function W(a){Jl.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,extent:a.extent,logo:a.logo,opaque:a.opaque,projection:a.projection,state:a.state,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction?a.tileLoadFunction:mv,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:a.tileUrlFunction,url:a.url,urls:a.urls,wrapX:a.wrapX});this.crossOrigin=void 0!==a.crossOrigin?a.crossOrigin:null;this.tileClass=void 0!==a.tileClass?a.tileClass:fu;this.i={};this.s={};this.qa=a.reprojectionErrorThreshold;
+this.C=!1}y(W,Jl);k=W.prototype;k.Ah=function(){if(cf(this.a))return!0;for(var a in this.i)if(cf(this.i[a]))return!0;return!1};k.Lc=function(a,b){var c=this.pd(a);this.a.Lc(this.a==c?b:{});for(var d in this.i){var e=this.i[d];e.Lc(e==c?b:{})}};k.Ud=function(a){return this.f&&a&&!Oc(this.f,a)?0:this.gf()};k.gf=function(){return 0};k.jf=function(a){return this.f&&a&&!Oc(this.f,a)?!1:Jl.prototype.jf.call(this,a)};
+k.eb=function(a){var b=this.f;return!this.tileGrid||b&&!Oc(b,a)?(b=w(a).toString(),b in this.s||(this.s[b]=vf(a)),this.s[b]):this.tileGrid};k.pd=function(a){var b=this.f;if(!b||Oc(b,a))return this.a;a=w(a).toString();a in this.i||(this.i[a]=new bf);return this.i[a]};function nv(a,b,c,d,e,f,g){b=[b,c,d];e=(c=Cf(a,b,f))?a.tileUrlFunction(c,e,f):void 0;e=new a.tileClass(b,void 0!==e?0:4,void 0!==e?e:"",a.crossOrigin,a.tileLoadFunction);e.key=g;B(e,"change",a.Bh,a);return e}
+k.ac=function(a,b,c,d,e){if(this.f&&e&&!Oc(this.f,e)){var f=this.pd(e);b=[a,b,c];a=this.Eb.apply(this,b);if(Ze(f,a))return f.get(a);var g=this.f;c=this.eb(g);var h=this.eb(e),l=Cf(this,b,e);d=new lv(g,c,e,h,b,l,this.bc(d),this.gf(),function(a,b,c,d){return ov(this,a,b,c,d,g)}.bind(this),this.qa,this.C);f.set(a,d);return d}return ov(this,a,b,c,d,e)};
+function ov(a,b,c,d,e,f){var g,h=a.Eb(b,c,d),l=a.cc;if(Ze(a.a,h)){if(g=a.a.get(h),g.key!=l){var m=g;g.a&&g.a.key==l?(g=g.a,2==m.V()&&(g.a=m)):(g=nv(a,b,c,d,e,f,l),2==m.V()?g.a=m:m.a&&2==m.a.V()&&(g.a=m.a,m.a=null));g.a&&(g.a.a=null);a.a.replace(h,g)}}else g=nv(a,b,c,d,e,f,l),a.a.set(h,g);return g}k.zb=function(a){if(this.C!=a){this.C=a;for(var b in this.i)this.i[b].clear();this.u()}};k.Ab=function(a,b){var c=yc(a);c&&(c=w(c).toString(),c in this.s||(this.s[c]=b))};function mv(a,b){a.$a().src=b};function pv(a){W.call(this,{cacheSize:a.cacheSize,crossOrigin:"anonymous",opaque:!0,projection:yc("EPSG:3857"),reprojectionErrorThreshold:a.reprojectionErrorThreshold,state:"loading",tileLoadFunction:a.tileLoadFunction,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.j=void 0!==a.culture?a.culture:"en-us";this.c=void 0!==a.maxZoom?a.maxZoom:-1;kv("https://dev.virtualearth.net/REST/v1/Imagery/Metadata/"+a.imagerySet+"?uriScheme=https&include=ImageryProviders&key="+a.key,this.v.bind(this),void 0,"jsonp")}
+y(pv,W);var qv=new je({html:'<a class="ol-attribution-bing-tos" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a>'});
+pv.prototype.v=function(a){if(200!=a.statusCode||"OK"!=a.statusDescription||"ValidCredentials"!=a.authenticationResultCode||1!=a.resourceSets.length||1!=a.resourceSets[0].resources.length)lf(this,"error");else{var b=a.brandLogoUri;-1==b.indexOf("https")&&(b=b.replace("http","https"));var c=a.resourceSets[0].resources[0],d=-1==this.c?c.zoomMax:this.c;a=wf(this.f);var e=yf({extent:a,minZoom:c.zoomMin,maxZoom:d,tileSize:c.imageWidth==c.imageHeight?c.imageWidth:[c.imageWidth,c.imageHeight]});this.tileGrid=
+e;var f=this.j;this.tileUrlFunction=Gl(c.imageUrlSubdomains.map(function(a){var b=[0,0,0],d=c.imageUrl.replace("{subdomain}",a).replace("{culture}",f);return function(a){if(a)return $e(a[0],a[1],-a[2]-1,b),d.replace("{quadkey}",af(b))}}));if(c.imageryProviders){var g=Bc(yc("EPSG:4326"),this.f);a=c.imageryProviders.map(function(a){var b=a.attribution,c={};a.coverageAreas.forEach(function(a){var b=a.zoomMin,f=Math.min(a.zoomMax,d);a=a.bbox;a=pc([a[1],a[0],a[3],a[2]],g);var h,l;for(h=b;h<=f;++h)l=h.toString(),
+b=pf(e,a,h),l in c?c[l].push(b):c[l]=[b]});return new je({html:b,tileRanges:c})});a.push(qv);this.oa(a)}this.R=b;lf(this,"ready")}};function rv(a){a=a||{};var b=void 0!==a.projection?a.projection:"EPSG:3857",c=void 0!==a.tileGrid?a.tileGrid:yf({extent:wf(b),maxZoom:a.maxZoom,minZoom:a.minZoom,tileSize:a.tileSize});W.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,opaque:a.opaque,projection:b,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:c,tileLoadFunction:a.tileLoadFunction,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:a.tileUrlFunction,url:a.url,urls:a.urls,
+wrapX:void 0!==a.wrapX?a.wrapX:!0})}y(rv,W);function sv(a){this.v=a.account;this.A=a.map||"";this.c=a.config||{};this.j={};rv.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,maxZoom:void 0!==a.maxZoom?a.maxZoom:18,minZoom:a.minZoom,projection:a.projection,state:"loading",wrapX:a.wrapX});tv(this)}y(sv,rv);k=sv.prototype;k.Tj=function(){return this.c};k.up=function(a){Ea(this.c,a);tv(this)};k.$o=function(a){this.c=a||{};tv(this)};
+function tv(a){var b=JSON.stringify(a.c);if(a.j[b])uv(a,a.j[b]);else{var c="https://"+a.v+".cartodb.com/api/v1/map";a.A&&(c+="/named/"+a.A);var d=new XMLHttpRequest;d.addEventListener("load",a.Nk.bind(a,b));d.addEventListener("error",a.Mk.bind(a));d.open("POST",c);d.setRequestHeader("Content-type","application/json");d.send(JSON.stringify(a.c))}}
+k.Nk=function(a,b){var c=b.target;if(200<=c.status&&300>c.status){var d;try{d=JSON.parse(c.responseText)}catch(e){lf(this,"error");return}uv(this,d);this.j[a]=d;lf(this,"ready")}else lf(this,"error")};k.Mk=function(){lf(this,"error")};function uv(a,b){a.Va("https://"+b.cdn_url.https+"/"+a.v+"/api/v1/map/"+b.layergroupid+"/{z}/{x}/{y}.png")};function Y(a){P.call(this,{attributions:a.attributions,extent:a.extent,logo:a.logo,projection:a.projection,wrapX:a.wrapX});this.C=void 0;this.ta=void 0!==a.distance?a.distance:20;this.A=[];this.ia=a.geometryFunction||function(a){return a.W()};this.v=a.source;this.v.I("change",Y.prototype.Sa,this)}y(Y,P);Y.prototype.Aa=function(){return this.v};Y.prototype.Pc=function(a,b,c){this.v.Pc(a,b,c);b!==this.C&&(this.clear(),this.C=b,vv(this),this.Jc(this.A))};
+Y.prototype.Sa=function(){this.clear();vv(this);this.Jc(this.A);this.u()};function vv(a){if(void 0!==a.C){a.A.length=0;for(var b=Lb(),c=a.ta*a.C,d=a.v.oe(),e={},f=0,g=d.length;f<g;f++){var h=d[f];w(h).toString()in e||!(h=a.ia(h))||(h=h.Z(),Xb(h,b),Ob(b,c,b),h=a.v.ef(b),h=h.filter(function(a){a=w(a).toString();return a in e?!1:e[a]=!0}),a.A.push(wv(a,h)))}}}
+function wv(a,b){for(var c=[0,0],d=b.length-1;0<=d;--d){var e=a.ia(b[d]);e?Bb(c,e.Z()):b.splice(d,1)}d=1/b.length;c[0]*=d;c[1]*=d;c=new Ik(new C(c));c.set("features",b);return c};function xv(a,b){var c=Object.keys(b).map(function(a){return a+"="+encodeURIComponent(b[a])}).join("&");a=a.replace(/[?&]$/,"");a=-1===a.indexOf("?")?a+"?":a+"&";return a+c};function yv(a){a=a||{};Ak.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions});this.Y=void 0!==a.crossOrigin?a.crossOrigin:null;this.i=a.url;this.j=void 0!==a.imageLoadFunction?a.imageLoadFunction:Gk;this.v=a.params||{};this.c=null;this.s=[0,0];this.T=0;this.S=void 0!==a.ratio?a.ratio:1.5}y(yv,Ak);k=yv.prototype;k.Sm=function(){return this.v};
+k.Mc=function(a,b,c,d){if(void 0===this.i)return null;b=Bk(this,b);var e=this.c;if(e&&this.T==this.g&&e.$()==b&&e.f==c&&Ub(e.H(),a))return e;e={F:"image",FORMAT:"PNG32",TRANSPARENT:!0};Ea(e,this.v);a=a.slice();var f=(a[0]+a[2])/2,g=(a[1]+a[3])/2;if(1!=this.S){var h=this.S*ic(a)/2,l=this.S*jc(a)/2;a[0]=f-h;a[1]=g-l;a[2]=f+h;a[3]=g+l}var h=b/c,l=Math.ceil(ic(a)/h),m=Math.ceil(jc(a)/h);a[0]=f-h*l/2;a[2]=f+h*l/2;a[1]=g-h*m/2;a[3]=g+h*m/2;this.s[0]=l;this.s[1]=m;f=a;g=this.s;d=d.cb.split(":").pop();e.SIZE=
+g[0]+","+g[1];e.BBOX=f.join(",");e.BBOXSR=d;e.IMAGESR=d;e.DPI=90*c;d=this.i.replace(/MapServer\/?$/,"MapServer/export").replace(/ImageServer\/?$/,"ImageServer/exportImage");e=xv(d,e);this.c=new eu(a,b,c,this.l,e,this.Y,this.j);this.T=this.g;B(this.c,"change",this.o,this);return this.c};k.Rm=function(){return this.j};k.Tm=function(){return this.i};k.Um=function(a){this.c=null;this.j=a;this.u()};k.Vm=function(a){a!=this.i&&(this.i=a,this.c=null,this.u())};k.Wm=function(a){Ea(this.v,a);this.c=null;this.u()};function zv(a){Ak.call(this,{projection:a.projection,resolutions:a.resolutions});this.Y=void 0!==a.crossOrigin?a.crossOrigin:null;this.s=void 0!==a.displayDpi?a.displayDpi:96;this.j=a.params||{};this.T=a.url;this.c=void 0!==a.imageLoadFunction?a.imageLoadFunction:Gk;this.ia=void 0!==a.hidpi?a.hidpi:!0;this.ta=void 0!==a.metersPerUnit?a.metersPerUnit:1;this.v=void 0!==a.ratio?a.ratio:1;this.Aa=void 0!==a.useOverlay?a.useOverlay:!1;this.i=null;this.S=0}y(zv,Ak);k=zv.prototype;k.Ym=function(){return this.j};
+k.Mc=function(a,b,c){b=Bk(this,b);c=this.ia?c:1;var d=this.i;if(d&&this.S==this.g&&d.$()==b&&d.f==c&&Ub(d.H(),a))return d;1!=this.v&&(a=a.slice(),oc(a,this.v));var e=[ic(a)/b*c,jc(a)/b*c];if(void 0!==this.T){var d=this.T,f=kc(a),g=this.ta,h=ic(a),l=jc(a),m=e[0],n=e[1],p=.0254/this.s,e={OPERATION:this.Aa?"GETDYNAMICMAPOVERLAYIMAGE":"GETMAPIMAGE",VERSION:"2.0.0",LOCALE:"en",CLIENTAGENT:"ol.source.ImageMapGuide source",CLIP:"1",SETDISPLAYDPI:this.s,SETDISPLAYWIDTH:Math.round(e[0]),SETDISPLAYHEIGHT:Math.round(e[1]),
+SETVIEWSCALE:n*h>m*l?h*g/(m*p):l*g/(n*p),SETVIEWCENTERX:f[0],SETVIEWCENTERY:f[1]};Ea(e,this.j);d=xv(d,e);d=new eu(a,b,c,this.l,d,this.Y,this.c);B(d,"change",this.o,this)}else d=null;this.i=d;this.S=this.g;return d};k.Xm=function(){return this.c};k.$m=function(a){Ea(this.j,a);this.u()};k.Zm=function(a){this.i=null;this.c=a;this.u()};function Av(a){var b=a.imageExtent,c=void 0!==a.crossOrigin?a.crossOrigin:null,d=void 0!==a.imageLoadFunction?a.imageLoadFunction:Gk;Ak.call(this,{attributions:a.attributions,logo:a.logo,projection:yc(a.projection)});this.c=new eu(b,void 0,1,this.l,a.url,c,d);this.i=a.imageSize?a.imageSize:null;B(this.c,"change",this.o,this)}y(Av,Ak);Av.prototype.Mc=function(a){return nc(a,this.c.H())?this.c:null};
+Av.prototype.o=function(a){if(2==this.c.V()){var b=this.c.H(),c=this.c.a(),d,e;this.i?(d=this.i[0],e=this.i[1]):(d=c.width,e=c.height);b=Math.ceil(ic(b)/(jc(b)/e));if(b!=d){var b=Oe(b,e),f=b.canvas;b.drawImage(c,0,0,d,e,0,0,f.width,f.height);this.c.g=f}}Ak.prototype.o.call(this,a)};function Bv(a){a=a||{};Ak.call(this,{attributions:a.attributions,logo:a.logo,projection:a.projection,resolutions:a.resolutions});this.ta=void 0!==a.crossOrigin?a.crossOrigin:null;this.j=a.url;this.S=void 0!==a.imageLoadFunction?a.imageLoadFunction:Gk;this.i=a.params||{};this.v=!0;Cv(this);this.ia=a.serverType;this.Aa=void 0!==a.hidpi?a.hidpi:!0;this.c=null;this.T=[0,0];this.Y=0;this.s=void 0!==a.ratio?a.ratio:1.5}y(Bv,Ak);var Dv=[101,101];k=Bv.prototype;
+k.fn=function(a,b,c,d){if(void 0!==this.j){var e=lc(a,b,0,Dv),f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.i.LAYERS};Ea(f,this.i,d);d=Math.floor((e[3]-a[1])/b);f[this.v?"I":"X"]=Math.floor((a[0]-e[0])/b);f[this.v?"J":"Y"]=d;return Ev(this,e,Dv,1,yc(c),f)}};k.hn=function(){return this.i};
+k.Mc=function(a,b,c,d){if(void 0===this.j)return null;b=Bk(this,b);1==c||this.Aa&&void 0!==this.ia||(c=1);a=a.slice();var e=(a[0]+a[2])/2,f=(a[1]+a[3])/2,g=b/c,h=ic(a)/g,g=jc(a)/g,l=this.c;if(l&&this.Y==this.g&&l.$()==b&&l.f==c&&Ub(l.H(),a))return l;if(1!=this.s){var l=this.s*ic(a)/2,m=this.s*jc(a)/2;a[0]=e-l;a[1]=f-m;a[2]=e+l;a[3]=f+m}e={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};Ea(e,this.i);this.T[0]=Math.ceil(h*this.s);this.T[1]=Math.ceil(g*this.s);d=Ev(this,
+a,this.T,c,d,e);this.c=new eu(a,b,c,this.l,d,this.ta,this.S);this.Y=this.g;B(this.c,"change",this.o,this);return this.c};k.gn=function(){return this.S};
+function Ev(a,b,c,d,e,f){f[a.v?"CRS":"SRS"]=e.cb;"STYLES"in a.i||(f.STYLES="");if(1!=d)switch(a.ia){case "geoserver":d=90*d+.5|0;f.FORMAT_OPTIONS="FORMAT_OPTIONS"in f?f.FORMAT_OPTIONS+(";dpi:"+d):"dpi:"+d;break;case "mapserver":f.MAP_RESOLUTION=90*d;break;case "carmentaserver":case "qgis":f.DPI=90*d}f.WIDTH=c[0];f.HEIGHT=c[1];c=e.b;var g;a.v&&"ne"==c.substr(0,2)?g=[b[1],b[0],b[3],b[2]]:g=b;f.BBOX=g.join(",");return xv(a.j,f)}k.jn=function(){return this.j};k.kn=function(a){this.c=null;this.S=a;this.u()};
+k.ln=function(a){a!=this.j&&(this.j=a,this.c=null,this.u())};k.mn=function(a){Ea(this.i,a);Cv(this);this.c=null;this.u()};function Cv(a){a.v=0<=Ab(a.i.VERSION||"1.3.0")};function Fv(a){a=a||{};var b;void 0!==a.attributions?b=a.attributions:b=[Gv];rv.call(this,{attributions:b,cacheSize:a.cacheSize,crossOrigin:void 0!==a.crossOrigin?a.crossOrigin:"anonymous",opaque:void 0!==a.opaque?a.opaque:!0,maxZoom:void 0!==a.maxZoom?a.maxZoom:19,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileLoadFunction:a.tileLoadFunction,url:void 0!==a.url?a.url:"https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png",wrapX:a.wrapX})}y(Fv,rv);var Gv=new je({html:'&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors.'});(function(){var a={},b={ja:a};(function(c){if("object"===typeof a&&"undefined"!==typeof b)b.ja=c();else{var d;"undefined"!==typeof window?d=window:"undefined"!==typeof global?d=global:"undefined"!==typeof self?d=self:d=this;d.Sp=c()}})(function(){return function d(a,b,g){function h(m,p){if(!b[m]){if(!a[m]){var q="function"==typeof require&&require;if(!p&&q)return q(m,!0);if(l)return l(m,!0);q=Error("Cannot find module '"+m+"'");throw q.code="MODULE_NOT_FOUND",q;}q=b[m]={ja:{}};a[m][0].call(q.ja,function(b){var d=
+a[m][1][b];return h(d?d:b)},q,q.ja,d,a,b,g)}return b[m].ja}for(var l="function"==typeof require&&require,m=0;m<g.length;m++)h(g[m]);return h}({1:[function(a,b,f){a=a("./processor");f.$i=a},{"./processor":2}],2:[function(a,b){function f(a){var b=!0;try{new ImageData(10,10)}catch(d){b=!1}return function(d){var e=d.buffers,f=d.meta,g=d.width,h=d.height,l=e.length,m=e[0].byteLength;if(d.imageOps){m=Array(l);for(d=0;d<l;++d){var z=m,F=d,N;N=new Uint8ClampedArray(e[d]);var K=g,X=h;N=b?new ImageData(N,K,
+X):{data:N,width:K,height:X};z[F]=N}g=a(m,f).data}else{g=new Uint8ClampedArray(m);h=Array(l);z=Array(l);for(d=0;d<l;++d)h[d]=new Uint8ClampedArray(e[d]),z[d]=[0,0,0,0];for(e=0;e<m;e+=4){for(d=0;d<l;++d)F=h[d],z[d][0]=F[e],z[d][1]=F[e+1],z[d][2]=F[e+2],z[d][3]=F[e+3];d=a(z,f);g[e]=d[0];g[e+1]=d[1];g[e+2]=d[2];g[e+3]=d[3]}}return g.buffer}}function g(a,b){var d=Object.keys(a.lib||{}).map(function(b){return"var "+b+" = "+a.lib[b].toString()+";"}).concat(["var __minion__ = ("+f.toString()+")(",a.operation.toString(),
+");",'self.addEventListener("message", function(event) {'," var buffer = __minion__(event.data);"," self.postMessage({buffer: buffer, meta: event.data.meta}, [buffer]);","});"]),d=URL.createObjectURL(new Blob(d,{type:"text/javascript"})),d=new Worker(d);d.addEventListener("message",b);return d}function h(a,b){var d=f(a.operation);return{postMessage:function(a){setTimeout(function(){b({data:{buffer:d(a),meta:a.meta}})},0)}}}function l(a){this.Re=!!a.ll;var b;0===a.threads?b=0:this.Re?b=1:b=a.threads||
+1;var d=[];if(b)for(var e=0;e<b;++e)d[e]=g(a,this.ig.bind(this,e));else d[0]=h(a,this.ig.bind(this,0));this.Ld=d;this.$c=[];this.oj=a.uo||Infinity;this.Jd=0;this.Ic={};this.Se=null}var m=a("./util").Fl;l.prototype.so=function(a,b,d){this.lj({Ac:a,Xg:b,qg:d});this.fg()};l.prototype.lj=function(a){for(this.$c.push(a);this.$c.length>this.oj;)this.$c.shift().qg(null,null)};l.prototype.fg=function(){if(0===this.Jd&&0<this.$c.length){var a=this.Se=this.$c.shift(),b=a.Ac[0].width,d=a.Ac[0].height,e=a.Ac.map(function(a){return a.data.buffer}),
+f=this.Ld.length;this.Jd=f;if(1===f)this.Ld[0].postMessage({buffers:e,meta:a.Xg,imageOps:this.Re,width:b,height:d},e);else for(var g=4*Math.ceil(a.Ac[0].data.length/4/f),h=0;h<f;++h){for(var l=h*g,m=[],z=0,F=e.length;z<F;++z)m.push(e[h].slice(l,l+g));this.Ld[h].postMessage({buffers:m,meta:a.Xg,imageOps:this.Re,width:b,height:d},m)}}};l.prototype.ig=function(a,b){this.Pp||(this.Ic[a]=b.data,--this.Jd,0===this.Jd&&this.pj())};l.prototype.pj=function(){var a=this.Se,b=this.Ld.length,d,e;if(1===b)d=new Uint8ClampedArray(this.Ic[0].buffer),
+e=this.Ic[0].meta;else{var f=a.Ac[0].data.length;d=new Uint8ClampedArray(f);e=Array(f);for(var f=4*Math.ceil(f/4/b),g=0;g<b;++g){var h=g*f;d.set(new Uint8ClampedArray(this.Ic[g].buffer),h);e[g]=this.Ic[g].meta}}this.Se=null;this.Ic={};a.qg(null,m(d,a.Ac[0].width,a.Ac[0].height),e);this.fg()};b.ja=l},{"./util":3}],3:[function(a,b,f){var g=!0;try{new ImageData(10,10)}catch(l){g=!1}var h=document.createElement("canvas").getContext("2d");f.Fl=function(a,b,d){if(g)return new ImageData(a,b,d);b=h.createImageData(b,
+d);b.data.set(a);return b}},{}]},{},[1])(1)});jl=b.ja})();function Hv(a){this.S=null;this.Aa=void 0!==a.operationType?a.operationType:"pixel";this.Sa=void 0!==a.threads?a.threads:1;this.c=Iv(a.sources);for(var b=0,c=this.c.length;b<c;++b)B(this.c[b],"change",this.u,this);this.i=Oe();this.ia=new Rh(function(){return 1},this.u.bind(this));for(var b=Jv(this.c),c={},d=0,e=b.length;d<e;++d)c[w(b[d].layer)]=b[d];this.j=this.s=null;this.Y={animate:!1,attributions:{},coordinateToPixelMatrix:Xc(),extent:null,focus:null,index:0,layerStates:c,layerStatesArray:b,logos:{},
+pixelRatio:1,pixelToCoordinateMatrix:Xc(),postRenderFunctions:[],size:[0,0],skippedFeatureUids:{},tileQueue:this.ia,time:Date.now(),usedTiles:{},viewState:{rotation:0},viewHints:[],wantedTiles:{}};Ak.call(this,{});void 0!==a.operation&&this.v(a.operation,a.lib)}y(Hv,Ak);Hv.prototype.v=function(a,b){this.S=new jl.$i({operation:a,ll:"image"===this.Aa,uo:1,lib:b,threads:this.Sa});this.u()};function Kv(a,b,c){var d=a.s;return!d||a.g!==d.Xo||c!==d.resolution||!$b(b,d.extent)}
+Hv.prototype.A=function(a,b,c,d){c=!0;for(var e,f=0,g=this.c.length;f<g;++f)if(e=this.c[f].a.ha(),"ready"!==e.V()){c=!1;break}if(!c)return null;a=a.slice();if(!Kv(this,a,b))return this.j;c=this.i.canvas;e=Math.round(ic(a)/b);f=Math.round(jc(a)/b);if(e!==c.width||f!==c.height)c.width=e,c.height=f;e=Ea({},this.Y);e.viewState=Ea({},e.viewState);var f=kc(a),g=Math.round(ic(a)/b),h=Math.round(jc(a)/b);e.extent=a;e.focus=kc(a);e.size[0]=g;e.size[1]=h;g=e.viewState;g.center=f;g.projection=d;g.resolution=
+b;this.j=d=new nk(a,b,1,this.l,c,this.T.bind(this,e));this.s={extent:a,resolution:b,Xo:this.g};return d};
+Hv.prototype.T=function(a,b){for(var c=this.c.length,d=Array(c),e=0;e<c;++e){var f;f=this.c[e];var g=a,h=a.layerStatesArray[e];if(f.l(g,h)){var l=g.size[0],m=g.size[1];if(Lv){var n=Lv.canvas;n.width!==l||n.height!==m?Lv=Oe(l,m):Lv.clearRect(0,0,l,m)}else Lv=Oe(l,m);f.i(g,h,Lv);f=Lv.getImageData(0,0,l,m)}else f=null;if(f)d[e]=f;else return}c={};this.b(new Mv(Nv,a,c));this.S.so(d,c,this.ta.bind(this,a,b));Sh(a.tileQueue,16,16)};
+Hv.prototype.ta=function(a,b,c,d,e){c?b(c):d&&(this.b(new Mv(Ov,a,e)),Kv(this,a.extent,a.viewState.resolution/a.pixelRatio)||this.i.putImageData(d,0,0),b(null))};var Lv=null;function Jv(a){return a.map(function(a){return jh(a.a)})}function Iv(a){for(var b=a.length,c=Array(b),d=0;d<b;++d){var e=d,f=a[d],g=null;f instanceof zf?(f=new dj({source:f}),g=new Bl(f)):f instanceof Ak&&(f=new cj({source:f}),g=new Al(f));c[e]=g}return c}
+function Mv(a,b,c){Wa.call(this,a);this.extent=b.extent;this.resolution=b.viewState.resolution/b.pixelRatio;this.data=c}y(Mv,Wa);var Nv="beforeoperations",Ov="afteroperations";var Pv={terrain:{tb:"jpg",opaque:!0},"terrain-background":{tb:"jpg",opaque:!0},"terrain-labels":{tb:"png",opaque:!1},"terrain-lines":{tb:"png",opaque:!1},"toner-background":{tb:"png",opaque:!0},toner:{tb:"png",opaque:!0},"toner-hybrid":{tb:"png",opaque:!1},"toner-labels":{tb:"png",opaque:!1},"toner-lines":{tb:"png",opaque:!1},"toner-lite":{tb:"png",opaque:!0},watercolor:{tb:"jpg",opaque:!0}},Qv={terrain:{minZoom:4,maxZoom:18},toner:{minZoom:0,maxZoom:20},watercolor:{minZoom:1,maxZoom:16}};
+function Rv(a){var b=a.layer.indexOf("-"),b=-1==b?a.layer:a.layer.slice(0,b),b=Qv[b],c=Pv[a.layer];rv.call(this,{attributions:Sv,cacheSize:a.cacheSize,crossOrigin:"anonymous",maxZoom:void 0!=a.maxZoom?a.maxZoom:b.maxZoom,minZoom:void 0!=a.minZoom?a.minZoom:b.minZoom,opaque:c.opaque,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileLoadFunction:a.tileLoadFunction,url:void 0!==a.url?a.url:"https://stamen-tiles-{a-d}.a.ssl.fastly.net/"+a.layer+"/{z}/{x}/{y}."+c.tb})}y(Rv,rv);
+var Sv=[new je({html:'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a>.'}),Gv];function Tv(a){a=a||{};W.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction,url:a.url,urls:a.urls,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.c=a.params||{};this.j=Lb()}y(Tv,W);Tv.prototype.v=function(){return this.c};Tv.prototype.bc=function(a){return a};
+Tv.prototype.vc=function(a,b,c){var d=this.tileGrid;d||(d=this.eb(c));if(!(d.b.length<=a[0])){var e=d.Ea(a,this.j),f=hf(d.Ja(a[0]),this.o);1!=b&&(f=gf(f,b,this.o));d={F:"image",FORMAT:"PNG32",TRANSPARENT:!0};Ea(d,this.c);var g=this.urls;g?(c=c.cb.split(":").pop(),d.SIZE=f[0]+","+f[1],d.BBOX=e.join(","),d.BBOXSR=c,d.IMAGESR=c,d.DPI=Math.round(d.DPI?d.DPI*b:90*b),a=(1==g.length?g[0]:g[xa((a[1]<<a[0])+a[2],g.length)]).replace(/MapServer\/?$/,"MapServer/export").replace(/ImageServer\/?$/,"ImageServer/exportImage"),
+a=xv(a,d)):a=void 0;return a}};Tv.prototype.A=function(a){Ea(this.c,a);this.u()};function Uv(a,b,c){df.call(this,a,2);this.l=b;this.c=c;this.g={}}y(Uv,df);Uv.prototype.$a=function(a){a=void 0!==a?w(a):-1;if(a in this.g)return this.g[a];var b=this.l,c=Oe(b[0],b[1]);c.strokeStyle="black";c.strokeRect(.5,.5,b[0]+.5,b[1]+.5);c.fillStyle="black";c.textAlign="center";c.textBaseline="middle";c.font="24px sans-serif";c.fillText(this.c,b[0]/2,b[1]/2);return this.g[a]=c.canvas};
+function Vv(a){zf.call(this,{opaque:!1,projection:a.projection,tileGrid:a.tileGrid,wrapX:void 0!==a.wrapX?a.wrapX:!0})}y(Vv,zf);Vv.prototype.ac=function(a,b,c){var d=this.Eb(a,b,c);if(Ze(this.a,d))return this.a.get(d);var e=hf(this.tileGrid.Ja(a));a=[a,b,c];b=(b=Cf(this,a))?Cf(this,b).toString():"";e=new Uv(a,e,b);this.a.set(d,e);return e};function Wv(a){this.c=null;W.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,projection:yc("EPSG:3857"),reprojectionErrorThreshold:a.reprojectionErrorThreshold,state:"loading",tileLoadFunction:a.tileLoadFunction,wrapX:void 0!==a.wrapX?a.wrapX:!0});if(a.jsonp)kv(a.url,this.yh.bind(this),this.me.bind(this));else{var b=new XMLHttpRequest;b.addEventListener("load",this.pn.bind(this));b.addEventListener("error",this.nn.bind(this));b.open("GET",a.url);b.send()}}
+y(Wv,W);k=Wv.prototype;k.pn=function(a){a=a.target;if(200<=a.status&&300>a.status){var b;try{b=JSON.parse(a.responseText)}catch(c){this.me();return}this.yh(b)}else this.me()};k.nn=function(){this.me()};k.Ak=function(){return this.c};
+k.yh=function(a){var b=yc("EPSG:4326"),c=this.f,d;void 0!==a.bounds&&(d=pc(a.bounds,Bc(b,c)));var e=a.minzoom||0,f=a.maxzoom||22;this.tileGrid=c=yf({extent:wf(c),maxZoom:f,minZoom:e});this.tileUrlFunction=Fl(a.tiles,c);if(void 0!==a.attribution&&!this.l){b=void 0!==d?d:b.H();d={};for(var g;e<=f;++e)g=e.toString(),d[g]=[pf(c,b,e)];this.oa([new je({html:a.attribution,tileRanges:d})])}this.c=a;lf(this,"ready")};k.me=function(){lf(this,"error")};function Xv(a){zf.call(this,{projection:yc("EPSG:3857"),state:"loading"});this.s=void 0!==a.preemptive?a.preemptive:!0;this.j=Hl;this.i=void 0;this.c=a.jsonp||!1;if(a.url)if(this.c)kv(a.url,this.Bf.bind(this),this.ne.bind(this));else{var b=new XMLHttpRequest;b.addEventListener("load",this.tn.bind(this));b.addEventListener("error",this.sn.bind(this));b.open("GET",a.url);b.send()}else a.tileJSON&&this.Bf(a.tileJSON)}y(Xv,zf);k=Xv.prototype;
+k.tn=function(a){a=a.target;if(200<=a.status&&300>a.status){var b;try{b=JSON.parse(a.responseText)}catch(c){this.ne();return}this.Bf(b)}else this.ne()};k.sn=function(){this.ne()};k.xk=function(){return this.i};k.Ij=function(a,b,c,d,e){this.tileGrid?(b=this.tileGrid.Zd(a,b),Yv(this.ac(b[0],b[1],b[2],1,this.f),a,c,d,e)):!0===e?Tf(function(){c.call(d,null)}):c.call(d,null)};k.ne=function(){lf(this,"error")};
+k.Bf=function(a){var b=yc("EPSG:4326"),c=this.f,d;void 0!==a.bounds&&(d=pc(a.bounds,Bc(b,c)));var e=a.minzoom||0,f=a.maxzoom||22;this.tileGrid=c=yf({extent:wf(c),maxZoom:f,minZoom:e});this.i=a.template;var g=a.grids;if(g){this.j=Fl(g,c);if(void 0!==a.attribution){b=void 0!==d?d:b.H();for(d={};e<=f;++e)g=e.toString(),d[g]=[pf(c,b,e)];this.oa([new je({html:a.attribution,tileRanges:d})])}lf(this,"ready")}else lf(this,"error")};
+k.ac=function(a,b,c,d,e){var f=this.Eb(a,b,c);if(Ze(this.a,f))return this.a.get(f);a=[a,b,c];b=Cf(this,a,e);d=this.j(b,d,e);d=new Zv(a,void 0!==d?0:4,void 0!==d?d:"",this.tileGrid.Ea(a),this.s,this.c);this.a.set(f,d);return d};k.Yf=function(a,b,c){a=this.Eb(a,b,c);Ze(this.a,a)&&this.a.get(a)};function Zv(a,b,c,d,e,f){df.call(this,a,b);this.s=c;this.g=d;this.U=e;this.c=this.j=this.l=null;this.v=f}y(Zv,df);k=Zv.prototype;k.$a=function(){return null};
+k.getData=function(a){if(!this.l||!this.j)return null;var b=this.l[Math.floor((1-(a[1]-this.g[1])/(this.g[3]-this.g[1]))*this.l.length)];if("string"!==typeof b)return null;b=b.charCodeAt(Math.floor((a[0]-this.g[0])/(this.g[2]-this.g[0])*b.length));93<=b&&b--;35<=b&&b--;b-=32;a=null;b in this.j&&(b=this.j[b],this.c&&b in this.c?a=this.c[b]:a=b);return a};
+function Yv(a,b,c,d,e){0==a.state&&!0===e?(Pa(a,"change",function(){c.call(d,this.getData(b))},a),$v(a)):!0===e?Tf(function(){c.call(d,this.getData(b))},a):c.call(d,a.getData(b))}k.ib=function(){return this.s};k.ae=function(){this.state=3;ef(this)};k.zh=function(a){this.l=a.grid;this.j=a.keys;this.c=a.data;this.state=4;ef(this)};
+function $v(a){if(0==a.state)if(a.state=1,a.v)kv(a.s,a.zh.bind(a),a.ae.bind(a));else{var b=new XMLHttpRequest;b.addEventListener("load",a.rn.bind(a));b.addEventListener("error",a.qn.bind(a));b.open("GET",a.s);b.send()}}k.rn=function(a){a=a.target;if(200<=a.status&&300>a.status){var b;try{b=JSON.parse(a.responseText)}catch(c){this.ae();return}this.zh(b)}else this.ae()};k.qn=function(){this.ae()};k.load=function(){this.U&&$v(this)};function aw(a){a=a||{};var b=a.params||{};W.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,opaque:!("TRANSPARENT"in b?b.TRANSPARENT:1),projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileGrid:a.tileGrid,tileLoadFunction:a.tileLoadFunction,url:a.url,urls:a.urls,wrapX:void 0!==a.wrapX?a.wrapX:!0});this.v=void 0!==a.gutter?a.gutter:0;this.c=b;this.j=!0;this.A=a.serverType;this.T=void 0!==a.hidpi?a.hidpi:!0;this.S="";
+bw(this);this.Y=Lb();cw(this);Bf(this,dw(this))}y(aw,W);k=aw.prototype;
+k.vn=function(a,b,c,d){c=yc(c);var e=this.tileGrid;e||(e=this.eb(c));b=e.Zd(a,b);if(!(e.b.length<=b[0])){var f=e.$(b[0]),g=e.Ea(b,this.Y),e=hf(e.Ja(b[0]),this.o),h=this.v;0!==h&&(e=ff(e,h,this.o),g=Ob(g,f*h,g));h={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.c.LAYERS};Ea(h,this.c,d);d=Math.floor((g[3]-a[1])/f);h[this.j?"I":"X"]=Math.floor((a[0]-g[0])/f);h[this.j?"J":"Y"]=d;return ew(this,b,e,g,1,c,h)}};k.gf=function(){return this.v};
+k.Eb=function(a,b,c){return this.S+W.prototype.Eb.call(this,a,b,c)};k.wn=function(){return this.c};
+function ew(a,b,c,d,e,f,g){var h=a.urls;if(h){g.WIDTH=c[0];g.HEIGHT=c[1];g[a.j?"CRS":"SRS"]=f.cb;"STYLES"in a.c||(g.STYLES="");if(1!=e)switch(a.A){case "geoserver":c=90*e+.5|0;g.FORMAT_OPTIONS="FORMAT_OPTIONS"in g?g.FORMAT_OPTIONS+(";dpi:"+c):"dpi:"+c;break;case "mapserver":g.MAP_RESOLUTION=90*e;break;case "carmentaserver":case "qgis":g.DPI=90*e}f=f.b;a.j&&"ne"==f.substr(0,2)&&(a=d[0],d[0]=d[1],d[1]=a,a=d[2],d[2]=d[3],d[3]=a);g.BBOX=d.join(",");return xv(1==h.length?h[0]:h[xa((b[1]<<b[0])+b[2],h.length)],
+g)}}k.bc=function(a){return this.T&&void 0!==this.A?a:1};function bw(a){var b=0,c=[];if(a.urls){var d,e;d=0;for(e=a.urls.length;d<e;++d)c[b++]=a.urls[d]}a.S=c.join("#")}function dw(a){var b=0,c=[],d;for(d in a.c)c[b++]=d+"-"+a.c[d];return c.join("/")}
+k.vc=function(a,b,c){var d=this.tileGrid;d||(d=this.eb(c));if(!(d.b.length<=a[0])){1==b||this.T&&void 0!==this.A||(b=1);var e=d.$(a[0]),f=d.Ea(a,this.Y),d=hf(d.Ja(a[0]),this.o),g=this.v;0!==g&&(d=ff(d,g,this.o),f=Ob(f,e*g,f));1!=b&&(d=gf(d,b,this.o));e={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};Ea(e,this.c);return ew(this,a,d,f,b,c,e)}};k.xn=function(a){Ea(this.c,a);bw(this);cw(this);Bf(this,dw(this))};function cw(a){a.j=0<=Ab(a.c.VERSION||"1.3.0")};function fw(a){this.l=a.matrixIds;mf.call(this,{extent:a.extent,origin:a.origin,origins:a.origins,resolutions:a.resolutions,tileSize:a.tileSize,tileSizes:a.tileSizes,sizes:a.sizes})}y(fw,mf);fw.prototype.j=function(){return this.l};
+function gw(a,b){var c=[],d=[],e=[],f=[],g=[],h;h=yc(a.SupportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/,"$1:$3"));var l=h.$b(),m="ne"==h.b.substr(0,2);a.TileMatrix.sort(function(a,b){return b.ScaleDenominator-a.ScaleDenominator});a.TileMatrix.forEach(function(a){d.push(a.Identifier);var b=2.8E-4*a.ScaleDenominator/l,h=a.TileWidth,r=a.TileHeight;m?e.push([a.TopLeftCorner[1],a.TopLeftCorner[0]]):e.push(a.TopLeftCorner);c.push(b);f.push(h==r?h:[h,r]);g.push([a.MatrixWidth,-a.MatrixHeight])});
+return new fw({extent:b,origins:e,resolutions:c,matrixIds:d,tileSizes:f,sizes:g})};function Z(a){function b(a){a="KVP"==d?xv(a,f):a.replace(/\{(\w+?)\}/g,function(a,b){return b.toLowerCase()in f?f[b.toLowerCase()]:a});return function(b){if(b){var c={TileMatrix:e.l[b[0]],TileCol:b[1],TileRow:-b[2]-1};Ea(c,g);b=a;return b="KVP"==d?xv(b,c):b.replace(/\{(\w+?)\}/g,function(a,b){return c[b]})}}}this.T=void 0!==a.version?a.version:"1.0.0";this.v=void 0!==a.format?a.format:"image/jpeg";this.c=void 0!==a.dimensions?a.dimensions:{};this.A=a.layer;this.j=a.matrixSet;this.S=a.style;var c=
+a.urls;void 0===c&&void 0!==a.url&&(c=Il(a.url));var d=this.Y=void 0!==a.requestEncoding?a.requestEncoding:"KVP",e=a.tileGrid,f={layer:this.A,style:this.S,tilematrixset:this.j};"KVP"==d&&Ea(f,{Service:"WMTS",Request:"GetTile",Version:this.T,Format:this.v});var g=this.c,h=c&&0<c.length?Gl(c.map(b)):Hl;W.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,projection:a.projection,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileClass:a.tileClass,
+tileGrid:e,tileLoadFunction:a.tileLoadFunction,tilePixelRatio:a.tilePixelRatio,tileUrlFunction:h,urls:c,wrapX:void 0!==a.wrapX?a.wrapX:!1});Bf(this,hw(this))}y(Z,W);k=Z.prototype;k.Vj=function(){return this.c};k.yn=function(){return this.v};k.zn=function(){return this.A};k.hk=function(){return this.j};k.vk=function(){return this.Y};k.An=function(){return this.S};k.Ck=function(){return this.T};function hw(a){var b=0,c=[],d;for(d in a.c)c[b++]=d+"-"+a.c[d];return c.join("/")}
+k.vp=function(a){Ea(this.c,a);Bf(this,hw(this))};function iw(a){a=a||{};var b=a.size,c=b[0],d=b[1],e=[],f=256;switch(void 0!==a.tierSizeCalculation?a.tierSizeCalculation:"default"){case "default":for(;c>f||d>f;)e.push([Math.ceil(c/f),Math.ceil(d/f)]),f+=f;break;case "truncated":for(;c>f||d>f;)e.push([Math.ceil(c/f),Math.ceil(d/f)]),c>>=1,d>>=1}e.push([1,1]);e.reverse();for(var f=[1],g=[0],d=1,c=e.length;d<c;d++)f.push(1<<d),g.push(e[d-1][0]*e[d-1][1]+g[d-1]);f.reverse();var b=[0,-b[1],b[0],0],b=new mf({extent:b,origin:fc(b),resolutions:f}),h=a.url;
+W.call(this,{attributions:a.attributions,cacheSize:a.cacheSize,crossOrigin:a.crossOrigin,logo:a.logo,reprojectionErrorThreshold:a.reprojectionErrorThreshold,tileClass:jw,tileGrid:b,tileUrlFunction:function(a){if(a){var b=a[0],c=a[1];a=-a[2]-1;return h+"TileGroup"+((c+a*e[b][0]+g[b])/256|0)+"/"+b+"-"+c+"-"+a+".jpg"}}})}y(iw,W);function jw(a,b,c,d,e){fu.call(this,a,b,c,d,e);this.l={}}y(jw,fu);
+jw.prototype.$a=function(a){var b=void 0!==a?w(a).toString():"";if(b in this.l)return this.l[b];a=fu.prototype.$a.call(this,a);if(2==this.state){if(256==a.width&&256==a.height)return this.l[b]=a;var c=Oe(256,256);c.drawImage(a,0,0);return this.l[b]=c.canvas}return a};function kw(a){a=a||{};this.a=void 0!==a.initialSize?a.initialSize:256;this.g=void 0!==a.maxSize?a.maxSize:void 0!==la?la:2048;this.b=void 0!==a.space?a.space:1;this.c=[new lw(this.a,this.b)];this.f=this.a;this.i=[new lw(this.f,this.b)]}kw.prototype.add=function(a,b,c,d,e,f){if(b+this.b>this.g||c+this.b>this.g)return null;d=mw(this,!1,a,b,c,d,f);if(!d)return null;a=mw(this,!0,a,b,c,void 0!==e?e:na,f);return{offsetX:d.offsetX,offsetY:d.offsetY,image:d.image,Sg:a.image}};
+function mw(a,b,c,d,e,f,g){var h=b?a.i:a.c,l,m,n;m=0;for(n=h.length;m<n;++m){l=h[m];if(l=l.add(c,d,e,f,g))return l;l||m!==n-1||(b?(l=Math.min(2*a.f,a.g),a.f=l):(l=Math.min(2*a.a,a.g),a.a=l),l=new lw(l,a.b),h.push(l),++n)}}function lw(a,b){this.b=b;this.a=[{x:0,y:0,width:a,height:a}];this.f={};this.g=Oe(a,a);this.c=this.g.canvas}lw.prototype.get=function(a){return this.f[a]||null};
+lw.prototype.add=function(a,b,c,d,e){var f,g,h;g=0;for(h=this.a.length;g<h;++g)if(f=this.a[g],f.width>=b+this.b&&f.height>=c+this.b)return h={offsetX:f.x+this.b,offsetY:f.y+this.b,image:this.c},this.f[a]=h,d.call(e,this.g,f.x+this.b,f.y+this.b),a=g,b+=this.b,d=c+this.b,f.width-b>f.height-d?(c={x:f.x+b,y:f.y,width:f.width-b,height:f.height},b={x:f.x,y:f.y+d,width:b,height:f.height-d},nw(this,a,c,b)):(c={x:f.x+b,y:f.y,width:f.width-b,height:d},b={x:f.x,y:f.y+d,width:f.width,height:f.height-d},nw(this,
+a,c,b)),h;return null};function nw(a,b,c,d){b=[b,1];0<c.width&&0<c.height&&b.push(c);0<d.width&&0<d.height&&b.push(d);a.a.splice.apply(a.a,b)};function ow(a){this.A=this.s=this.f=null;this.o=void 0!==a.fill?a.fill:null;this.ya=[0,0];this.b=a.points;this.g=void 0!==a.radius?a.radius:a.radius1;this.c=void 0!==a.radius2?a.radius2:this.g;this.l=void 0!==a.angle?a.angle:0;this.a=void 0!==a.stroke?a.stroke:null;this.R=this.Ba=this.D=null;var b=a.atlasManager,c="",d="",e=0,f=null,g,h=0;this.a&&(g=ve(this.a.b),h=this.a.a,void 0===h&&(h=1),f=this.a.g,hg||(f=null),d=this.a.c,void 0===d&&(d="round"),c=this.a.f,void 0===c&&(c="round"),e=this.a.i,void 0===
+e&&(e=10));var l=2*(this.g+h)+1,c={strokeStyle:g,Bd:h,size:l,lineCap:c,lineDash:f,lineJoin:d,miterLimit:e};if(void 0===b){var m=Oe(l,l);this.s=m.canvas;b=l=this.s.width;this.Ih(c,m,0,0);this.o?this.A=this.s:(m=Oe(c.size,c.size),this.A=m.canvas,this.Hh(c,m,0,0))}else l=Math.round(l),(d=!this.o)&&(m=this.Hh.bind(this,c)),e=this.a?pj(this.a):"-",f=this.o?jj(this.o):"-",this.f&&e==this.f[1]&&f==this.f[2]&&this.g==this.f[3]&&this.c==this.f[4]&&this.l==this.f[5]&&this.b==this.f[6]||(this.f=["r"+e+f+(void 0!==
+this.g?this.g.toString():"-")+(void 0!==this.c?this.c.toString():"-")+(void 0!==this.l?this.l.toString():"-")+(void 0!==this.b?this.b.toString():"-"),e,f,this.g,this.c,this.l,this.b]),m=b.add(this.f[0],l,l,this.Ih.bind(this,c),m),this.s=m.image,this.ya=[m.offsetX,m.offsetY],b=m.image.width,this.A=d?m.Sg:this.s;this.D=[l/2,l/2];this.Ba=[l,l];this.R=[b,b];Ch.call(this,{opacity:1,rotateWithView:void 0!==a.rotateWithView?a.rotateWithView:!1,rotation:void 0!==a.rotation?a.rotation:0,scale:1,snapToPixel:void 0!==
+a.snapToPixel?a.snapToPixel:!0})}y(ow,Ch);k=ow.prototype;k.Yb=function(){return this.D};k.Fn=function(){return this.l};k.Gn=function(){return this.o};k.pe=function(){return this.A};k.jc=function(){return this.s};k.ld=function(){return this.R};k.td=function(){return 2};k.Ia=function(){return this.ya};k.Hn=function(){return this.b};k.In=function(){return this.g};k.uk=function(){return this.c};k.Fb=function(){return this.Ba};k.Jn=function(){return this.a};k.pf=na;k.load=na;k.Xf=na;
+k.Ih=function(a,b,c,d){var e;b.setTransform(1,0,0,1,0,0);b.translate(c,d);b.beginPath();this.c!==this.g&&(this.b*=2);for(c=0;c<=this.b;c++)d=2*c*Math.PI/this.b-Math.PI/2+this.l,e=0===c%2?this.g:this.c,b.lineTo(a.size/2+e*Math.cos(d),a.size/2+e*Math.sin(d));this.o&&(b.fillStyle=xe(this.o.b),b.fill());this.a&&(b.strokeStyle=a.strokeStyle,b.lineWidth=a.Bd,a.lineDash&&b.setLineDash(a.lineDash),b.lineCap=a.lineCap,b.lineJoin=a.lineJoin,b.miterLimit=a.miterLimit,b.stroke());b.closePath()};
+k.Hh=function(a,b,c,d){b.setTransform(1,0,0,1,0,0);b.translate(c,d);b.beginPath();this.c!==this.g&&(this.b*=2);var e;for(c=0;c<=this.b;c++)e=2*c*Math.PI/this.b-Math.PI/2+this.l,d=0===c%2?this.g:this.c,b.lineTo(a.size/2+d*Math.cos(e),a.size/2+d*Math.sin(e));b.fillStyle=ej;b.fill();this.a&&(b.strokeStyle=a.strokeStyle,b.lineWidth=a.Bd,a.lineDash&&b.setLineDash(a.lineDash),b.stroke());b.closePath()};t("ol.animation.bounce",function(a){var b=a.resolution,c=a.start?a.start:Date.now(),d=void 0!==a.duration?a.duration:1E3,e=a.easing?a.easing:be;return function(a,g){if(g.time<c)return g.animate=!0,g.viewHints[0]+=1,!0;if(g.time<c+d){var h=e((g.time-c)/d),l=b-g.viewState.resolution;g.animate=!0;g.viewState.resolution+=h*l;g.viewHints[0]+=1;return!0}return!1}},OPENLAYERS);t("ol.animation.pan",ce,OPENLAYERS);t("ol.animation.rotate",de,OPENLAYERS);t("ol.animation.zoom",ee,OPENLAYERS);
+t("ol.Attribution",je,OPENLAYERS);je.prototype.getHTML=je.prototype.g;ke.prototype.element=ke.prototype.element;t("ol.Collection",le,OPENLAYERS);le.prototype.clear=le.prototype.clear;le.prototype.extend=le.prototype.qf;le.prototype.forEach=le.prototype.forEach;le.prototype.getArray=le.prototype.Gl;le.prototype.item=le.prototype.item;le.prototype.getLength=le.prototype.dc;le.prototype.insertAt=le.prototype.ee;le.prototype.pop=le.prototype.pop;le.prototype.push=le.prototype.push;
+le.prototype.remove=le.prototype.remove;le.prototype.removeAt=le.prototype.Rf;le.prototype.setAt=le.prototype.Zo;t("ol.colorlike.asColorLike",xe,OPENLAYERS);t("ol.coordinate.add",Bb,OPENLAYERS);t("ol.coordinate.createStringXY",function(a){return function(b){return Jb(b,a)}},OPENLAYERS);t("ol.coordinate.format",Eb,OPENLAYERS);t("ol.coordinate.rotate",Gb,OPENLAYERS);t("ol.coordinate.toStringHDMS",function(a,b){return a?Db(a[1],"NS",b)+" "+Db(a[0],"EW",b):""},OPENLAYERS);
+t("ol.coordinate.toStringXY",Jb,OPENLAYERS);t("ol.DeviceOrientation",qn,OPENLAYERS);qn.prototype.getAlpha=qn.prototype.Oj;qn.prototype.getBeta=qn.prototype.Rj;qn.prototype.getGamma=qn.prototype.Yj;qn.prototype.getHeading=qn.prototype.Hl;qn.prototype.getTracking=qn.prototype.$g;qn.prototype.setTracking=qn.prototype.rf;t("ol.easing.easeIn",Yd,OPENLAYERS);t("ol.easing.easeOut",Zd,OPENLAYERS);t("ol.easing.inAndOut",$d,OPENLAYERS);t("ol.easing.linear",ae,OPENLAYERS);t("ol.easing.upAndDown",be,OPENLAYERS);
+t("ol.extent.boundingExtent",Kb,OPENLAYERS);t("ol.extent.buffer",Ob,OPENLAYERS);t("ol.extent.containsCoordinate",Sb,OPENLAYERS);t("ol.extent.containsExtent",Ub,OPENLAYERS);t("ol.extent.containsXY",Tb,OPENLAYERS);t("ol.extent.createEmpty",Lb,OPENLAYERS);t("ol.extent.equals",$b,OPENLAYERS);t("ol.extent.extend",ac,OPENLAYERS);t("ol.extent.getBottomLeft",cc,OPENLAYERS);t("ol.extent.getBottomRight",dc,OPENLAYERS);t("ol.extent.getCenter",kc,OPENLAYERS);t("ol.extent.getHeight",jc,OPENLAYERS);
+t("ol.extent.getIntersection",mc,OPENLAYERS);t("ol.extent.getSize",function(a){return[a[2]-a[0],a[3]-a[1]]},OPENLAYERS);t("ol.extent.getTopLeft",fc,OPENLAYERS);t("ol.extent.getTopRight",ec,OPENLAYERS);t("ol.extent.getWidth",ic,OPENLAYERS);t("ol.extent.intersects",nc,OPENLAYERS);t("ol.extent.isEmpty",hc,OPENLAYERS);t("ol.extent.applyTransform",pc,OPENLAYERS);t("ol.Feature",Ik,OPENLAYERS);Ik.prototype.clone=Ik.prototype.clone;Ik.prototype.getGeometry=Ik.prototype.W;Ik.prototype.getId=Ik.prototype.Xa;
+Ik.prototype.getGeometryName=Ik.prototype.$j;Ik.prototype.getStyle=Ik.prototype.Jl;Ik.prototype.getStyleFunction=Ik.prototype.ec;Ik.prototype.setGeometry=Ik.prototype.Ua;Ik.prototype.setStyle=Ik.prototype.sf;Ik.prototype.setId=Ik.prototype.mc;Ik.prototype.setGeometryName=Ik.prototype.Ec;t("ol.featureloader.tile",dl,OPENLAYERS);t("ol.featureloader.xhr",el,OPENLAYERS);t("ol.Geolocation",Ut,OPENLAYERS);Ut.prototype.getAccuracy=Ut.prototype.Mj;Ut.prototype.getAccuracyGeometry=Ut.prototype.Nj;
+Ut.prototype.getAltitude=Ut.prototype.Pj;Ut.prototype.getAltitudeAccuracy=Ut.prototype.Qj;Ut.prototype.getHeading=Ut.prototype.Ll;Ut.prototype.getPosition=Ut.prototype.Ml;Ut.prototype.getProjection=Ut.prototype.ah;Ut.prototype.getSpeed=Ut.prototype.wk;Ut.prototype.getTracking=Ut.prototype.bh;Ut.prototype.getTrackingOptions=Ut.prototype.Mg;Ut.prototype.setProjection=Ut.prototype.dh;Ut.prototype.setTracking=Ut.prototype.ge;Ut.prototype.setTrackingOptions=Ut.prototype.si;t("ol.Graticule",$t,OPENLAYERS);
+$t.prototype.getMap=$t.prototype.Pl;$t.prototype.getMeridians=$t.prototype.ik;$t.prototype.getParallels=$t.prototype.qk;$t.prototype.setMap=$t.prototype.setMap;t("ol.has.DEVICE_PIXEL_RATIO",gg,OPENLAYERS);t("ol.has.CANVAS",ig,OPENLAYERS);t("ol.has.DEVICE_ORIENTATION",jg,OPENLAYERS);t("ol.has.GEOLOCATION",kg,OPENLAYERS);t("ol.has.TOUCH",lg,OPENLAYERS);t("ol.has.WEBGL",bg,OPENLAYERS);eu.prototype.getImage=eu.prototype.a;eu.prototype.load=eu.prototype.load;fu.prototype.getImage=fu.prototype.$a;
+fu.prototype.load=fu.prototype.load;t("ol.Kinetic",Th,OPENLAYERS);t("ol.loadingstrategy.all",fl,OPENLAYERS);t("ol.loadingstrategy.bbox",function(a){return[a]},OPENLAYERS);t("ol.loadingstrategy.tile",function(a){return function(b,c){var d=a.Lb(c),e=pf(a,b,d),f=[],d=[d,0,0];for(d[1]=e.ca;d[1]<=e.ea;++d[1])for(d[2]=e.fa;d[2]<=e.ga;++d[2])f.push(a.Ea(d));return f}},OPENLAYERS);t("ol.Map",Q,OPENLAYERS);Q.prototype.addControl=Q.prototype.uj;Q.prototype.addInteraction=Q.prototype.vj;
+Q.prototype.addLayer=Q.prototype.kg;Q.prototype.addOverlay=Q.prototype.lg;Q.prototype.beforeRender=Q.prototype.Wa;Q.prototype.forEachFeatureAtPixel=Q.prototype.kd;Q.prototype.forEachLayerAtPixel=Q.prototype.Tl;Q.prototype.hasFeatureAtPixel=Q.prototype.kl;Q.prototype.getEventCoordinate=Q.prototype.Wj;Q.prototype.getEventPixel=Q.prototype.Td;Q.prototype.getTarget=Q.prototype.tf;Q.prototype.getTargetElement=Q.prototype.yc;Q.prototype.getCoordinateFromPixel=Q.prototype.Ma;Q.prototype.getControls=Q.prototype.Uj;
+Q.prototype.getOverlays=Q.prototype.nk;Q.prototype.getOverlayById=Q.prototype.mk;Q.prototype.getInteractions=Q.prototype.ak;Q.prototype.getLayerGroup=Q.prototype.xc;Q.prototype.getLayers=Q.prototype.eh;Q.prototype.getPixelFromCoordinate=Q.prototype.Ga;Q.prototype.getSize=Q.prototype.Za;Q.prototype.getView=Q.prototype.aa;Q.prototype.getViewport=Q.prototype.Dk;Q.prototype.renderSync=Q.prototype.Vo;Q.prototype.render=Q.prototype.render;Q.prototype.removeControl=Q.prototype.Oo;
+Q.prototype.removeInteraction=Q.prototype.Po;Q.prototype.removeLayer=Q.prototype.Ro;Q.prototype.removeOverlay=Q.prototype.So;Q.prototype.setLayerGroup=Q.prototype.ji;Q.prototype.setSize=Q.prototype.Wf;Q.prototype.setTarget=Q.prototype.fh;Q.prototype.setView=Q.prototype.kp;Q.prototype.updateSize=Q.prototype.Xc;Vg.prototype.originalEvent=Vg.prototype.originalEvent;Vg.prototype.pixel=Vg.prototype.pixel;Vg.prototype.coordinate=Vg.prototype.coordinate;Vg.prototype.dragging=Vg.prototype.dragging;
+We.prototype.map=We.prototype.map;We.prototype.frameState=We.prototype.frameState;db.prototype.key=db.prototype.key;db.prototype.oldValue=db.prototype.oldValue;t("ol.Object",eb,OPENLAYERS);eb.prototype.get=eb.prototype.get;eb.prototype.getKeys=eb.prototype.N;eb.prototype.getProperties=eb.prototype.O;eb.prototype.set=eb.prototype.set;eb.prototype.setProperties=eb.prototype.G;eb.prototype.unset=eb.prototype.P;t("ol.Observable",bb,OPENLAYERS);t("ol.Observable.unByKey",cb,OPENLAYERS);
+bb.prototype.changed=bb.prototype.u;bb.prototype.dispatchEvent=bb.prototype.b;bb.prototype.getRevision=bb.prototype.K;bb.prototype.on=bb.prototype.I;bb.prototype.once=bb.prototype.L;bb.prototype.un=bb.prototype.J;bb.prototype.unByKey=bb.prototype.M;t("ol.inherits",y,OPENLAYERS);t("ol.Overlay",Xm,OPENLAYERS);Xm.prototype.getElement=Xm.prototype.Sd;Xm.prototype.getId=Xm.prototype.Xa;Xm.prototype.getMap=Xm.prototype.he;Xm.prototype.getOffset=Xm.prototype.Kg;Xm.prototype.getPosition=Xm.prototype.gh;
+Xm.prototype.getPositioning=Xm.prototype.Lg;Xm.prototype.setElement=Xm.prototype.fi;Xm.prototype.setMap=Xm.prototype.setMap;Xm.prototype.setOffset=Xm.prototype.li;Xm.prototype.setPosition=Xm.prototype.uf;Xm.prototype.setPositioning=Xm.prototype.oi;t("ol.render.toContext",function(a,b){var c=a.canvas,d=b?b:{},e=d.pixelRatio||gg;if(d=d.size)c.width=d[0]*e,c.height=d[1]*e,c.style.width=d[0]+"px",c.style.height=d[1]+"px";c=[0,0,c.width,c.height];d=qh(Xc(),0,0,e,e,0,0,0);return new yj(a,e,c,d,0)},OPENLAYERS);
+t("ol.size.toSize",hf,OPENLAYERS);df.prototype.getTileCoord=df.prototype.i;df.prototype.load=df.prototype.load;Kk.prototype.getFormat=Kk.prototype.Ul;Kk.prototype.setFeatures=Kk.prototype.gi;Kk.prototype.setProjection=Kk.prototype.vf;Kk.prototype.setLoader=Kk.prototype.ki;t("ol.View",Rd,OPENLAYERS);Rd.prototype.constrainCenter=Rd.prototype.Pd;Rd.prototype.constrainResolution=Rd.prototype.constrainResolution;Rd.prototype.constrainRotation=Rd.prototype.constrainRotation;Rd.prototype.getCenter=Rd.prototype.ab;
+Rd.prototype.calculateExtent=Rd.prototype.Kc;Rd.prototype.getMaxResolution=Rd.prototype.Vl;Rd.prototype.getMinResolution=Rd.prototype.Wl;Rd.prototype.getProjection=Rd.prototype.Xl;Rd.prototype.getResolution=Rd.prototype.$;Rd.prototype.getResolutions=Rd.prototype.Yl;Rd.prototype.getRotation=Rd.prototype.La;Rd.prototype.getZoom=Rd.prototype.Fk;Rd.prototype.fit=Rd.prototype.cf;Rd.prototype.centerOn=Rd.prototype.Ej;Rd.prototype.rotate=Rd.prototype.rotate;Rd.prototype.setCenter=Rd.prototype.mb;
+Rd.prototype.setResolution=Rd.prototype.Ub;Rd.prototype.setRotation=Rd.prototype.ie;Rd.prototype.setZoom=Rd.prototype.np;t("ol.xml.getAllTextContent",Nk,OPENLAYERS);t("ol.xml.parse",Rk,OPENLAYERS);gm.prototype.getGL=gm.prototype.$n;gm.prototype.useProgram=gm.prototype.we;t("ol.tilegrid.TileGrid",mf,OPENLAYERS);mf.prototype.forEachTileCoord=mf.prototype.yg;mf.prototype.getMaxZoom=mf.prototype.Ig;mf.prototype.getMinZoom=mf.prototype.Jg;mf.prototype.getOrigin=mf.prototype.Ia;
+mf.prototype.getResolution=mf.prototype.$;mf.prototype.getResolutions=mf.prototype.Kh;mf.prototype.getTileCoordExtent=mf.prototype.Ea;mf.prototype.getTileCoordForCoordAndResolution=mf.prototype.Zd;mf.prototype.getTileCoordForCoordAndZ=mf.prototype.qd;mf.prototype.getTileSize=mf.prototype.Ja;mf.prototype.getZForResolution=mf.prototype.Lb;t("ol.tilegrid.createXYZ",yf,OPENLAYERS);t("ol.tilegrid.WMTS",fw,OPENLAYERS);fw.prototype.getMatrixIds=fw.prototype.j;
+t("ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet",gw,OPENLAYERS);t("ol.style.AtlasManager",kw,OPENLAYERS);t("ol.style.Circle",qj,OPENLAYERS);qj.prototype.getFill=qj.prototype.Bn;qj.prototype.getImage=qj.prototype.jc;qj.prototype.getRadius=qj.prototype.Cn;qj.prototype.getStroke=qj.prototype.Dn;t("ol.style.Fill",ij,OPENLAYERS);ij.prototype.getColor=ij.prototype.g;ij.prototype.setColor=ij.prototype.f;t("ol.style.Icon",Dh,OPENLAYERS);Dh.prototype.getAnchor=Dh.prototype.Yb;Dh.prototype.getImage=Dh.prototype.jc;
+Dh.prototype.getOrigin=Dh.prototype.Ia;Dh.prototype.getSrc=Dh.prototype.En;Dh.prototype.getSize=Dh.prototype.Fb;Dh.prototype.load=Dh.prototype.load;t("ol.style.Image",Ch,OPENLAYERS);Ch.prototype.getOpacity=Ch.prototype.qe;Ch.prototype.getRotateWithView=Ch.prototype.Xd;Ch.prototype.getRotation=Ch.prototype.re;Ch.prototype.getScale=Ch.prototype.se;Ch.prototype.getSnapToPixel=Ch.prototype.Yd;Ch.prototype.setOpacity=Ch.prototype.te;Ch.prototype.setRotation=Ch.prototype.ue;Ch.prototype.setScale=Ch.prototype.ve;
+t("ol.style.RegularShape",ow,OPENLAYERS);ow.prototype.getAnchor=ow.prototype.Yb;ow.prototype.getAngle=ow.prototype.Fn;ow.prototype.getFill=ow.prototype.Gn;ow.prototype.getImage=ow.prototype.jc;ow.prototype.getOrigin=ow.prototype.Ia;ow.prototype.getPoints=ow.prototype.Hn;ow.prototype.getRadius=ow.prototype.In;ow.prototype.getRadius2=ow.prototype.uk;ow.prototype.getSize=ow.prototype.Fb;ow.prototype.getStroke=ow.prototype.Jn;t("ol.style.Stroke",oj,OPENLAYERS);oj.prototype.getColor=oj.prototype.Kn;
+oj.prototype.getLineCap=oj.prototype.dk;oj.prototype.getLineDash=oj.prototype.Ln;oj.prototype.getLineJoin=oj.prototype.ek;oj.prototype.getMiterLimit=oj.prototype.jk;oj.prototype.getWidth=oj.prototype.Mn;oj.prototype.setColor=oj.prototype.Nn;oj.prototype.setLineCap=oj.prototype.fp;oj.prototype.setLineDash=oj.prototype.On;oj.prototype.setLineJoin=oj.prototype.gp;oj.prototype.setMiterLimit=oj.prototype.hp;oj.prototype.setWidth=oj.prototype.lp;t("ol.style.Style",rj,OPENLAYERS);
+rj.prototype.getGeometry=rj.prototype.W;rj.prototype.getGeometryFunction=rj.prototype.Zj;rj.prototype.getFill=rj.prototype.Pn;rj.prototype.getImage=rj.prototype.Qn;rj.prototype.getStroke=rj.prototype.Rn;rj.prototype.getText=rj.prototype.Ha;rj.prototype.getZIndex=rj.prototype.Sn;rj.prototype.setGeometry=rj.prototype.Jh;rj.prototype.setZIndex=rj.prototype.Tn;t("ol.style.Text",Gp,OPENLAYERS);Gp.prototype.getFont=Gp.prototype.Xj;Gp.prototype.getOffsetX=Gp.prototype.kk;Gp.prototype.getOffsetY=Gp.prototype.lk;
+Gp.prototype.getFill=Gp.prototype.Un;Gp.prototype.getRotation=Gp.prototype.Vn;Gp.prototype.getScale=Gp.prototype.Wn;Gp.prototype.getStroke=Gp.prototype.Xn;Gp.prototype.getText=Gp.prototype.Ha;Gp.prototype.getTextAlign=Gp.prototype.yk;Gp.prototype.getTextBaseline=Gp.prototype.zk;Gp.prototype.setFont=Gp.prototype.bp;Gp.prototype.setOffsetX=Gp.prototype.mi;Gp.prototype.setOffsetY=Gp.prototype.ni;Gp.prototype.setFill=Gp.prototype.ap;Gp.prototype.setRotation=Gp.prototype.Yn;Gp.prototype.setScale=Gp.prototype.Zn;
+Gp.prototype.setStroke=Gp.prototype.ip;Gp.prototype.setText=Gp.prototype.pi;Gp.prototype.setTextAlign=Gp.prototype.ri;Gp.prototype.setTextBaseline=Gp.prototype.jp;t("ol.Sphere",sc,OPENLAYERS);sc.prototype.geodesicArea=sc.prototype.a;sc.prototype.haversineDistance=sc.prototype.b;t("ol.source.BingMaps",pv,OPENLAYERS);t("ol.source.BingMaps.TOS_ATTRIBUTION",qv,OPENLAYERS);t("ol.source.CartoDB",sv,OPENLAYERS);sv.prototype.getConfig=sv.prototype.Tj;sv.prototype.updateConfig=sv.prototype.up;
+sv.prototype.setConfig=sv.prototype.$o;t("ol.source.Cluster",Y,OPENLAYERS);Y.prototype.getSource=Y.prototype.Aa;t("ol.source.ImageArcGISRest",yv,OPENLAYERS);yv.prototype.getParams=yv.prototype.Sm;yv.prototype.getImageLoadFunction=yv.prototype.Rm;yv.prototype.getUrl=yv.prototype.Tm;yv.prototype.setImageLoadFunction=yv.prototype.Um;yv.prototype.setUrl=yv.prototype.Vm;yv.prototype.updateParams=yv.prototype.Wm;t("ol.source.ImageCanvas",Hk,OPENLAYERS);t("ol.source.ImageMapGuide",zv,OPENLAYERS);
+zv.prototype.getParams=zv.prototype.Ym;zv.prototype.getImageLoadFunction=zv.prototype.Xm;zv.prototype.updateParams=zv.prototype.$m;zv.prototype.setImageLoadFunction=zv.prototype.Zm;t("ol.source.Image",Ak,OPENLAYERS);Ck.prototype.image=Ck.prototype.image;t("ol.source.ImageStatic",Av,OPENLAYERS);t("ol.source.ImageVector",yl,OPENLAYERS);yl.prototype.getSource=yl.prototype.an;yl.prototype.getStyle=yl.prototype.bn;yl.prototype.getStyleFunction=yl.prototype.cn;yl.prototype.setStyle=yl.prototype.xh;
+t("ol.source.ImageWMS",Bv,OPENLAYERS);Bv.prototype.getGetFeatureInfoUrl=Bv.prototype.fn;Bv.prototype.getParams=Bv.prototype.hn;Bv.prototype.getImageLoadFunction=Bv.prototype.gn;Bv.prototype.getUrl=Bv.prototype.jn;Bv.prototype.setImageLoadFunction=Bv.prototype.kn;Bv.prototype.setUrl=Bv.prototype.ln;Bv.prototype.updateParams=Bv.prototype.mn;t("ol.source.OSM",Fv,OPENLAYERS);t("ol.source.OSM.ATTRIBUTION",Gv,OPENLAYERS);t("ol.source.Raster",Hv,OPENLAYERS);Hv.prototype.setOperation=Hv.prototype.v;
+Mv.prototype.extent=Mv.prototype.extent;Mv.prototype.resolution=Mv.prototype.resolution;Mv.prototype.data=Mv.prototype.data;t("ol.source.Source",jf,OPENLAYERS);jf.prototype.getAttributions=jf.prototype.wa;jf.prototype.getLogo=jf.prototype.ua;jf.prototype.getProjection=jf.prototype.xa;jf.prototype.getState=jf.prototype.V;jf.prototype.refresh=jf.prototype.sa;jf.prototype.setAttributions=jf.prototype.oa;t("ol.source.Stamen",Rv,OPENLAYERS);t("ol.source.TileArcGISRest",Tv,OPENLAYERS);
+Tv.prototype.getParams=Tv.prototype.v;Tv.prototype.updateParams=Tv.prototype.A;t("ol.source.TileDebug",Vv,OPENLAYERS);t("ol.source.TileImage",W,OPENLAYERS);W.prototype.setRenderReprojectionEdges=W.prototype.zb;W.prototype.setTileGridForProjection=W.prototype.Ab;t("ol.source.TileJSON",Wv,OPENLAYERS);Wv.prototype.getTileJSON=Wv.prototype.Ak;t("ol.source.Tile",zf,OPENLAYERS);zf.prototype.getTileGrid=zf.prototype.Na;Df.prototype.tile=Df.prototype.tile;t("ol.source.TileUTFGrid",Xv,OPENLAYERS);
+Xv.prototype.getTemplate=Xv.prototype.xk;Xv.prototype.forDataAtCoordinateAndResolution=Xv.prototype.Ij;t("ol.source.TileWMS",aw,OPENLAYERS);aw.prototype.getGetFeatureInfoUrl=aw.prototype.vn;aw.prototype.getParams=aw.prototype.wn;aw.prototype.updateParams=aw.prototype.xn;Jl.prototype.getTileLoadFunction=Jl.prototype.fb;Jl.prototype.getTileUrlFunction=Jl.prototype.gb;Jl.prototype.getUrls=Jl.prototype.hb;Jl.prototype.setTileLoadFunction=Jl.prototype.kb;Jl.prototype.setTileUrlFunction=Jl.prototype.Qa;
+Jl.prototype.setUrl=Jl.prototype.Va;Jl.prototype.setUrls=Jl.prototype.bb;t("ol.source.Vector",P,OPENLAYERS);P.prototype.addFeature=P.prototype.rb;P.prototype.addFeatures=P.prototype.Jc;P.prototype.clear=P.prototype.clear;P.prototype.forEachFeature=P.prototype.wg;P.prototype.forEachFeatureInExtent=P.prototype.ub;P.prototype.forEachFeatureIntersectingExtent=P.prototype.xg;P.prototype.getFeaturesCollection=P.prototype.Fg;P.prototype.getFeatures=P.prototype.oe;P.prototype.getFeaturesAtCoordinate=P.prototype.Eg;
+P.prototype.getFeaturesInExtent=P.prototype.ef;P.prototype.getClosestFeatureToCoordinate=P.prototype.Ag;P.prototype.getExtent=P.prototype.H;P.prototype.getFeatureById=P.prototype.Dg;P.prototype.getFormat=P.prototype.Ch;P.prototype.getUrl=P.prototype.Dh;P.prototype.removeFeature=P.prototype.nb;vl.prototype.feature=vl.prototype.feature;t("ol.source.VectorTile",Kl,OPENLAYERS);t("ol.source.WMTS",Z,OPENLAYERS);Z.prototype.getDimensions=Z.prototype.Vj;Z.prototype.getFormat=Z.prototype.yn;
+Z.prototype.getLayer=Z.prototype.zn;Z.prototype.getMatrixSet=Z.prototype.hk;Z.prototype.getRequestEncoding=Z.prototype.vk;Z.prototype.getStyle=Z.prototype.An;Z.prototype.getVersion=Z.prototype.Ck;Z.prototype.updateDimensions=Z.prototype.vp;
+t("ol.source.WMTS.optionsFromCapabilities",function(a,b){var c=ob(a.Contents.Layer,function(a){return a.Identifier==b.layer}),d=a.Contents.TileMatrixSet,e,f;e=1<c.TileMatrixSetLink.length?"projection"in b?sb(c.TileMatrixSetLink,function(a){return ob(d,function(b){return b.Identifier==a.TileMatrixSet}).SupportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/,"$1:$3")==b.projection}):sb(c.TileMatrixSetLink,function(a){return a.TileMatrixSet==b.matrixSet}):0;0>e&&(e=0);f=c.TileMatrixSetLink[e].TileMatrixSet;
+var g=c.Format[0];"format"in b&&(g=b.format);e=sb(c.Style,function(a){return"style"in b?a.Title==b.style:a.isDefault});0>e&&(e=0);e=c.Style[e].Identifier;var h={};"Dimension"in c&&c.Dimension.forEach(function(a){var b=a.Identifier,c=a.Default;void 0===c&&(c=a.Value[0]);h[b]=c});var l=ob(a.Contents.TileMatrixSet,function(a){return a.Identifier==f}),m;m="projection"in b?yc(b.projection):yc(l.SupportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/,"$1:$3"));var n=c.WGS84BoundingBox,p,q;void 0!==n&&
+(q=yc("EPSG:4326").H(),q=n[0]==q[0]&&n[2]==q[2],p=Sc(n,"EPSG:4326",m),(n=m.H())&&(Ub(n,p)||(p=void 0)));var l=gw(l,p),r=[];p=b.requestEncoding;p=void 0!==p?p:"";if("OperationsMetadata"in a&&"GetTile"in a.OperationsMetadata)for(var n=a.OperationsMetadata.GetTile.DCP.HTTP.Get,u=0,x=n.length;u<x;++u){var v=ob(n[u].Constraint,function(a){return"GetEncoding"==a.name}).AllowedValues.Value;""===p&&(p=v[0]);if("KVP"===p)jb(v,"KVP")&&r.push(n[u].href);else break}0===r.length&&(p="REST",c.ResourceURL.forEach(function(a){"tile"===
+a.resourceType&&(g=a.format,r.push(a.template))}));return{urls:r,layer:b.layer,matrixSet:f,format:g,projection:m,requestEncoding:p,tileGrid:l,style:e,dimensions:h,wrapX:q}},OPENLAYERS);t("ol.source.XYZ",rv,OPENLAYERS);t("ol.source.Zoomify",iw,OPENLAYERS);lh.prototype.vectorContext=lh.prototype.vectorContext;lh.prototype.frameState=lh.prototype.frameState;lh.prototype.context=lh.prototype.context;lh.prototype.glContext=lh.prototype.glContext;hk.prototype.get=hk.prototype.get;
+hk.prototype.getExtent=hk.prototype.H;hk.prototype.getGeometry=hk.prototype.W;hk.prototype.getProperties=hk.prototype.Nm;hk.prototype.getType=hk.prototype.X;t("ol.render.VectorContext",kh,OPENLAYERS);Cm.prototype.setStyle=Cm.prototype.sd;Cm.prototype.drawGeometry=Cm.prototype.sc;Cm.prototype.drawFeature=Cm.prototype.Ye;yj.prototype.drawCircle=yj.prototype.Rd;yj.prototype.setStyle=yj.prototype.sd;yj.prototype.drawGeometry=yj.prototype.sc;yj.prototype.drawFeature=yj.prototype.Ye;
+t("ol.proj.common.add",bj,OPENLAYERS);t("ol.proj.METERS_PER_UNIT",uc,OPENLAYERS);t("ol.proj.Projection",vc,OPENLAYERS);vc.prototype.getCode=vc.prototype.Sj;vc.prototype.getExtent=vc.prototype.H;vc.prototype.getUnits=vc.prototype.wb;vc.prototype.getMetersPerUnit=vc.prototype.$b;vc.prototype.getWorldExtent=vc.prototype.Ek;vc.prototype.isGlobal=vc.prototype.pl;vc.prototype.setGlobal=vc.prototype.ep;vc.prototype.setExtent=vc.prototype.Mm;vc.prototype.setWorldExtent=vc.prototype.mp;
+vc.prototype.setGetPointResolution=vc.prototype.cp;vc.prototype.getPointResolution=vc.prototype.getPointResolution;t("ol.proj.setProj4",function(a){xc=a},OPENLAYERS);t("ol.proj.addEquivalentProjections",zc,OPENLAYERS);t("ol.proj.addProjection",Lc,OPENLAYERS);t("ol.proj.addCoordinateTransforms",Ac,OPENLAYERS);t("ol.proj.fromLonLat",function(a,b){return Rc(a,"EPSG:4326",void 0!==b?b:"EPSG:3857")},OPENLAYERS);t("ol.proj.toLonLat",function(a,b){return Rc(a,void 0!==b?b:"EPSG:3857","EPSG:4326")},OPENLAYERS);
+t("ol.proj.get",yc,OPENLAYERS);t("ol.proj.equivalent",Oc,OPENLAYERS);t("ol.proj.getTransform",Pc,OPENLAYERS);t("ol.proj.transform",Rc,OPENLAYERS);t("ol.proj.transformExtent",Sc,OPENLAYERS);t("ol.layer.Heatmap",V,OPENLAYERS);V.prototype.getBlur=V.prototype.zg;V.prototype.getGradient=V.prototype.Gg;V.prototype.getRadius=V.prototype.ph;V.prototype.setBlur=V.prototype.di;V.prototype.setGradient=V.prototype.ii;V.prototype.setRadius=V.prototype.qh;t("ol.layer.Image",cj,OPENLAYERS);
+cj.prototype.getSource=cj.prototype.ha;t("ol.layer.Layer",mh,OPENLAYERS);mh.prototype.getSource=mh.prototype.ha;mh.prototype.setMap=mh.prototype.setMap;mh.prototype.setSource=mh.prototype.Fc;t("ol.layer.Base",ih,OPENLAYERS);ih.prototype.getExtent=ih.prototype.H;ih.prototype.getMaxResolution=ih.prototype.Nb;ih.prototype.getMinResolution=ih.prototype.Ob;ih.prototype.getOpacity=ih.prototype.Pb;ih.prototype.getVisible=ih.prototype.xb;ih.prototype.getZIndex=ih.prototype.Qb;ih.prototype.setExtent=ih.prototype.fc;
+ih.prototype.setMaxResolution=ih.prototype.nc;ih.prototype.setMinResolution=ih.prototype.oc;ih.prototype.setOpacity=ih.prototype.gc;ih.prototype.setVisible=ih.prototype.hc;ih.prototype.setZIndex=ih.prototype.ic;t("ol.layer.Group",Ti,OPENLAYERS);Ti.prototype.getLayers=Ti.prototype.Tc;Ti.prototype.setLayers=Ti.prototype.oh;t("ol.layer.Tile",dj,OPENLAYERS);dj.prototype.getPreload=dj.prototype.f;dj.prototype.getSource=dj.prototype.ha;dj.prototype.setPreload=dj.prototype.l;
+dj.prototype.getUseInterimTilesOnError=dj.prototype.c;dj.prototype.setUseInterimTilesOnError=dj.prototype.A;t("ol.layer.Vector",G,OPENLAYERS);G.prototype.getSource=G.prototype.ha;G.prototype.getStyle=G.prototype.C;G.prototype.getStyleFunction=G.prototype.D;G.prototype.setStyle=G.prototype.l;t("ol.layer.VectorTile",I,OPENLAYERS);I.prototype.getPreload=I.prototype.f;I.prototype.getUseInterimTilesOnError=I.prototype.c;I.prototype.setPreload=I.prototype.Y;I.prototype.setUseInterimTilesOnError=I.prototype.ia;
+t("ol.interaction.DoubleClickZoom",Zh,OPENLAYERS);t("ol.interaction.DoubleClickZoom.handleEvent",$h,OPENLAYERS);t("ol.interaction.DragAndDrop",hu,OPENLAYERS);t("ol.interaction.DragAndDrop.handleEvent",qc,OPENLAYERS);ku.prototype.features=ku.prototype.features;ku.prototype.file=ku.prototype.file;ku.prototype.projection=ku.prototype.projection;xi.prototype.coordinate=xi.prototype.coordinate;xi.prototype.mapBrowserEvent=xi.prototype.mapBrowserEvent;t("ol.interaction.DragBox",yi,OPENLAYERS);
+yi.prototype.getGeometry=yi.prototype.W;t("ol.interaction.DragPan",mi,OPENLAYERS);t("ol.interaction.DragRotateAndZoom",mu,OPENLAYERS);t("ol.interaction.DragRotate",qi,OPENLAYERS);t("ol.interaction.DragZoom",Di,OPENLAYERS);qu.prototype.feature=qu.prototype.feature;t("ol.interaction.Draw",ru,OPENLAYERS);t("ol.interaction.Draw.handleEvent",tu,OPENLAYERS);ru.prototype.removeLastPoint=ru.prototype.Qo;ru.prototype.finishDrawing=ru.prototype.jd;ru.prototype.extend=ru.prototype.rm;
+t("ol.interaction.Draw.createRegularPolygon",function(a,b){return function(c,d){var e=c[0],f=c[1],g=Math.sqrt(Hb(e,f)),h=d?d:Pd(new Vt(e),a);Qd(h,e,g,b?b:Math.atan((f[1]-e[1])/(f[0]-e[0])));return h}},OPENLAYERS);t("ol.interaction.Interaction",Vh,OPENLAYERS);Vh.prototype.getActive=Vh.prototype.f;Vh.prototype.getMap=Vh.prototype.l;Vh.prototype.setActive=Vh.prototype.i;t("ol.interaction.defaults",Si,OPENLAYERS);t("ol.interaction.KeyboardPan",Ei,OPENLAYERS);
+t("ol.interaction.KeyboardPan.handleEvent",Fi,OPENLAYERS);t("ol.interaction.KeyboardZoom",Gi,OPENLAYERS);t("ol.interaction.KeyboardZoom.handleEvent",Hi,OPENLAYERS);Hu.prototype.features=Hu.prototype.features;Hu.prototype.mapBrowserEvent=Hu.prototype.mapBrowserEvent;t("ol.interaction.Modify",Iu,OPENLAYERS);t("ol.interaction.Modify.handleEvent",Lu,OPENLAYERS);Iu.prototype.removePoint=Iu.prototype.ai;t("ol.interaction.MouseWheelZoom",Ii,OPENLAYERS);t("ol.interaction.MouseWheelZoom.handleEvent",Ji,OPENLAYERS);
+Ii.prototype.setMouseAnchor=Ii.prototype.D;t("ol.interaction.PinchRotate",Ki,OPENLAYERS);t("ol.interaction.PinchZoom",Oi,OPENLAYERS);t("ol.interaction.Pointer",ji,OPENLAYERS);t("ol.interaction.Pointer.handleEvent",ki,OPENLAYERS);Vu.prototype.selected=Vu.prototype.selected;Vu.prototype.deselected=Vu.prototype.deselected;Vu.prototype.mapBrowserEvent=Vu.prototype.mapBrowserEvent;t("ol.interaction.Select",Wu,OPENLAYERS);Wu.prototype.getFeatures=Wu.prototype.Bm;Wu.prototype.getLayer=Wu.prototype.Cm;
+t("ol.interaction.Select.handleEvent",Xu,OPENLAYERS);Wu.prototype.setMap=Wu.prototype.setMap;t("ol.interaction.Snap",Zu,OPENLAYERS);Zu.prototype.addFeature=Zu.prototype.rb;Zu.prototype.removeFeature=Zu.prototype.nb;cv.prototype.features=cv.prototype.features;cv.prototype.coordinate=cv.prototype.coordinate;t("ol.interaction.Translate",dv,OPENLAYERS);t("ol.geom.Circle",Vt,OPENLAYERS);Vt.prototype.clone=Vt.prototype.clone;Vt.prototype.getCenter=Vt.prototype.rd;Vt.prototype.getRadius=Vt.prototype.wf;
+Vt.prototype.getType=Vt.prototype.X;Vt.prototype.intersectsExtent=Vt.prototype.Ka;Vt.prototype.setCenter=Vt.prototype.jm;Vt.prototype.setCenterAndRadius=Vt.prototype.Vf;Vt.prototype.setRadius=Vt.prototype.km;Vt.prototype.transform=Vt.prototype.jb;t("ol.geom.Geometry",Tc,OPENLAYERS);Tc.prototype.getClosestPoint=Tc.prototype.vb;Tc.prototype.getExtent=Tc.prototype.H;Tc.prototype.rotate=Tc.prototype.rotate;Tc.prototype.simplify=Tc.prototype.Bb;Tc.prototype.transform=Tc.prototype.jb;
+t("ol.geom.GeometryCollection",Ln,OPENLAYERS);Ln.prototype.clone=Ln.prototype.clone;Ln.prototype.getGeometries=Ln.prototype.ff;Ln.prototype.getType=Ln.prototype.X;Ln.prototype.intersectsExtent=Ln.prototype.Ka;Ln.prototype.setGeometries=Ln.prototype.hi;Ln.prototype.applyTransform=Ln.prototype.rc;Ln.prototype.translate=Ln.prototype.Sc;t("ol.geom.LinearRing",zd,OPENLAYERS);zd.prototype.clone=zd.prototype.clone;zd.prototype.getArea=zd.prototype.nm;zd.prototype.getCoordinates=zd.prototype.Z;
+zd.prototype.getType=zd.prototype.X;zd.prototype.setCoordinates=zd.prototype.pa;t("ol.geom.LineString",R,OPENLAYERS);R.prototype.appendCoordinate=R.prototype.wj;R.prototype.clone=R.prototype.clone;R.prototype.forEachSegment=R.prototype.Lj;R.prototype.getCoordinateAtM=R.prototype.lm;R.prototype.getCoordinates=R.prototype.Z;R.prototype.getCoordinateAt=R.prototype.Bg;R.prototype.getLength=R.prototype.mm;R.prototype.getType=R.prototype.X;R.prototype.intersectsExtent=R.prototype.Ka;
+R.prototype.setCoordinates=R.prototype.pa;t("ol.geom.MultiLineString",S,OPENLAYERS);S.prototype.appendLineString=S.prototype.xj;S.prototype.clone=S.prototype.clone;S.prototype.getCoordinateAtM=S.prototype.om;S.prototype.getCoordinates=S.prototype.Z;S.prototype.getLineString=S.prototype.fk;S.prototype.getLineStrings=S.prototype.md;S.prototype.getType=S.prototype.X;S.prototype.intersectsExtent=S.prototype.Ka;S.prototype.setCoordinates=S.prototype.pa;t("ol.geom.MultiPoint",Bn,OPENLAYERS);
+Bn.prototype.appendPoint=Bn.prototype.zj;Bn.prototype.clone=Bn.prototype.clone;Bn.prototype.getCoordinates=Bn.prototype.Z;Bn.prototype.getPoint=Bn.prototype.rk;Bn.prototype.getPoints=Bn.prototype.je;Bn.prototype.getType=Bn.prototype.X;Bn.prototype.intersectsExtent=Bn.prototype.Ka;Bn.prototype.setCoordinates=Bn.prototype.pa;t("ol.geom.MultiPolygon",T,OPENLAYERS);T.prototype.appendPolygon=T.prototype.Aj;T.prototype.clone=T.prototype.clone;T.prototype.getArea=T.prototype.pm;
+T.prototype.getCoordinates=T.prototype.Z;T.prototype.getInteriorPoints=T.prototype.ck;T.prototype.getPolygon=T.prototype.tk;T.prototype.getPolygons=T.prototype.Wd;T.prototype.getType=T.prototype.X;T.prototype.intersectsExtent=T.prototype.Ka;T.prototype.setCoordinates=T.prototype.pa;t("ol.geom.Point",C,OPENLAYERS);C.prototype.clone=C.prototype.clone;C.prototype.getCoordinates=C.prototype.Z;C.prototype.getType=C.prototype.X;C.prototype.intersectsExtent=C.prototype.Ka;C.prototype.setCoordinates=C.prototype.pa;
+t("ol.geom.Polygon",E,OPENLAYERS);E.prototype.appendLinearRing=E.prototype.yj;E.prototype.clone=E.prototype.clone;E.prototype.getArea=E.prototype.qm;E.prototype.getCoordinates=E.prototype.Z;E.prototype.getInteriorPoint=E.prototype.bk;E.prototype.getLinearRingCount=E.prototype.gk;E.prototype.getLinearRing=E.prototype.Hg;E.prototype.getLinearRings=E.prototype.Vd;E.prototype.getType=E.prototype.X;E.prototype.intersectsExtent=E.prototype.Ka;E.prototype.setCoordinates=E.prototype.pa;
+t("ol.geom.Polygon.circular",Nd,OPENLAYERS);t("ol.geom.Polygon.fromExtent",Od,OPENLAYERS);t("ol.geom.Polygon.fromCircle",Pd,OPENLAYERS);t("ol.geom.SimpleGeometry",hd,OPENLAYERS);hd.prototype.getFirstCoordinate=hd.prototype.Ib;hd.prototype.getLastCoordinate=hd.prototype.Jb;hd.prototype.getLayout=hd.prototype.Kb;hd.prototype.applyTransform=hd.prototype.rc;hd.prototype.translate=hd.prototype.Sc;t("ol.format.EsriJSON",En,OPENLAYERS);En.prototype.readFeature=En.prototype.Rb;En.prototype.readFeatures=En.prototype.Fa;
+En.prototype.readGeometry=En.prototype.Vc;En.prototype.readProjection=En.prototype.Oa;En.prototype.writeGeometry=En.prototype.Zc;En.prototype.writeGeometryObject=En.prototype.Ke;En.prototype.writeFeature=En.prototype.Dd;En.prototype.writeFeatureObject=En.prototype.Yc;En.prototype.writeFeatures=En.prototype.Xb;En.prototype.writeFeaturesObject=En.prototype.Ie;t("ol.format.Feature",rn,OPENLAYERS);t("ol.format.GeoJSON",Pn,OPENLAYERS);Pn.prototype.readFeature=Pn.prototype.Rb;
+Pn.prototype.readFeatures=Pn.prototype.Fa;Pn.prototype.readGeometry=Pn.prototype.Vc;Pn.prototype.readProjection=Pn.prototype.Oa;Pn.prototype.writeFeature=Pn.prototype.Dd;Pn.prototype.writeFeatureObject=Pn.prototype.Yc;Pn.prototype.writeFeatures=Pn.prototype.Xb;Pn.prototype.writeFeaturesObject=Pn.prototype.Ie;Pn.prototype.writeGeometry=Pn.prototype.Zc;Pn.prototype.writeGeometryObject=Pn.prototype.Ke;t("ol.format.GPX",uo,OPENLAYERS);uo.prototype.readFeature=uo.prototype.Rb;
+uo.prototype.readFeatures=uo.prototype.Fa;uo.prototype.readProjection=uo.prototype.Oa;uo.prototype.writeFeatures=uo.prototype.Xb;uo.prototype.writeFeaturesNode=uo.prototype.a;t("ol.format.IGC",dp,OPENLAYERS);dp.prototype.readFeature=dp.prototype.Rb;dp.prototype.readFeatures=dp.prototype.Fa;dp.prototype.readProjection=dp.prototype.Oa;t("ol.format.KML",Hp,OPENLAYERS);Hp.prototype.readFeature=Hp.prototype.Rb;Hp.prototype.readFeatures=Hp.prototype.Fa;Hp.prototype.readName=Hp.prototype.Fo;
+Hp.prototype.readNetworkLinks=Hp.prototype.Go;Hp.prototype.readProjection=Hp.prototype.Oa;Hp.prototype.writeFeatures=Hp.prototype.Xb;Hp.prototype.writeFeaturesNode=Hp.prototype.a;t("ol.format.MVT",wr,OPENLAYERS);wr.prototype.readFeatures=wr.prototype.Fa;wr.prototype.readProjection=wr.prototype.Oa;wr.prototype.setLayers=wr.prototype.c;t("ol.format.OSMXML",Sr,OPENLAYERS);Sr.prototype.readFeatures=Sr.prototype.Fa;Sr.prototype.readProjection=Sr.prototype.Oa;t("ol.format.Polyline",qs,OPENLAYERS);
+t("ol.format.Polyline.encodeDeltas",rs,OPENLAYERS);t("ol.format.Polyline.decodeDeltas",ts,OPENLAYERS);t("ol.format.Polyline.encodeFloats",ss,OPENLAYERS);t("ol.format.Polyline.decodeFloats",us,OPENLAYERS);qs.prototype.readFeature=qs.prototype.Rb;qs.prototype.readFeatures=qs.prototype.Fa;qs.prototype.readGeometry=qs.prototype.Vc;qs.prototype.readProjection=qs.prototype.Oa;qs.prototype.writeGeometry=qs.prototype.Zc;t("ol.format.TopoJSON",ws,OPENLAYERS);ws.prototype.readFeatures=ws.prototype.Fa;
+ws.prototype.readProjection=ws.prototype.Oa;t("ol.format.WFS",Cs,OPENLAYERS);Cs.prototype.readFeatures=Cs.prototype.Fa;Cs.prototype.readTransactionResponse=Cs.prototype.o;Cs.prototype.readFeatureCollectionMetadata=Cs.prototype.l;Cs.prototype.writeGetFeature=Cs.prototype.j;Cs.prototype.writeTransaction=Cs.prototype.U;Cs.prototype.readProjection=Cs.prototype.Oa;t("ol.format.WKT",Ts,OPENLAYERS);Ts.prototype.readFeature=Ts.prototype.Rb;Ts.prototype.readFeatures=Ts.prototype.Fa;
+Ts.prototype.readGeometry=Ts.prototype.Vc;Ts.prototype.writeFeature=Ts.prototype.Dd;Ts.prototype.writeFeatures=Ts.prototype.Xb;Ts.prototype.writeGeometry=Ts.prototype.Zc;t("ol.format.WMSCapabilities",jt,OPENLAYERS);jt.prototype.read=jt.prototype.read;t("ol.format.WMSGetFeatureInfo",Gt,OPENLAYERS);Gt.prototype.readFeatures=Gt.prototype.Fa;t("ol.format.WMTSCapabilities",Ht,OPENLAYERS);Ht.prototype.read=Ht.prototype.read;t("ol.format.ogc.filter.and",yr,OPENLAYERS);
+t("ol.format.ogc.filter.or",function(a,b){return new Fr(a,b)},OPENLAYERS);t("ol.format.ogc.filter.not",function(a){return new Gr(a)},OPENLAYERS);t("ol.format.ogc.filter.bbox",Ar,OPENLAYERS);t("ol.format.ogc.filter.equalTo",function(a,b,c){return new Jr(a,b,c)},OPENLAYERS);t("ol.format.ogc.filter.notEqualTo",function(a,b,c){return new Kr(a,b,c)},OPENLAYERS);t("ol.format.ogc.filter.lessThan",function(a,b){return new Lr(a,b)},OPENLAYERS);
+t("ol.format.ogc.filter.lessThanOrEqualTo",function(a,b){return new Mr(a,b)},OPENLAYERS);t("ol.format.ogc.filter.greaterThan",function(a,b){return new Nr(a,b)},OPENLAYERS);t("ol.format.ogc.filter.greaterThanOrEqualTo",function(a,b){return new Or(a,b)},OPENLAYERS);t("ol.format.ogc.filter.isNull",function(a){return new Pr(a)},OPENLAYERS);t("ol.format.ogc.filter.between",function(a,b,c){return new Qr(a,b,c)},OPENLAYERS);
+t("ol.format.ogc.filter.like",function(a,b,c,d,e,f){return new Rr(a,b,c,d,e,f)},OPENLAYERS);t("ol.format.ogc.filter.Filter",Cr,OPENLAYERS);t("ol.format.ogc.filter.And",zr,OPENLAYERS);t("ol.format.ogc.filter.Or",Fr,OPENLAYERS);t("ol.format.ogc.filter.Not",Gr,OPENLAYERS);t("ol.format.ogc.filter.Bbox",Br,OPENLAYERS);t("ol.format.ogc.filter.Comparison",Hr,OPENLAYERS);t("ol.format.ogc.filter.ComparisonBinary",Ir,OPENLAYERS);t("ol.format.ogc.filter.EqualTo",Jr,OPENLAYERS);
+t("ol.format.ogc.filter.NotEqualTo",Kr,OPENLAYERS);t("ol.format.ogc.filter.LessThan",Lr,OPENLAYERS);t("ol.format.ogc.filter.LessThanOrEqualTo",Mr,OPENLAYERS);t("ol.format.ogc.filter.GreaterThan",Nr,OPENLAYERS);t("ol.format.ogc.filter.GreaterThanOrEqualTo",Or,OPENLAYERS);t("ol.format.ogc.filter.IsNull",Pr,OPENLAYERS);t("ol.format.ogc.filter.IsBetween",Qr,OPENLAYERS);t("ol.format.ogc.filter.IsLike",Rr,OPENLAYERS);t("ol.format.GML2",ko,OPENLAYERS);t("ol.format.GML3",lo,OPENLAYERS);
+lo.prototype.writeGeometryNode=lo.prototype.s;lo.prototype.writeFeatures=lo.prototype.Xb;lo.prototype.writeFeaturesNode=lo.prototype.a;t("ol.format.GML",lo,OPENLAYERS);lo.prototype.writeFeatures=lo.prototype.Xb;lo.prototype.writeFeaturesNode=lo.prototype.a;Xn.prototype.readFeatures=Xn.prototype.Fa;t("ol.events.condition.altKeyOnly",function(a){a=a.originalEvent;return a.altKey&&!(a.metaKey||a.ctrlKey)&&!a.shiftKey},OPENLAYERS);t("ol.events.condition.altShiftKeysOnly",ai,OPENLAYERS);
+t("ol.events.condition.always",qc,OPENLAYERS);t("ol.events.condition.click",function(a){return a.type==Zg},OPENLAYERS);t("ol.events.condition.never",rc,OPENLAYERS);t("ol.events.condition.pointerMove",ci,OPENLAYERS);t("ol.events.condition.singleClick",di,OPENLAYERS);t("ol.events.condition.doubleClick",function(a){return a.type==$g},OPENLAYERS);t("ol.events.condition.noModifierKeys",ei,OPENLAYERS);
+t("ol.events.condition.platformModifierKeyOnly",function(a){a=a.originalEvent;return!a.altKey&&(fg?a.metaKey:a.ctrlKey)&&!a.shiftKey},OPENLAYERS);t("ol.events.condition.shiftKeyOnly",fi,OPENLAYERS);t("ol.events.condition.targetNotEditable",gi,OPENLAYERS);t("ol.events.condition.mouseOnly",hi,OPENLAYERS);t("ol.events.condition.primaryAction",ii,OPENLAYERS);Wa.prototype.type=Wa.prototype.type;Wa.prototype.target=Wa.prototype.target;Wa.prototype.preventDefault=Wa.prototype.preventDefault;
+Wa.prototype.stopPropagation=Wa.prototype.stopPropagation;t("ol.control.Attribution",Ef,OPENLAYERS);t("ol.control.Attribution.render",Ff,OPENLAYERS);Ef.prototype.getCollapsible=Ef.prototype.$l;Ef.prototype.setCollapsible=Ef.prototype.cm;Ef.prototype.setCollapsed=Ef.prototype.bm;Ef.prototype.getCollapsed=Ef.prototype.Zl;t("ol.control.Control",Xe,OPENLAYERS);Xe.prototype.getMap=Xe.prototype.i;Xe.prototype.setMap=Xe.prototype.setMap;Xe.prototype.setTarget=Xe.prototype.c;t("ol.control.defaults",Kf,OPENLAYERS);
+t("ol.control.FullScreen",Lf,OPENLAYERS);t("ol.control.MousePosition",Qf,OPENLAYERS);t("ol.control.MousePosition.render",Rf,OPENLAYERS);Qf.prototype.getCoordinateFormat=Qf.prototype.Cg;Qf.prototype.getProjection=Qf.prototype.hh;Qf.prototype.setCoordinateFormat=Qf.prototype.ei;Qf.prototype.setProjection=Qf.prototype.ih;t("ol.control.OverviewMap",an,OPENLAYERS);t("ol.control.OverviewMap.render",bn,OPENLAYERS);an.prototype.getCollapsible=an.prototype.fm;an.prototype.setCollapsible=an.prototype.im;
+an.prototype.setCollapsed=an.prototype.hm;an.prototype.getCollapsed=an.prototype.em;an.prototype.getOverviewMap=an.prototype.pk;t("ol.control.Rotate",Hf,OPENLAYERS);t("ol.control.Rotate.render",If,OPENLAYERS);t("ol.control.ScaleLine",fn,OPENLAYERS);fn.prototype.getUnits=fn.prototype.wb;t("ol.control.ScaleLine.render",gn,OPENLAYERS);fn.prototype.setUnits=fn.prototype.D;t("ol.control.Zoom",Jf,OPENLAYERS);t("ol.control.ZoomSlider",kn,OPENLAYERS);t("ol.control.ZoomSlider.render",mn,OPENLAYERS);
+t("ol.control.ZoomToExtent",pn,OPENLAYERS);t("ol.color.asArray",te,OPENLAYERS);t("ol.color.asString",ve,OPENLAYERS);ke.prototype.type=ke.prototype.type;ke.prototype.target=ke.prototype.target;ke.prototype.preventDefault=ke.prototype.preventDefault;ke.prototype.stopPropagation=ke.prototype.stopPropagation;eb.prototype.changed=eb.prototype.u;eb.prototype.dispatchEvent=eb.prototype.b;eb.prototype.getRevision=eb.prototype.K;eb.prototype.on=eb.prototype.I;eb.prototype.once=eb.prototype.L;
+eb.prototype.un=eb.prototype.J;eb.prototype.unByKey=eb.prototype.M;le.prototype.get=le.prototype.get;le.prototype.getKeys=le.prototype.N;le.prototype.getProperties=le.prototype.O;le.prototype.set=le.prototype.set;le.prototype.setProperties=le.prototype.G;le.prototype.unset=le.prototype.P;le.prototype.changed=le.prototype.u;le.prototype.dispatchEvent=le.prototype.b;le.prototype.getRevision=le.prototype.K;le.prototype.on=le.prototype.I;le.prototype.once=le.prototype.L;le.prototype.un=le.prototype.J;
+le.prototype.unByKey=le.prototype.M;qn.prototype.get=qn.prototype.get;qn.prototype.getKeys=qn.prototype.N;qn.prototype.getProperties=qn.prototype.O;qn.prototype.set=qn.prototype.set;qn.prototype.setProperties=qn.prototype.G;qn.prototype.unset=qn.prototype.P;qn.prototype.changed=qn.prototype.u;qn.prototype.dispatchEvent=qn.prototype.b;qn.prototype.getRevision=qn.prototype.K;qn.prototype.on=qn.prototype.I;qn.prototype.once=qn.prototype.L;qn.prototype.un=qn.prototype.J;qn.prototype.unByKey=qn.prototype.M;
+Ik.prototype.get=Ik.prototype.get;Ik.prototype.getKeys=Ik.prototype.N;Ik.prototype.getProperties=Ik.prototype.O;Ik.prototype.set=Ik.prototype.set;Ik.prototype.setProperties=Ik.prototype.G;Ik.prototype.unset=Ik.prototype.P;Ik.prototype.changed=Ik.prototype.u;Ik.prototype.dispatchEvent=Ik.prototype.b;Ik.prototype.getRevision=Ik.prototype.K;Ik.prototype.on=Ik.prototype.I;Ik.prototype.once=Ik.prototype.L;Ik.prototype.un=Ik.prototype.J;Ik.prototype.unByKey=Ik.prototype.M;Ut.prototype.get=Ut.prototype.get;
+Ut.prototype.getKeys=Ut.prototype.N;Ut.prototype.getProperties=Ut.prototype.O;Ut.prototype.set=Ut.prototype.set;Ut.prototype.setProperties=Ut.prototype.G;Ut.prototype.unset=Ut.prototype.P;Ut.prototype.changed=Ut.prototype.u;Ut.prototype.dispatchEvent=Ut.prototype.b;Ut.prototype.getRevision=Ut.prototype.K;Ut.prototype.on=Ut.prototype.I;Ut.prototype.once=Ut.prototype.L;Ut.prototype.un=Ut.prototype.J;Ut.prototype.unByKey=Ut.prototype.M;fu.prototype.getTileCoord=fu.prototype.i;Q.prototype.get=Q.prototype.get;
+Q.prototype.getKeys=Q.prototype.N;Q.prototype.getProperties=Q.prototype.O;Q.prototype.set=Q.prototype.set;Q.prototype.setProperties=Q.prototype.G;Q.prototype.unset=Q.prototype.P;Q.prototype.changed=Q.prototype.u;Q.prototype.dispatchEvent=Q.prototype.b;Q.prototype.getRevision=Q.prototype.K;Q.prototype.on=Q.prototype.I;Q.prototype.once=Q.prototype.L;Q.prototype.un=Q.prototype.J;Q.prototype.unByKey=Q.prototype.M;We.prototype.type=We.prototype.type;We.prototype.target=We.prototype.target;
+We.prototype.preventDefault=We.prototype.preventDefault;We.prototype.stopPropagation=We.prototype.stopPropagation;Vg.prototype.map=Vg.prototype.map;Vg.prototype.frameState=Vg.prototype.frameState;Vg.prototype.type=Vg.prototype.type;Vg.prototype.target=Vg.prototype.target;Vg.prototype.preventDefault=Vg.prototype.preventDefault;Vg.prototype.stopPropagation=Vg.prototype.stopPropagation;Wg.prototype.originalEvent=Wg.prototype.originalEvent;Wg.prototype.pixel=Wg.prototype.pixel;
+Wg.prototype.coordinate=Wg.prototype.coordinate;Wg.prototype.dragging=Wg.prototype.dragging;Wg.prototype.preventDefault=Wg.prototype.preventDefault;Wg.prototype.stopPropagation=Wg.prototype.stopPropagation;Wg.prototype.map=Wg.prototype.map;Wg.prototype.frameState=Wg.prototype.frameState;Wg.prototype.type=Wg.prototype.type;Wg.prototype.target=Wg.prototype.target;db.prototype.type=db.prototype.type;db.prototype.target=db.prototype.target;db.prototype.preventDefault=db.prototype.preventDefault;
+db.prototype.stopPropagation=db.prototype.stopPropagation;Xm.prototype.get=Xm.prototype.get;Xm.prototype.getKeys=Xm.prototype.N;Xm.prototype.getProperties=Xm.prototype.O;Xm.prototype.set=Xm.prototype.set;Xm.prototype.setProperties=Xm.prototype.G;Xm.prototype.unset=Xm.prototype.P;Xm.prototype.changed=Xm.prototype.u;Xm.prototype.dispatchEvent=Xm.prototype.b;Xm.prototype.getRevision=Xm.prototype.K;Xm.prototype.on=Xm.prototype.I;Xm.prototype.once=Xm.prototype.L;Xm.prototype.un=Xm.prototype.J;
+Xm.prototype.unByKey=Xm.prototype.M;Kk.prototype.getTileCoord=Kk.prototype.i;Rd.prototype.get=Rd.prototype.get;Rd.prototype.getKeys=Rd.prototype.N;Rd.prototype.getProperties=Rd.prototype.O;Rd.prototype.set=Rd.prototype.set;Rd.prototype.setProperties=Rd.prototype.G;Rd.prototype.unset=Rd.prototype.P;Rd.prototype.changed=Rd.prototype.u;Rd.prototype.dispatchEvent=Rd.prototype.b;Rd.prototype.getRevision=Rd.prototype.K;Rd.prototype.on=Rd.prototype.I;Rd.prototype.once=Rd.prototype.L;Rd.prototype.un=Rd.prototype.J;
+Rd.prototype.unByKey=Rd.prototype.M;fw.prototype.forEachTileCoord=fw.prototype.yg;fw.prototype.getMaxZoom=fw.prototype.Ig;fw.prototype.getMinZoom=fw.prototype.Jg;fw.prototype.getOrigin=fw.prototype.Ia;fw.prototype.getResolution=fw.prototype.$;fw.prototype.getResolutions=fw.prototype.Kh;fw.prototype.getTileCoordExtent=fw.prototype.Ea;fw.prototype.getTileCoordForCoordAndResolution=fw.prototype.Zd;fw.prototype.getTileCoordForCoordAndZ=fw.prototype.qd;fw.prototype.getTileSize=fw.prototype.Ja;
+fw.prototype.getZForResolution=fw.prototype.Lb;qj.prototype.getOpacity=qj.prototype.qe;qj.prototype.getRotateWithView=qj.prototype.Xd;qj.prototype.getRotation=qj.prototype.re;qj.prototype.getScale=qj.prototype.se;qj.prototype.getSnapToPixel=qj.prototype.Yd;qj.prototype.setOpacity=qj.prototype.te;qj.prototype.setRotation=qj.prototype.ue;qj.prototype.setScale=qj.prototype.ve;Dh.prototype.getOpacity=Dh.prototype.qe;Dh.prototype.getRotateWithView=Dh.prototype.Xd;Dh.prototype.getRotation=Dh.prototype.re;
+Dh.prototype.getScale=Dh.prototype.se;Dh.prototype.getSnapToPixel=Dh.prototype.Yd;Dh.prototype.setOpacity=Dh.prototype.te;Dh.prototype.setRotation=Dh.prototype.ue;Dh.prototype.setScale=Dh.prototype.ve;ow.prototype.getOpacity=ow.prototype.qe;ow.prototype.getRotateWithView=ow.prototype.Xd;ow.prototype.getRotation=ow.prototype.re;ow.prototype.getScale=ow.prototype.se;ow.prototype.getSnapToPixel=ow.prototype.Yd;ow.prototype.setOpacity=ow.prototype.te;ow.prototype.setRotation=ow.prototype.ue;
+ow.prototype.setScale=ow.prototype.ve;jf.prototype.get=jf.prototype.get;jf.prototype.getKeys=jf.prototype.N;jf.prototype.getProperties=jf.prototype.O;jf.prototype.set=jf.prototype.set;jf.prototype.setProperties=jf.prototype.G;jf.prototype.unset=jf.prototype.P;jf.prototype.changed=jf.prototype.u;jf.prototype.dispatchEvent=jf.prototype.b;jf.prototype.getRevision=jf.prototype.K;jf.prototype.on=jf.prototype.I;jf.prototype.once=jf.prototype.L;jf.prototype.un=jf.prototype.J;jf.prototype.unByKey=jf.prototype.M;
+zf.prototype.getAttributions=zf.prototype.wa;zf.prototype.getLogo=zf.prototype.ua;zf.prototype.getProjection=zf.prototype.xa;zf.prototype.getState=zf.prototype.V;zf.prototype.refresh=zf.prototype.sa;zf.prototype.setAttributions=zf.prototype.oa;zf.prototype.get=zf.prototype.get;zf.prototype.getKeys=zf.prototype.N;zf.prototype.getProperties=zf.prototype.O;zf.prototype.set=zf.prototype.set;zf.prototype.setProperties=zf.prototype.G;zf.prototype.unset=zf.prototype.P;zf.prototype.changed=zf.prototype.u;
+zf.prototype.dispatchEvent=zf.prototype.b;zf.prototype.getRevision=zf.prototype.K;zf.prototype.on=zf.prototype.I;zf.prototype.once=zf.prototype.L;zf.prototype.un=zf.prototype.J;zf.prototype.unByKey=zf.prototype.M;Jl.prototype.getTileGrid=Jl.prototype.Na;Jl.prototype.refresh=Jl.prototype.sa;Jl.prototype.getAttributions=Jl.prototype.wa;Jl.prototype.getLogo=Jl.prototype.ua;Jl.prototype.getProjection=Jl.prototype.xa;Jl.prototype.getState=Jl.prototype.V;Jl.prototype.setAttributions=Jl.prototype.oa;
+Jl.prototype.get=Jl.prototype.get;Jl.prototype.getKeys=Jl.prototype.N;Jl.prototype.getProperties=Jl.prototype.O;Jl.prototype.set=Jl.prototype.set;Jl.prototype.setProperties=Jl.prototype.G;Jl.prototype.unset=Jl.prototype.P;Jl.prototype.changed=Jl.prototype.u;Jl.prototype.dispatchEvent=Jl.prototype.b;Jl.prototype.getRevision=Jl.prototype.K;Jl.prototype.on=Jl.prototype.I;Jl.prototype.once=Jl.prototype.L;Jl.prototype.un=Jl.prototype.J;Jl.prototype.unByKey=Jl.prototype.M;
+W.prototype.getTileLoadFunction=W.prototype.fb;W.prototype.getTileUrlFunction=W.prototype.gb;W.prototype.getUrls=W.prototype.hb;W.prototype.setTileLoadFunction=W.prototype.kb;W.prototype.setTileUrlFunction=W.prototype.Qa;W.prototype.setUrl=W.prototype.Va;W.prototype.setUrls=W.prototype.bb;W.prototype.getTileGrid=W.prototype.Na;W.prototype.refresh=W.prototype.sa;W.prototype.getAttributions=W.prototype.wa;W.prototype.getLogo=W.prototype.ua;W.prototype.getProjection=W.prototype.xa;
+W.prototype.getState=W.prototype.V;W.prototype.setAttributions=W.prototype.oa;W.prototype.get=W.prototype.get;W.prototype.getKeys=W.prototype.N;W.prototype.getProperties=W.prototype.O;W.prototype.set=W.prototype.set;W.prototype.setProperties=W.prototype.G;W.prototype.unset=W.prototype.P;W.prototype.changed=W.prototype.u;W.prototype.dispatchEvent=W.prototype.b;W.prototype.getRevision=W.prototype.K;W.prototype.on=W.prototype.I;W.prototype.once=W.prototype.L;W.prototype.un=W.prototype.J;
+W.prototype.unByKey=W.prototype.M;pv.prototype.setRenderReprojectionEdges=pv.prototype.zb;pv.prototype.setTileGridForProjection=pv.prototype.Ab;pv.prototype.getTileLoadFunction=pv.prototype.fb;pv.prototype.getTileUrlFunction=pv.prototype.gb;pv.prototype.getUrls=pv.prototype.hb;pv.prototype.setTileLoadFunction=pv.prototype.kb;pv.prototype.setTileUrlFunction=pv.prototype.Qa;pv.prototype.setUrl=pv.prototype.Va;pv.prototype.setUrls=pv.prototype.bb;pv.prototype.getTileGrid=pv.prototype.Na;
+pv.prototype.refresh=pv.prototype.sa;pv.prototype.getAttributions=pv.prototype.wa;pv.prototype.getLogo=pv.prototype.ua;pv.prototype.getProjection=pv.prototype.xa;pv.prototype.getState=pv.prototype.V;pv.prototype.setAttributions=pv.prototype.oa;pv.prototype.get=pv.prototype.get;pv.prototype.getKeys=pv.prototype.N;pv.prototype.getProperties=pv.prototype.O;pv.prototype.set=pv.prototype.set;pv.prototype.setProperties=pv.prototype.G;pv.prototype.unset=pv.prototype.P;pv.prototype.changed=pv.prototype.u;
+pv.prototype.dispatchEvent=pv.prototype.b;pv.prototype.getRevision=pv.prototype.K;pv.prototype.on=pv.prototype.I;pv.prototype.once=pv.prototype.L;pv.prototype.un=pv.prototype.J;pv.prototype.unByKey=pv.prototype.M;rv.prototype.setRenderReprojectionEdges=rv.prototype.zb;rv.prototype.setTileGridForProjection=rv.prototype.Ab;rv.prototype.getTileLoadFunction=rv.prototype.fb;rv.prototype.getTileUrlFunction=rv.prototype.gb;rv.prototype.getUrls=rv.prototype.hb;rv.prototype.setTileLoadFunction=rv.prototype.kb;
+rv.prototype.setTileUrlFunction=rv.prototype.Qa;rv.prototype.setUrl=rv.prototype.Va;rv.prototype.setUrls=rv.prototype.bb;rv.prototype.getTileGrid=rv.prototype.Na;rv.prototype.refresh=rv.prototype.sa;rv.prototype.getAttributions=rv.prototype.wa;rv.prototype.getLogo=rv.prototype.ua;rv.prototype.getProjection=rv.prototype.xa;rv.prototype.getState=rv.prototype.V;rv.prototype.setAttributions=rv.prototype.oa;rv.prototype.get=rv.prototype.get;rv.prototype.getKeys=rv.prototype.N;
+rv.prototype.getProperties=rv.prototype.O;rv.prototype.set=rv.prototype.set;rv.prototype.setProperties=rv.prototype.G;rv.prototype.unset=rv.prototype.P;rv.prototype.changed=rv.prototype.u;rv.prototype.dispatchEvent=rv.prototype.b;rv.prototype.getRevision=rv.prototype.K;rv.prototype.on=rv.prototype.I;rv.prototype.once=rv.prototype.L;rv.prototype.un=rv.prototype.J;rv.prototype.unByKey=rv.prototype.M;sv.prototype.setRenderReprojectionEdges=sv.prototype.zb;sv.prototype.setTileGridForProjection=sv.prototype.Ab;
+sv.prototype.getTileLoadFunction=sv.prototype.fb;sv.prototype.getTileUrlFunction=sv.prototype.gb;sv.prototype.getUrls=sv.prototype.hb;sv.prototype.setTileLoadFunction=sv.prototype.kb;sv.prototype.setTileUrlFunction=sv.prototype.Qa;sv.prototype.setUrl=sv.prototype.Va;sv.prototype.setUrls=sv.prototype.bb;sv.prototype.getTileGrid=sv.prototype.Na;sv.prototype.refresh=sv.prototype.sa;sv.prototype.getAttributions=sv.prototype.wa;sv.prototype.getLogo=sv.prototype.ua;sv.prototype.getProjection=sv.prototype.xa;
+sv.prototype.getState=sv.prototype.V;sv.prototype.setAttributions=sv.prototype.oa;sv.prototype.get=sv.prototype.get;sv.prototype.getKeys=sv.prototype.N;sv.prototype.getProperties=sv.prototype.O;sv.prototype.set=sv.prototype.set;sv.prototype.setProperties=sv.prototype.G;sv.prototype.unset=sv.prototype.P;sv.prototype.changed=sv.prototype.u;sv.prototype.dispatchEvent=sv.prototype.b;sv.prototype.getRevision=sv.prototype.K;sv.prototype.on=sv.prototype.I;sv.prototype.once=sv.prototype.L;
+sv.prototype.un=sv.prototype.J;sv.prototype.unByKey=sv.prototype.M;P.prototype.getAttributions=P.prototype.wa;P.prototype.getLogo=P.prototype.ua;P.prototype.getProjection=P.prototype.xa;P.prototype.getState=P.prototype.V;P.prototype.refresh=P.prototype.sa;P.prototype.setAttributions=P.prototype.oa;P.prototype.get=P.prototype.get;P.prototype.getKeys=P.prototype.N;P.prototype.getProperties=P.prototype.O;P.prototype.set=P.prototype.set;P.prototype.setProperties=P.prototype.G;P.prototype.unset=P.prototype.P;
+P.prototype.changed=P.prototype.u;P.prototype.dispatchEvent=P.prototype.b;P.prototype.getRevision=P.prototype.K;P.prototype.on=P.prototype.I;P.prototype.once=P.prototype.L;P.prototype.un=P.prototype.J;P.prototype.unByKey=P.prototype.M;Y.prototype.addFeature=Y.prototype.rb;Y.prototype.addFeatures=Y.prototype.Jc;Y.prototype.clear=Y.prototype.clear;Y.prototype.forEachFeature=Y.prototype.wg;Y.prototype.forEachFeatureInExtent=Y.prototype.ub;Y.prototype.forEachFeatureIntersectingExtent=Y.prototype.xg;
+Y.prototype.getFeaturesCollection=Y.prototype.Fg;Y.prototype.getFeatures=Y.prototype.oe;Y.prototype.getFeaturesAtCoordinate=Y.prototype.Eg;Y.prototype.getFeaturesInExtent=Y.prototype.ef;Y.prototype.getClosestFeatureToCoordinate=Y.prototype.Ag;Y.prototype.getExtent=Y.prototype.H;Y.prototype.getFeatureById=Y.prototype.Dg;Y.prototype.getFormat=Y.prototype.Ch;Y.prototype.getUrl=Y.prototype.Dh;Y.prototype.removeFeature=Y.prototype.nb;Y.prototype.getAttributions=Y.prototype.wa;Y.prototype.getLogo=Y.prototype.ua;
+Y.prototype.getProjection=Y.prototype.xa;Y.prototype.getState=Y.prototype.V;Y.prototype.refresh=Y.prototype.sa;Y.prototype.setAttributions=Y.prototype.oa;Y.prototype.get=Y.prototype.get;Y.prototype.getKeys=Y.prototype.N;Y.prototype.getProperties=Y.prototype.O;Y.prototype.set=Y.prototype.set;Y.prototype.setProperties=Y.prototype.G;Y.prototype.unset=Y.prototype.P;Y.prototype.changed=Y.prototype.u;Y.prototype.dispatchEvent=Y.prototype.b;Y.prototype.getRevision=Y.prototype.K;Y.prototype.on=Y.prototype.I;
+Y.prototype.once=Y.prototype.L;Y.prototype.un=Y.prototype.J;Y.prototype.unByKey=Y.prototype.M;Ak.prototype.getAttributions=Ak.prototype.wa;Ak.prototype.getLogo=Ak.prototype.ua;Ak.prototype.getProjection=Ak.prototype.xa;Ak.prototype.getState=Ak.prototype.V;Ak.prototype.refresh=Ak.prototype.sa;Ak.prototype.setAttributions=Ak.prototype.oa;Ak.prototype.get=Ak.prototype.get;Ak.prototype.getKeys=Ak.prototype.N;Ak.prototype.getProperties=Ak.prototype.O;Ak.prototype.set=Ak.prototype.set;
+Ak.prototype.setProperties=Ak.prototype.G;Ak.prototype.unset=Ak.prototype.P;Ak.prototype.changed=Ak.prototype.u;Ak.prototype.dispatchEvent=Ak.prototype.b;Ak.prototype.getRevision=Ak.prototype.K;Ak.prototype.on=Ak.prototype.I;Ak.prototype.once=Ak.prototype.L;Ak.prototype.un=Ak.prototype.J;Ak.prototype.unByKey=Ak.prototype.M;yv.prototype.getAttributions=yv.prototype.wa;yv.prototype.getLogo=yv.prototype.ua;yv.prototype.getProjection=yv.prototype.xa;yv.prototype.getState=yv.prototype.V;
+yv.prototype.refresh=yv.prototype.sa;yv.prototype.setAttributions=yv.prototype.oa;yv.prototype.get=yv.prototype.get;yv.prototype.getKeys=yv.prototype.N;yv.prototype.getProperties=yv.prototype.O;yv.prototype.set=yv.prototype.set;yv.prototype.setProperties=yv.prototype.G;yv.prototype.unset=yv.prototype.P;yv.prototype.changed=yv.prototype.u;yv.prototype.dispatchEvent=yv.prototype.b;yv.prototype.getRevision=yv.prototype.K;yv.prototype.on=yv.prototype.I;yv.prototype.once=yv.prototype.L;
+yv.prototype.un=yv.prototype.J;yv.prototype.unByKey=yv.prototype.M;Hk.prototype.getAttributions=Hk.prototype.wa;Hk.prototype.getLogo=Hk.prototype.ua;Hk.prototype.getProjection=Hk.prototype.xa;Hk.prototype.getState=Hk.prototype.V;Hk.prototype.refresh=Hk.prototype.sa;Hk.prototype.setAttributions=Hk.prototype.oa;Hk.prototype.get=Hk.prototype.get;Hk.prototype.getKeys=Hk.prototype.N;Hk.prototype.getProperties=Hk.prototype.O;Hk.prototype.set=Hk.prototype.set;Hk.prototype.setProperties=Hk.prototype.G;
+Hk.prototype.unset=Hk.prototype.P;Hk.prototype.changed=Hk.prototype.u;Hk.prototype.dispatchEvent=Hk.prototype.b;Hk.prototype.getRevision=Hk.prototype.K;Hk.prototype.on=Hk.prototype.I;Hk.prototype.once=Hk.prototype.L;Hk.prototype.un=Hk.prototype.J;Hk.prototype.unByKey=Hk.prototype.M;zv.prototype.getAttributions=zv.prototype.wa;zv.prototype.getLogo=zv.prototype.ua;zv.prototype.getProjection=zv.prototype.xa;zv.prototype.getState=zv.prototype.V;zv.prototype.refresh=zv.prototype.sa;
+zv.prototype.setAttributions=zv.prototype.oa;zv.prototype.get=zv.prototype.get;zv.prototype.getKeys=zv.prototype.N;zv.prototype.getProperties=zv.prototype.O;zv.prototype.set=zv.prototype.set;zv.prototype.setProperties=zv.prototype.G;zv.prototype.unset=zv.prototype.P;zv.prototype.changed=zv.prototype.u;zv.prototype.dispatchEvent=zv.prototype.b;zv.prototype.getRevision=zv.prototype.K;zv.prototype.on=zv.prototype.I;zv.prototype.once=zv.prototype.L;zv.prototype.un=zv.prototype.J;
+zv.prototype.unByKey=zv.prototype.M;Ck.prototype.type=Ck.prototype.type;Ck.prototype.target=Ck.prototype.target;Ck.prototype.preventDefault=Ck.prototype.preventDefault;Ck.prototype.stopPropagation=Ck.prototype.stopPropagation;Av.prototype.getAttributions=Av.prototype.wa;Av.prototype.getLogo=Av.prototype.ua;Av.prototype.getProjection=Av.prototype.xa;Av.prototype.getState=Av.prototype.V;Av.prototype.refresh=Av.prototype.sa;Av.prototype.setAttributions=Av.prototype.oa;Av.prototype.get=Av.prototype.get;
+Av.prototype.getKeys=Av.prototype.N;Av.prototype.getProperties=Av.prototype.O;Av.prototype.set=Av.prototype.set;Av.prototype.setProperties=Av.prototype.G;Av.prototype.unset=Av.prototype.P;Av.prototype.changed=Av.prototype.u;Av.prototype.dispatchEvent=Av.prototype.b;Av.prototype.getRevision=Av.prototype.K;Av.prototype.on=Av.prototype.I;Av.prototype.once=Av.prototype.L;Av.prototype.un=Av.prototype.J;Av.prototype.unByKey=Av.prototype.M;yl.prototype.getAttributions=yl.prototype.wa;
+yl.prototype.getLogo=yl.prototype.ua;yl.prototype.getProjection=yl.prototype.xa;yl.prototype.getState=yl.prototype.V;yl.prototype.refresh=yl.prototype.sa;yl.prototype.setAttributions=yl.prototype.oa;yl.prototype.get=yl.prototype.get;yl.prototype.getKeys=yl.prototype.N;yl.prototype.getProperties=yl.prototype.O;yl.prototype.set=yl.prototype.set;yl.prototype.setProperties=yl.prototype.G;yl.prototype.unset=yl.prototype.P;yl.prototype.changed=yl.prototype.u;yl.prototype.dispatchEvent=yl.prototype.b;
+yl.prototype.getRevision=yl.prototype.K;yl.prototype.on=yl.prototype.I;yl.prototype.once=yl.prototype.L;yl.prototype.un=yl.prototype.J;yl.prototype.unByKey=yl.prototype.M;Bv.prototype.getAttributions=Bv.prototype.wa;Bv.prototype.getLogo=Bv.prototype.ua;Bv.prototype.getProjection=Bv.prototype.xa;Bv.prototype.getState=Bv.prototype.V;Bv.prototype.refresh=Bv.prototype.sa;Bv.prototype.setAttributions=Bv.prototype.oa;Bv.prototype.get=Bv.prototype.get;Bv.prototype.getKeys=Bv.prototype.N;
+Bv.prototype.getProperties=Bv.prototype.O;Bv.prototype.set=Bv.prototype.set;Bv.prototype.setProperties=Bv.prototype.G;Bv.prototype.unset=Bv.prototype.P;Bv.prototype.changed=Bv.prototype.u;Bv.prototype.dispatchEvent=Bv.prototype.b;Bv.prototype.getRevision=Bv.prototype.K;Bv.prototype.on=Bv.prototype.I;Bv.prototype.once=Bv.prototype.L;Bv.prototype.un=Bv.prototype.J;Bv.prototype.unByKey=Bv.prototype.M;Fv.prototype.setRenderReprojectionEdges=Fv.prototype.zb;Fv.prototype.setTileGridForProjection=Fv.prototype.Ab;
+Fv.prototype.getTileLoadFunction=Fv.prototype.fb;Fv.prototype.getTileUrlFunction=Fv.prototype.gb;Fv.prototype.getUrls=Fv.prototype.hb;Fv.prototype.setTileLoadFunction=Fv.prototype.kb;Fv.prototype.setTileUrlFunction=Fv.prototype.Qa;Fv.prototype.setUrl=Fv.prototype.Va;Fv.prototype.setUrls=Fv.prototype.bb;Fv.prototype.getTileGrid=Fv.prototype.Na;Fv.prototype.refresh=Fv.prototype.sa;Fv.prototype.getAttributions=Fv.prototype.wa;Fv.prototype.getLogo=Fv.prototype.ua;Fv.prototype.getProjection=Fv.prototype.xa;
+Fv.prototype.getState=Fv.prototype.V;Fv.prototype.setAttributions=Fv.prototype.oa;Fv.prototype.get=Fv.prototype.get;Fv.prototype.getKeys=Fv.prototype.N;Fv.prototype.getProperties=Fv.prototype.O;Fv.prototype.set=Fv.prototype.set;Fv.prototype.setProperties=Fv.prototype.G;Fv.prototype.unset=Fv.prototype.P;Fv.prototype.changed=Fv.prototype.u;Fv.prototype.dispatchEvent=Fv.prototype.b;Fv.prototype.getRevision=Fv.prototype.K;Fv.prototype.on=Fv.prototype.I;Fv.prototype.once=Fv.prototype.L;
+Fv.prototype.un=Fv.prototype.J;Fv.prototype.unByKey=Fv.prototype.M;Hv.prototype.getAttributions=Hv.prototype.wa;Hv.prototype.getLogo=Hv.prototype.ua;Hv.prototype.getProjection=Hv.prototype.xa;Hv.prototype.getState=Hv.prototype.V;Hv.prototype.refresh=Hv.prototype.sa;Hv.prototype.setAttributions=Hv.prototype.oa;Hv.prototype.get=Hv.prototype.get;Hv.prototype.getKeys=Hv.prototype.N;Hv.prototype.getProperties=Hv.prototype.O;Hv.prototype.set=Hv.prototype.set;Hv.prototype.setProperties=Hv.prototype.G;
+Hv.prototype.unset=Hv.prototype.P;Hv.prototype.changed=Hv.prototype.u;Hv.prototype.dispatchEvent=Hv.prototype.b;Hv.prototype.getRevision=Hv.prototype.K;Hv.prototype.on=Hv.prototype.I;Hv.prototype.once=Hv.prototype.L;Hv.prototype.un=Hv.prototype.J;Hv.prototype.unByKey=Hv.prototype.M;Mv.prototype.type=Mv.prototype.type;Mv.prototype.target=Mv.prototype.target;Mv.prototype.preventDefault=Mv.prototype.preventDefault;Mv.prototype.stopPropagation=Mv.prototype.stopPropagation;
+Rv.prototype.setRenderReprojectionEdges=Rv.prototype.zb;Rv.prototype.setTileGridForProjection=Rv.prototype.Ab;Rv.prototype.getTileLoadFunction=Rv.prototype.fb;Rv.prototype.getTileUrlFunction=Rv.prototype.gb;Rv.prototype.getUrls=Rv.prototype.hb;Rv.prototype.setTileLoadFunction=Rv.prototype.kb;Rv.prototype.setTileUrlFunction=Rv.prototype.Qa;Rv.prototype.setUrl=Rv.prototype.Va;Rv.prototype.setUrls=Rv.prototype.bb;Rv.prototype.getTileGrid=Rv.prototype.Na;Rv.prototype.refresh=Rv.prototype.sa;
+Rv.prototype.getAttributions=Rv.prototype.wa;Rv.prototype.getLogo=Rv.prototype.ua;Rv.prototype.getProjection=Rv.prototype.xa;Rv.prototype.getState=Rv.prototype.V;Rv.prototype.setAttributions=Rv.prototype.oa;Rv.prototype.get=Rv.prototype.get;Rv.prototype.getKeys=Rv.prototype.N;Rv.prototype.getProperties=Rv.prototype.O;Rv.prototype.set=Rv.prototype.set;Rv.prototype.setProperties=Rv.prototype.G;Rv.prototype.unset=Rv.prototype.P;Rv.prototype.changed=Rv.prototype.u;Rv.prototype.dispatchEvent=Rv.prototype.b;
+Rv.prototype.getRevision=Rv.prototype.K;Rv.prototype.on=Rv.prototype.I;Rv.prototype.once=Rv.prototype.L;Rv.prototype.un=Rv.prototype.J;Rv.prototype.unByKey=Rv.prototype.M;Tv.prototype.setRenderReprojectionEdges=Tv.prototype.zb;Tv.prototype.setTileGridForProjection=Tv.prototype.Ab;Tv.prototype.getTileLoadFunction=Tv.prototype.fb;Tv.prototype.getTileUrlFunction=Tv.prototype.gb;Tv.prototype.getUrls=Tv.prototype.hb;Tv.prototype.setTileLoadFunction=Tv.prototype.kb;Tv.prototype.setTileUrlFunction=Tv.prototype.Qa;
+Tv.prototype.setUrl=Tv.prototype.Va;Tv.prototype.setUrls=Tv.prototype.bb;Tv.prototype.getTileGrid=Tv.prototype.Na;Tv.prototype.refresh=Tv.prototype.sa;Tv.prototype.getAttributions=Tv.prototype.wa;Tv.prototype.getLogo=Tv.prototype.ua;Tv.prototype.getProjection=Tv.prototype.xa;Tv.prototype.getState=Tv.prototype.V;Tv.prototype.setAttributions=Tv.prototype.oa;Tv.prototype.get=Tv.prototype.get;Tv.prototype.getKeys=Tv.prototype.N;Tv.prototype.getProperties=Tv.prototype.O;Tv.prototype.set=Tv.prototype.set;
+Tv.prototype.setProperties=Tv.prototype.G;Tv.prototype.unset=Tv.prototype.P;Tv.prototype.changed=Tv.prototype.u;Tv.prototype.dispatchEvent=Tv.prototype.b;Tv.prototype.getRevision=Tv.prototype.K;Tv.prototype.on=Tv.prototype.I;Tv.prototype.once=Tv.prototype.L;Tv.prototype.un=Tv.prototype.J;Tv.prototype.unByKey=Tv.prototype.M;Vv.prototype.getTileGrid=Vv.prototype.Na;Vv.prototype.refresh=Vv.prototype.sa;Vv.prototype.getAttributions=Vv.prototype.wa;Vv.prototype.getLogo=Vv.prototype.ua;
+Vv.prototype.getProjection=Vv.prototype.xa;Vv.prototype.getState=Vv.prototype.V;Vv.prototype.setAttributions=Vv.prototype.oa;Vv.prototype.get=Vv.prototype.get;Vv.prototype.getKeys=Vv.prototype.N;Vv.prototype.getProperties=Vv.prototype.O;Vv.prototype.set=Vv.prototype.set;Vv.prototype.setProperties=Vv.prototype.G;Vv.prototype.unset=Vv.prototype.P;Vv.prototype.changed=Vv.prototype.u;Vv.prototype.dispatchEvent=Vv.prototype.b;Vv.prototype.getRevision=Vv.prototype.K;Vv.prototype.on=Vv.prototype.I;
+Vv.prototype.once=Vv.prototype.L;Vv.prototype.un=Vv.prototype.J;Vv.prototype.unByKey=Vv.prototype.M;Wv.prototype.setRenderReprojectionEdges=Wv.prototype.zb;Wv.prototype.setTileGridForProjection=Wv.prototype.Ab;Wv.prototype.getTileLoadFunction=Wv.prototype.fb;Wv.prototype.getTileUrlFunction=Wv.prototype.gb;Wv.prototype.getUrls=Wv.prototype.hb;Wv.prototype.setTileLoadFunction=Wv.prototype.kb;Wv.prototype.setTileUrlFunction=Wv.prototype.Qa;Wv.prototype.setUrl=Wv.prototype.Va;Wv.prototype.setUrls=Wv.prototype.bb;
+Wv.prototype.getTileGrid=Wv.prototype.Na;Wv.prototype.refresh=Wv.prototype.sa;Wv.prototype.getAttributions=Wv.prototype.wa;Wv.prototype.getLogo=Wv.prototype.ua;Wv.prototype.getProjection=Wv.prototype.xa;Wv.prototype.getState=Wv.prototype.V;Wv.prototype.setAttributions=Wv.prototype.oa;Wv.prototype.get=Wv.prototype.get;Wv.prototype.getKeys=Wv.prototype.N;Wv.prototype.getProperties=Wv.prototype.O;Wv.prototype.set=Wv.prototype.set;Wv.prototype.setProperties=Wv.prototype.G;Wv.prototype.unset=Wv.prototype.P;
+Wv.prototype.changed=Wv.prototype.u;Wv.prototype.dispatchEvent=Wv.prototype.b;Wv.prototype.getRevision=Wv.prototype.K;Wv.prototype.on=Wv.prototype.I;Wv.prototype.once=Wv.prototype.L;Wv.prototype.un=Wv.prototype.J;Wv.prototype.unByKey=Wv.prototype.M;Df.prototype.type=Df.prototype.type;Df.prototype.target=Df.prototype.target;Df.prototype.preventDefault=Df.prototype.preventDefault;Df.prototype.stopPropagation=Df.prototype.stopPropagation;Xv.prototype.getTileGrid=Xv.prototype.Na;
+Xv.prototype.refresh=Xv.prototype.sa;Xv.prototype.getAttributions=Xv.prototype.wa;Xv.prototype.getLogo=Xv.prototype.ua;Xv.prototype.getProjection=Xv.prototype.xa;Xv.prototype.getState=Xv.prototype.V;Xv.prototype.setAttributions=Xv.prototype.oa;Xv.prototype.get=Xv.prototype.get;Xv.prototype.getKeys=Xv.prototype.N;Xv.prototype.getProperties=Xv.prototype.O;Xv.prototype.set=Xv.prototype.set;Xv.prototype.setProperties=Xv.prototype.G;Xv.prototype.unset=Xv.prototype.P;Xv.prototype.changed=Xv.prototype.u;
+Xv.prototype.dispatchEvent=Xv.prototype.b;Xv.prototype.getRevision=Xv.prototype.K;Xv.prototype.on=Xv.prototype.I;Xv.prototype.once=Xv.prototype.L;Xv.prototype.un=Xv.prototype.J;Xv.prototype.unByKey=Xv.prototype.M;aw.prototype.setRenderReprojectionEdges=aw.prototype.zb;aw.prototype.setTileGridForProjection=aw.prototype.Ab;aw.prototype.getTileLoadFunction=aw.prototype.fb;aw.prototype.getTileUrlFunction=aw.prototype.gb;aw.prototype.getUrls=aw.prototype.hb;aw.prototype.setTileLoadFunction=aw.prototype.kb;
+aw.prototype.setTileUrlFunction=aw.prototype.Qa;aw.prototype.setUrl=aw.prototype.Va;aw.prototype.setUrls=aw.prototype.bb;aw.prototype.getTileGrid=aw.prototype.Na;aw.prototype.refresh=aw.prototype.sa;aw.prototype.getAttributions=aw.prototype.wa;aw.prototype.getLogo=aw.prototype.ua;aw.prototype.getProjection=aw.prototype.xa;aw.prototype.getState=aw.prototype.V;aw.prototype.setAttributions=aw.prototype.oa;aw.prototype.get=aw.prototype.get;aw.prototype.getKeys=aw.prototype.N;
+aw.prototype.getProperties=aw.prototype.O;aw.prototype.set=aw.prototype.set;aw.prototype.setProperties=aw.prototype.G;aw.prototype.unset=aw.prototype.P;aw.prototype.changed=aw.prototype.u;aw.prototype.dispatchEvent=aw.prototype.b;aw.prototype.getRevision=aw.prototype.K;aw.prototype.on=aw.prototype.I;aw.prototype.once=aw.prototype.L;aw.prototype.un=aw.prototype.J;aw.prototype.unByKey=aw.prototype.M;vl.prototype.type=vl.prototype.type;vl.prototype.target=vl.prototype.target;
+vl.prototype.preventDefault=vl.prototype.preventDefault;vl.prototype.stopPropagation=vl.prototype.stopPropagation;Kl.prototype.getTileLoadFunction=Kl.prototype.fb;Kl.prototype.getTileUrlFunction=Kl.prototype.gb;Kl.prototype.getUrls=Kl.prototype.hb;Kl.prototype.setTileLoadFunction=Kl.prototype.kb;Kl.prototype.setTileUrlFunction=Kl.prototype.Qa;Kl.prototype.setUrl=Kl.prototype.Va;Kl.prototype.setUrls=Kl.prototype.bb;Kl.prototype.getTileGrid=Kl.prototype.Na;Kl.prototype.refresh=Kl.prototype.sa;
+Kl.prototype.getAttributions=Kl.prototype.wa;Kl.prototype.getLogo=Kl.prototype.ua;Kl.prototype.getProjection=Kl.prototype.xa;Kl.prototype.getState=Kl.prototype.V;Kl.prototype.setAttributions=Kl.prototype.oa;Kl.prototype.get=Kl.prototype.get;Kl.prototype.getKeys=Kl.prototype.N;Kl.prototype.getProperties=Kl.prototype.O;Kl.prototype.set=Kl.prototype.set;Kl.prototype.setProperties=Kl.prototype.G;Kl.prototype.unset=Kl.prototype.P;Kl.prototype.changed=Kl.prototype.u;Kl.prototype.dispatchEvent=Kl.prototype.b;
+Kl.prototype.getRevision=Kl.prototype.K;Kl.prototype.on=Kl.prototype.I;Kl.prototype.once=Kl.prototype.L;Kl.prototype.un=Kl.prototype.J;Kl.prototype.unByKey=Kl.prototype.M;Z.prototype.setRenderReprojectionEdges=Z.prototype.zb;Z.prototype.setTileGridForProjection=Z.prototype.Ab;Z.prototype.getTileLoadFunction=Z.prototype.fb;Z.prototype.getTileUrlFunction=Z.prototype.gb;Z.prototype.getUrls=Z.prototype.hb;Z.prototype.setTileLoadFunction=Z.prototype.kb;Z.prototype.setTileUrlFunction=Z.prototype.Qa;
+Z.prototype.setUrl=Z.prototype.Va;Z.prototype.setUrls=Z.prototype.bb;Z.prototype.getTileGrid=Z.prototype.Na;Z.prototype.refresh=Z.prototype.sa;Z.prototype.getAttributions=Z.prototype.wa;Z.prototype.getLogo=Z.prototype.ua;Z.prototype.getProjection=Z.prototype.xa;Z.prototype.getState=Z.prototype.V;Z.prototype.setAttributions=Z.prototype.oa;Z.prototype.get=Z.prototype.get;Z.prototype.getKeys=Z.prototype.N;Z.prototype.getProperties=Z.prototype.O;Z.prototype.set=Z.prototype.set;
+Z.prototype.setProperties=Z.prototype.G;Z.prototype.unset=Z.prototype.P;Z.prototype.changed=Z.prototype.u;Z.prototype.dispatchEvent=Z.prototype.b;Z.prototype.getRevision=Z.prototype.K;Z.prototype.on=Z.prototype.I;Z.prototype.once=Z.prototype.L;Z.prototype.un=Z.prototype.J;Z.prototype.unByKey=Z.prototype.M;iw.prototype.setRenderReprojectionEdges=iw.prototype.zb;iw.prototype.setTileGridForProjection=iw.prototype.Ab;iw.prototype.getTileLoadFunction=iw.prototype.fb;iw.prototype.getTileUrlFunction=iw.prototype.gb;
+iw.prototype.getUrls=iw.prototype.hb;iw.prototype.setTileLoadFunction=iw.prototype.kb;iw.prototype.setTileUrlFunction=iw.prototype.Qa;iw.prototype.setUrl=iw.prototype.Va;iw.prototype.setUrls=iw.prototype.bb;iw.prototype.getTileGrid=iw.prototype.Na;iw.prototype.refresh=iw.prototype.sa;iw.prototype.getAttributions=iw.prototype.wa;iw.prototype.getLogo=iw.prototype.ua;iw.prototype.getProjection=iw.prototype.xa;iw.prototype.getState=iw.prototype.V;iw.prototype.setAttributions=iw.prototype.oa;
+iw.prototype.get=iw.prototype.get;iw.prototype.getKeys=iw.prototype.N;iw.prototype.getProperties=iw.prototype.O;iw.prototype.set=iw.prototype.set;iw.prototype.setProperties=iw.prototype.G;iw.prototype.unset=iw.prototype.P;iw.prototype.changed=iw.prototype.u;iw.prototype.dispatchEvent=iw.prototype.b;iw.prototype.getRevision=iw.prototype.K;iw.prototype.on=iw.prototype.I;iw.prototype.once=iw.prototype.L;iw.prototype.un=iw.prototype.J;iw.prototype.unByKey=iw.prototype.M;lv.prototype.getTileCoord=lv.prototype.i;
+lv.prototype.load=lv.prototype.load;th.prototype.changed=th.prototype.u;th.prototype.dispatchEvent=th.prototype.b;th.prototype.getRevision=th.prototype.K;th.prototype.on=th.prototype.I;th.prototype.once=th.prototype.L;th.prototype.un=th.prototype.J;th.prototype.unByKey=th.prototype.M;Gm.prototype.changed=Gm.prototype.u;Gm.prototype.dispatchEvent=Gm.prototype.b;Gm.prototype.getRevision=Gm.prototype.K;Gm.prototype.on=Gm.prototype.I;Gm.prototype.once=Gm.prototype.L;Gm.prototype.un=Gm.prototype.J;
+Gm.prototype.unByKey=Gm.prototype.M;Jm.prototype.changed=Jm.prototype.u;Jm.prototype.dispatchEvent=Jm.prototype.b;Jm.prototype.getRevision=Jm.prototype.K;Jm.prototype.on=Jm.prototype.I;Jm.prototype.once=Jm.prototype.L;Jm.prototype.un=Jm.prototype.J;Jm.prototype.unByKey=Jm.prototype.M;Pm.prototype.changed=Pm.prototype.u;Pm.prototype.dispatchEvent=Pm.prototype.b;Pm.prototype.getRevision=Pm.prototype.K;Pm.prototype.on=Pm.prototype.I;Pm.prototype.once=Pm.prototype.L;Pm.prototype.un=Pm.prototype.J;
+Pm.prototype.unByKey=Pm.prototype.M;Rm.prototype.changed=Rm.prototype.u;Rm.prototype.dispatchEvent=Rm.prototype.b;Rm.prototype.getRevision=Rm.prototype.K;Rm.prototype.on=Rm.prototype.I;Rm.prototype.once=Rm.prototype.L;Rm.prototype.un=Rm.prototype.J;Rm.prototype.unByKey=Rm.prototype.M;Sl.prototype.changed=Sl.prototype.u;Sl.prototype.dispatchEvent=Sl.prototype.b;Sl.prototype.getRevision=Sl.prototype.K;Sl.prototype.on=Sl.prototype.I;Sl.prototype.once=Sl.prototype.L;Sl.prototype.un=Sl.prototype.J;
+Sl.prototype.unByKey=Sl.prototype.M;Tl.prototype.changed=Tl.prototype.u;Tl.prototype.dispatchEvent=Tl.prototype.b;Tl.prototype.getRevision=Tl.prototype.K;Tl.prototype.on=Tl.prototype.I;Tl.prototype.once=Tl.prototype.L;Tl.prototype.un=Tl.prototype.J;Tl.prototype.unByKey=Tl.prototype.M;Ul.prototype.changed=Ul.prototype.u;Ul.prototype.dispatchEvent=Ul.prototype.b;Ul.prototype.getRevision=Ul.prototype.K;Ul.prototype.on=Ul.prototype.I;Ul.prototype.once=Ul.prototype.L;Ul.prototype.un=Ul.prototype.J;
+Ul.prototype.unByKey=Ul.prototype.M;Wl.prototype.changed=Wl.prototype.u;Wl.prototype.dispatchEvent=Wl.prototype.b;Wl.prototype.getRevision=Wl.prototype.K;Wl.prototype.on=Wl.prototype.I;Wl.prototype.once=Wl.prototype.L;Wl.prototype.un=Wl.prototype.J;Wl.prototype.unByKey=Wl.prototype.M;Jj.prototype.changed=Jj.prototype.u;Jj.prototype.dispatchEvent=Jj.prototype.b;Jj.prototype.getRevision=Jj.prototype.K;Jj.prototype.on=Jj.prototype.I;Jj.prototype.once=Jj.prototype.L;Jj.prototype.un=Jj.prototype.J;
+Jj.prototype.unByKey=Jj.prototype.M;Al.prototype.changed=Al.prototype.u;Al.prototype.dispatchEvent=Al.prototype.b;Al.prototype.getRevision=Al.prototype.K;Al.prototype.on=Al.prototype.I;Al.prototype.once=Al.prototype.L;Al.prototype.un=Al.prototype.J;Al.prototype.unByKey=Al.prototype.M;Bl.prototype.changed=Bl.prototype.u;Bl.prototype.dispatchEvent=Bl.prototype.b;Bl.prototype.getRevision=Bl.prototype.K;Bl.prototype.on=Bl.prototype.I;Bl.prototype.once=Bl.prototype.L;Bl.prototype.un=Bl.prototype.J;
+Bl.prototype.unByKey=Bl.prototype.M;Dl.prototype.changed=Dl.prototype.u;Dl.prototype.dispatchEvent=Dl.prototype.b;Dl.prototype.getRevision=Dl.prototype.K;Dl.prototype.on=Dl.prototype.I;Dl.prototype.once=Dl.prototype.L;Dl.prototype.un=Dl.prototype.J;Dl.prototype.unByKey=Dl.prototype.M;Ol.prototype.changed=Ol.prototype.u;Ol.prototype.dispatchEvent=Ol.prototype.b;Ol.prototype.getRevision=Ol.prototype.K;Ol.prototype.on=Ol.prototype.I;Ol.prototype.once=Ol.prototype.L;Ol.prototype.un=Ol.prototype.J;
+Ol.prototype.unByKey=Ol.prototype.M;lh.prototype.type=lh.prototype.type;lh.prototype.target=lh.prototype.target;lh.prototype.preventDefault=lh.prototype.preventDefault;lh.prototype.stopPropagation=lh.prototype.stopPropagation;Wf.prototype.type=Wf.prototype.type;Wf.prototype.target=Wf.prototype.target;Wf.prototype.preventDefault=Wf.prototype.preventDefault;Wf.prototype.stopPropagation=Wf.prototype.stopPropagation;ih.prototype.get=ih.prototype.get;ih.prototype.getKeys=ih.prototype.N;
+ih.prototype.getProperties=ih.prototype.O;ih.prototype.set=ih.prototype.set;ih.prototype.setProperties=ih.prototype.G;ih.prototype.unset=ih.prototype.P;ih.prototype.changed=ih.prototype.u;ih.prototype.dispatchEvent=ih.prototype.b;ih.prototype.getRevision=ih.prototype.K;ih.prototype.on=ih.prototype.I;ih.prototype.once=ih.prototype.L;ih.prototype.un=ih.prototype.J;ih.prototype.unByKey=ih.prototype.M;mh.prototype.getExtent=mh.prototype.H;mh.prototype.getMaxResolution=mh.prototype.Nb;
+mh.prototype.getMinResolution=mh.prototype.Ob;mh.prototype.getOpacity=mh.prototype.Pb;mh.prototype.getVisible=mh.prototype.xb;mh.prototype.getZIndex=mh.prototype.Qb;mh.prototype.setExtent=mh.prototype.fc;mh.prototype.setMaxResolution=mh.prototype.nc;mh.prototype.setMinResolution=mh.prototype.oc;mh.prototype.setOpacity=mh.prototype.gc;mh.prototype.setVisible=mh.prototype.hc;mh.prototype.setZIndex=mh.prototype.ic;mh.prototype.get=mh.prototype.get;mh.prototype.getKeys=mh.prototype.N;
+mh.prototype.getProperties=mh.prototype.O;mh.prototype.set=mh.prototype.set;mh.prototype.setProperties=mh.prototype.G;mh.prototype.unset=mh.prototype.P;mh.prototype.changed=mh.prototype.u;mh.prototype.dispatchEvent=mh.prototype.b;mh.prototype.getRevision=mh.prototype.K;mh.prototype.on=mh.prototype.I;mh.prototype.once=mh.prototype.L;mh.prototype.un=mh.prototype.J;mh.prototype.unByKey=mh.prototype.M;G.prototype.setMap=G.prototype.setMap;G.prototype.setSource=G.prototype.Fc;G.prototype.getExtent=G.prototype.H;
+G.prototype.getMaxResolution=G.prototype.Nb;G.prototype.getMinResolution=G.prototype.Ob;G.prototype.getOpacity=G.prototype.Pb;G.prototype.getVisible=G.prototype.xb;G.prototype.getZIndex=G.prototype.Qb;G.prototype.setExtent=G.prototype.fc;G.prototype.setMaxResolution=G.prototype.nc;G.prototype.setMinResolution=G.prototype.oc;G.prototype.setOpacity=G.prototype.gc;G.prototype.setVisible=G.prototype.hc;G.prototype.setZIndex=G.prototype.ic;G.prototype.get=G.prototype.get;G.prototype.getKeys=G.prototype.N;
+G.prototype.getProperties=G.prototype.O;G.prototype.set=G.prototype.set;G.prototype.setProperties=G.prototype.G;G.prototype.unset=G.prototype.P;G.prototype.changed=G.prototype.u;G.prototype.dispatchEvent=G.prototype.b;G.prototype.getRevision=G.prototype.K;G.prototype.on=G.prototype.I;G.prototype.once=G.prototype.L;G.prototype.un=G.prototype.J;G.prototype.unByKey=G.prototype.M;V.prototype.getSource=V.prototype.ha;V.prototype.getStyle=V.prototype.C;V.prototype.getStyleFunction=V.prototype.D;
+V.prototype.setStyle=V.prototype.l;V.prototype.setMap=V.prototype.setMap;V.prototype.setSource=V.prototype.Fc;V.prototype.getExtent=V.prototype.H;V.prototype.getMaxResolution=V.prototype.Nb;V.prototype.getMinResolution=V.prototype.Ob;V.prototype.getOpacity=V.prototype.Pb;V.prototype.getVisible=V.prototype.xb;V.prototype.getZIndex=V.prototype.Qb;V.prototype.setExtent=V.prototype.fc;V.prototype.setMaxResolution=V.prototype.nc;V.prototype.setMinResolution=V.prototype.oc;V.prototype.setOpacity=V.prototype.gc;
+V.prototype.setVisible=V.prototype.hc;V.prototype.setZIndex=V.prototype.ic;V.prototype.get=V.prototype.get;V.prototype.getKeys=V.prototype.N;V.prototype.getProperties=V.prototype.O;V.prototype.set=V.prototype.set;V.prototype.setProperties=V.prototype.G;V.prototype.unset=V.prototype.P;V.prototype.changed=V.prototype.u;V.prototype.dispatchEvent=V.prototype.b;V.prototype.getRevision=V.prototype.K;V.prototype.on=V.prototype.I;V.prototype.once=V.prototype.L;V.prototype.un=V.prototype.J;
+V.prototype.unByKey=V.prototype.M;cj.prototype.setMap=cj.prototype.setMap;cj.prototype.setSource=cj.prototype.Fc;cj.prototype.getExtent=cj.prototype.H;cj.prototype.getMaxResolution=cj.prototype.Nb;cj.prototype.getMinResolution=cj.prototype.Ob;cj.prototype.getOpacity=cj.prototype.Pb;cj.prototype.getVisible=cj.prototype.xb;cj.prototype.getZIndex=cj.prototype.Qb;cj.prototype.setExtent=cj.prototype.fc;cj.prototype.setMaxResolution=cj.prototype.nc;cj.prototype.setMinResolution=cj.prototype.oc;
+cj.prototype.setOpacity=cj.prototype.gc;cj.prototype.setVisible=cj.prototype.hc;cj.prototype.setZIndex=cj.prototype.ic;cj.prototype.get=cj.prototype.get;cj.prototype.getKeys=cj.prototype.N;cj.prototype.getProperties=cj.prototype.O;cj.prototype.set=cj.prototype.set;cj.prototype.setProperties=cj.prototype.G;cj.prototype.unset=cj.prototype.P;cj.prototype.changed=cj.prototype.u;cj.prototype.dispatchEvent=cj.prototype.b;cj.prototype.getRevision=cj.prototype.K;cj.prototype.on=cj.prototype.I;
+cj.prototype.once=cj.prototype.L;cj.prototype.un=cj.prototype.J;cj.prototype.unByKey=cj.prototype.M;Ti.prototype.getExtent=Ti.prototype.H;Ti.prototype.getMaxResolution=Ti.prototype.Nb;Ti.prototype.getMinResolution=Ti.prototype.Ob;Ti.prototype.getOpacity=Ti.prototype.Pb;Ti.prototype.getVisible=Ti.prototype.xb;Ti.prototype.getZIndex=Ti.prototype.Qb;Ti.prototype.setExtent=Ti.prototype.fc;Ti.prototype.setMaxResolution=Ti.prototype.nc;Ti.prototype.setMinResolution=Ti.prototype.oc;
+Ti.prototype.setOpacity=Ti.prototype.gc;Ti.prototype.setVisible=Ti.prototype.hc;Ti.prototype.setZIndex=Ti.prototype.ic;Ti.prototype.get=Ti.prototype.get;Ti.prototype.getKeys=Ti.prototype.N;Ti.prototype.getProperties=Ti.prototype.O;Ti.prototype.set=Ti.prototype.set;Ti.prototype.setProperties=Ti.prototype.G;Ti.prototype.unset=Ti.prototype.P;Ti.prototype.changed=Ti.prototype.u;Ti.prototype.dispatchEvent=Ti.prototype.b;Ti.prototype.getRevision=Ti.prototype.K;Ti.prototype.on=Ti.prototype.I;
+Ti.prototype.once=Ti.prototype.L;Ti.prototype.un=Ti.prototype.J;Ti.prototype.unByKey=Ti.prototype.M;dj.prototype.setMap=dj.prototype.setMap;dj.prototype.setSource=dj.prototype.Fc;dj.prototype.getExtent=dj.prototype.H;dj.prototype.getMaxResolution=dj.prototype.Nb;dj.prototype.getMinResolution=dj.prototype.Ob;dj.prototype.getOpacity=dj.prototype.Pb;dj.prototype.getVisible=dj.prototype.xb;dj.prototype.getZIndex=dj.prototype.Qb;dj.prototype.setExtent=dj.prototype.fc;dj.prototype.setMaxResolution=dj.prototype.nc;
+dj.prototype.setMinResolution=dj.prototype.oc;dj.prototype.setOpacity=dj.prototype.gc;dj.prototype.setVisible=dj.prototype.hc;dj.prototype.setZIndex=dj.prototype.ic;dj.prototype.get=dj.prototype.get;dj.prototype.getKeys=dj.prototype.N;dj.prototype.getProperties=dj.prototype.O;dj.prototype.set=dj.prototype.set;dj.prototype.setProperties=dj.prototype.G;dj.prototype.unset=dj.prototype.P;dj.prototype.changed=dj.prototype.u;dj.prototype.dispatchEvent=dj.prototype.b;dj.prototype.getRevision=dj.prototype.K;
+dj.prototype.on=dj.prototype.I;dj.prototype.once=dj.prototype.L;dj.prototype.un=dj.prototype.J;dj.prototype.unByKey=dj.prototype.M;I.prototype.getSource=I.prototype.ha;I.prototype.getStyle=I.prototype.C;I.prototype.getStyleFunction=I.prototype.D;I.prototype.setStyle=I.prototype.l;I.prototype.setMap=I.prototype.setMap;I.prototype.setSource=I.prototype.Fc;I.prototype.getExtent=I.prototype.H;I.prototype.getMaxResolution=I.prototype.Nb;I.prototype.getMinResolution=I.prototype.Ob;
+I.prototype.getOpacity=I.prototype.Pb;I.prototype.getVisible=I.prototype.xb;I.prototype.getZIndex=I.prototype.Qb;I.prototype.setExtent=I.prototype.fc;I.prototype.setMaxResolution=I.prototype.nc;I.prototype.setMinResolution=I.prototype.oc;I.prototype.setOpacity=I.prototype.gc;I.prototype.setVisible=I.prototype.hc;I.prototype.setZIndex=I.prototype.ic;I.prototype.get=I.prototype.get;I.prototype.getKeys=I.prototype.N;I.prototype.getProperties=I.prototype.O;I.prototype.set=I.prototype.set;
+I.prototype.setProperties=I.prototype.G;I.prototype.unset=I.prototype.P;I.prototype.changed=I.prototype.u;I.prototype.dispatchEvent=I.prototype.b;I.prototype.getRevision=I.prototype.K;I.prototype.on=I.prototype.I;I.prototype.once=I.prototype.L;I.prototype.un=I.prototype.J;I.prototype.unByKey=I.prototype.M;Vh.prototype.get=Vh.prototype.get;Vh.prototype.getKeys=Vh.prototype.N;Vh.prototype.getProperties=Vh.prototype.O;Vh.prototype.set=Vh.prototype.set;Vh.prototype.setProperties=Vh.prototype.G;
+Vh.prototype.unset=Vh.prototype.P;Vh.prototype.changed=Vh.prototype.u;Vh.prototype.dispatchEvent=Vh.prototype.b;Vh.prototype.getRevision=Vh.prototype.K;Vh.prototype.on=Vh.prototype.I;Vh.prototype.once=Vh.prototype.L;Vh.prototype.un=Vh.prototype.J;Vh.prototype.unByKey=Vh.prototype.M;Zh.prototype.getActive=Zh.prototype.f;Zh.prototype.getMap=Zh.prototype.l;Zh.prototype.setActive=Zh.prototype.i;Zh.prototype.get=Zh.prototype.get;Zh.prototype.getKeys=Zh.prototype.N;Zh.prototype.getProperties=Zh.prototype.O;
+Zh.prototype.set=Zh.prototype.set;Zh.prototype.setProperties=Zh.prototype.G;Zh.prototype.unset=Zh.prototype.P;Zh.prototype.changed=Zh.prototype.u;Zh.prototype.dispatchEvent=Zh.prototype.b;Zh.prototype.getRevision=Zh.prototype.K;Zh.prototype.on=Zh.prototype.I;Zh.prototype.once=Zh.prototype.L;Zh.prototype.un=Zh.prototype.J;Zh.prototype.unByKey=Zh.prototype.M;hu.prototype.getActive=hu.prototype.f;hu.prototype.getMap=hu.prototype.l;hu.prototype.setActive=hu.prototype.i;hu.prototype.get=hu.prototype.get;
+hu.prototype.getKeys=hu.prototype.N;hu.prototype.getProperties=hu.prototype.O;hu.prototype.set=hu.prototype.set;hu.prototype.setProperties=hu.prototype.G;hu.prototype.unset=hu.prototype.P;hu.prototype.changed=hu.prototype.u;hu.prototype.dispatchEvent=hu.prototype.b;hu.prototype.getRevision=hu.prototype.K;hu.prototype.on=hu.prototype.I;hu.prototype.once=hu.prototype.L;hu.prototype.un=hu.prototype.J;hu.prototype.unByKey=hu.prototype.M;ku.prototype.type=ku.prototype.type;ku.prototype.target=ku.prototype.target;
+ku.prototype.preventDefault=ku.prototype.preventDefault;ku.prototype.stopPropagation=ku.prototype.stopPropagation;xi.prototype.type=xi.prototype.type;xi.prototype.target=xi.prototype.target;xi.prototype.preventDefault=xi.prototype.preventDefault;xi.prototype.stopPropagation=xi.prototype.stopPropagation;ji.prototype.getActive=ji.prototype.f;ji.prototype.getMap=ji.prototype.l;ji.prototype.setActive=ji.prototype.i;ji.prototype.get=ji.prototype.get;ji.prototype.getKeys=ji.prototype.N;
+ji.prototype.getProperties=ji.prototype.O;ji.prototype.set=ji.prototype.set;ji.prototype.setProperties=ji.prototype.G;ji.prototype.unset=ji.prototype.P;ji.prototype.changed=ji.prototype.u;ji.prototype.dispatchEvent=ji.prototype.b;ji.prototype.getRevision=ji.prototype.K;ji.prototype.on=ji.prototype.I;ji.prototype.once=ji.prototype.L;ji.prototype.un=ji.prototype.J;ji.prototype.unByKey=ji.prototype.M;yi.prototype.getActive=yi.prototype.f;yi.prototype.getMap=yi.prototype.l;yi.prototype.setActive=yi.prototype.i;
+yi.prototype.get=yi.prototype.get;yi.prototype.getKeys=yi.prototype.N;yi.prototype.getProperties=yi.prototype.O;yi.prototype.set=yi.prototype.set;yi.prototype.setProperties=yi.prototype.G;yi.prototype.unset=yi.prototype.P;yi.prototype.changed=yi.prototype.u;yi.prototype.dispatchEvent=yi.prototype.b;yi.prototype.getRevision=yi.prototype.K;yi.prototype.on=yi.prototype.I;yi.prototype.once=yi.prototype.L;yi.prototype.un=yi.prototype.J;yi.prototype.unByKey=yi.prototype.M;mi.prototype.getActive=mi.prototype.f;
+mi.prototype.getMap=mi.prototype.l;mi.prototype.setActive=mi.prototype.i;mi.prototype.get=mi.prototype.get;mi.prototype.getKeys=mi.prototype.N;mi.prototype.getProperties=mi.prototype.O;mi.prototype.set=mi.prototype.set;mi.prototype.setProperties=mi.prototype.G;mi.prototype.unset=mi.prototype.P;mi.prototype.changed=mi.prototype.u;mi.prototype.dispatchEvent=mi.prototype.b;mi.prototype.getRevision=mi.prototype.K;mi.prototype.on=mi.prototype.I;mi.prototype.once=mi.prototype.L;mi.prototype.un=mi.prototype.J;
+mi.prototype.unByKey=mi.prototype.M;mu.prototype.getActive=mu.prototype.f;mu.prototype.getMap=mu.prototype.l;mu.prototype.setActive=mu.prototype.i;mu.prototype.get=mu.prototype.get;mu.prototype.getKeys=mu.prototype.N;mu.prototype.getProperties=mu.prototype.O;mu.prototype.set=mu.prototype.set;mu.prototype.setProperties=mu.prototype.G;mu.prototype.unset=mu.prototype.P;mu.prototype.changed=mu.prototype.u;mu.prototype.dispatchEvent=mu.prototype.b;mu.prototype.getRevision=mu.prototype.K;
+mu.prototype.on=mu.prototype.I;mu.prototype.once=mu.prototype.L;mu.prototype.un=mu.prototype.J;mu.prototype.unByKey=mu.prototype.M;qi.prototype.getActive=qi.prototype.f;qi.prototype.getMap=qi.prototype.l;qi.prototype.setActive=qi.prototype.i;qi.prototype.get=qi.prototype.get;qi.prototype.getKeys=qi.prototype.N;qi.prototype.getProperties=qi.prototype.O;qi.prototype.set=qi.prototype.set;qi.prototype.setProperties=qi.prototype.G;qi.prototype.unset=qi.prototype.P;qi.prototype.changed=qi.prototype.u;
+qi.prototype.dispatchEvent=qi.prototype.b;qi.prototype.getRevision=qi.prototype.K;qi.prototype.on=qi.prototype.I;qi.prototype.once=qi.prototype.L;qi.prototype.un=qi.prototype.J;qi.prototype.unByKey=qi.prototype.M;Di.prototype.getGeometry=Di.prototype.W;Di.prototype.getActive=Di.prototype.f;Di.prototype.getMap=Di.prototype.l;Di.prototype.setActive=Di.prototype.i;Di.prototype.get=Di.prototype.get;Di.prototype.getKeys=Di.prototype.N;Di.prototype.getProperties=Di.prototype.O;Di.prototype.set=Di.prototype.set;
+Di.prototype.setProperties=Di.prototype.G;Di.prototype.unset=Di.prototype.P;Di.prototype.changed=Di.prototype.u;Di.prototype.dispatchEvent=Di.prototype.b;Di.prototype.getRevision=Di.prototype.K;Di.prototype.on=Di.prototype.I;Di.prototype.once=Di.prototype.L;Di.prototype.un=Di.prototype.J;Di.prototype.unByKey=Di.prototype.M;qu.prototype.type=qu.prototype.type;qu.prototype.target=qu.prototype.target;qu.prototype.preventDefault=qu.prototype.preventDefault;qu.prototype.stopPropagation=qu.prototype.stopPropagation;
+ru.prototype.getActive=ru.prototype.f;ru.prototype.getMap=ru.prototype.l;ru.prototype.setActive=ru.prototype.i;ru.prototype.get=ru.prototype.get;ru.prototype.getKeys=ru.prototype.N;ru.prototype.getProperties=ru.prototype.O;ru.prototype.set=ru.prototype.set;ru.prototype.setProperties=ru.prototype.G;ru.prototype.unset=ru.prototype.P;ru.prototype.changed=ru.prototype.u;ru.prototype.dispatchEvent=ru.prototype.b;ru.prototype.getRevision=ru.prototype.K;ru.prototype.on=ru.prototype.I;ru.prototype.once=ru.prototype.L;
+ru.prototype.un=ru.prototype.J;ru.prototype.unByKey=ru.prototype.M;Ei.prototype.getActive=Ei.prototype.f;Ei.prototype.getMap=Ei.prototype.l;Ei.prototype.setActive=Ei.prototype.i;Ei.prototype.get=Ei.prototype.get;Ei.prototype.getKeys=Ei.prototype.N;Ei.prototype.getProperties=Ei.prototype.O;Ei.prototype.set=Ei.prototype.set;Ei.prototype.setProperties=Ei.prototype.G;Ei.prototype.unset=Ei.prototype.P;Ei.prototype.changed=Ei.prototype.u;Ei.prototype.dispatchEvent=Ei.prototype.b;
+Ei.prototype.getRevision=Ei.prototype.K;Ei.prototype.on=Ei.prototype.I;Ei.prototype.once=Ei.prototype.L;Ei.prototype.un=Ei.prototype.J;Ei.prototype.unByKey=Ei.prototype.M;Gi.prototype.getActive=Gi.prototype.f;Gi.prototype.getMap=Gi.prototype.l;Gi.prototype.setActive=Gi.prototype.i;Gi.prototype.get=Gi.prototype.get;Gi.prototype.getKeys=Gi.prototype.N;Gi.prototype.getProperties=Gi.prototype.O;Gi.prototype.set=Gi.prototype.set;Gi.prototype.setProperties=Gi.prototype.G;Gi.prototype.unset=Gi.prototype.P;
+Gi.prototype.changed=Gi.prototype.u;Gi.prototype.dispatchEvent=Gi.prototype.b;Gi.prototype.getRevision=Gi.prototype.K;Gi.prototype.on=Gi.prototype.I;Gi.prototype.once=Gi.prototype.L;Gi.prototype.un=Gi.prototype.J;Gi.prototype.unByKey=Gi.prototype.M;Hu.prototype.type=Hu.prototype.type;Hu.prototype.target=Hu.prototype.target;Hu.prototype.preventDefault=Hu.prototype.preventDefault;Hu.prototype.stopPropagation=Hu.prototype.stopPropagation;Iu.prototype.getActive=Iu.prototype.f;Iu.prototype.getMap=Iu.prototype.l;
+Iu.prototype.setActive=Iu.prototype.i;Iu.prototype.get=Iu.prototype.get;Iu.prototype.getKeys=Iu.prototype.N;Iu.prototype.getProperties=Iu.prototype.O;Iu.prototype.set=Iu.prototype.set;Iu.prototype.setProperties=Iu.prototype.G;Iu.prototype.unset=Iu.prototype.P;Iu.prototype.changed=Iu.prototype.u;Iu.prototype.dispatchEvent=Iu.prototype.b;Iu.prototype.getRevision=Iu.prototype.K;Iu.prototype.on=Iu.prototype.I;Iu.prototype.once=Iu.prototype.L;Iu.prototype.un=Iu.prototype.J;Iu.prototype.unByKey=Iu.prototype.M;
+Ii.prototype.getActive=Ii.prototype.f;Ii.prototype.getMap=Ii.prototype.l;Ii.prototype.setActive=Ii.prototype.i;Ii.prototype.get=Ii.prototype.get;Ii.prototype.getKeys=Ii.prototype.N;Ii.prototype.getProperties=Ii.prototype.O;Ii.prototype.set=Ii.prototype.set;Ii.prototype.setProperties=Ii.prototype.G;Ii.prototype.unset=Ii.prototype.P;Ii.prototype.changed=Ii.prototype.u;Ii.prototype.dispatchEvent=Ii.prototype.b;Ii.prototype.getRevision=Ii.prototype.K;Ii.prototype.on=Ii.prototype.I;Ii.prototype.once=Ii.prototype.L;
+Ii.prototype.un=Ii.prototype.J;Ii.prototype.unByKey=Ii.prototype.M;Ki.prototype.getActive=Ki.prototype.f;Ki.prototype.getMap=Ki.prototype.l;Ki.prototype.setActive=Ki.prototype.i;Ki.prototype.get=Ki.prototype.get;Ki.prototype.getKeys=Ki.prototype.N;Ki.prototype.getProperties=Ki.prototype.O;Ki.prototype.set=Ki.prototype.set;Ki.prototype.setProperties=Ki.prototype.G;Ki.prototype.unset=Ki.prototype.P;Ki.prototype.changed=Ki.prototype.u;Ki.prototype.dispatchEvent=Ki.prototype.b;
+Ki.prototype.getRevision=Ki.prototype.K;Ki.prototype.on=Ki.prototype.I;Ki.prototype.once=Ki.prototype.L;Ki.prototype.un=Ki.prototype.J;Ki.prototype.unByKey=Ki.prototype.M;Oi.prototype.getActive=Oi.prototype.f;Oi.prototype.getMap=Oi.prototype.l;Oi.prototype.setActive=Oi.prototype.i;Oi.prototype.get=Oi.prototype.get;Oi.prototype.getKeys=Oi.prototype.N;Oi.prototype.getProperties=Oi.prototype.O;Oi.prototype.set=Oi.prototype.set;Oi.prototype.setProperties=Oi.prototype.G;Oi.prototype.unset=Oi.prototype.P;
+Oi.prototype.changed=Oi.prototype.u;Oi.prototype.dispatchEvent=Oi.prototype.b;Oi.prototype.getRevision=Oi.prototype.K;Oi.prototype.on=Oi.prototype.I;Oi.prototype.once=Oi.prototype.L;Oi.prototype.un=Oi.prototype.J;Oi.prototype.unByKey=Oi.prototype.M;Vu.prototype.type=Vu.prototype.type;Vu.prototype.target=Vu.prototype.target;Vu.prototype.preventDefault=Vu.prototype.preventDefault;Vu.prototype.stopPropagation=Vu.prototype.stopPropagation;Wu.prototype.getActive=Wu.prototype.f;Wu.prototype.getMap=Wu.prototype.l;
+Wu.prototype.setActive=Wu.prototype.i;Wu.prototype.get=Wu.prototype.get;Wu.prototype.getKeys=Wu.prototype.N;Wu.prototype.getProperties=Wu.prototype.O;Wu.prototype.set=Wu.prototype.set;Wu.prototype.setProperties=Wu.prototype.G;Wu.prototype.unset=Wu.prototype.P;Wu.prototype.changed=Wu.prototype.u;Wu.prototype.dispatchEvent=Wu.prototype.b;Wu.prototype.getRevision=Wu.prototype.K;Wu.prototype.on=Wu.prototype.I;Wu.prototype.once=Wu.prototype.L;Wu.prototype.un=Wu.prototype.J;Wu.prototype.unByKey=Wu.prototype.M;
+Zu.prototype.getActive=Zu.prototype.f;Zu.prototype.getMap=Zu.prototype.l;Zu.prototype.setActive=Zu.prototype.i;Zu.prototype.get=Zu.prototype.get;Zu.prototype.getKeys=Zu.prototype.N;Zu.prototype.getProperties=Zu.prototype.O;Zu.prototype.set=Zu.prototype.set;Zu.prototype.setProperties=Zu.prototype.G;Zu.prototype.unset=Zu.prototype.P;Zu.prototype.changed=Zu.prototype.u;Zu.prototype.dispatchEvent=Zu.prototype.b;Zu.prototype.getRevision=Zu.prototype.K;Zu.prototype.on=Zu.prototype.I;Zu.prototype.once=Zu.prototype.L;
+Zu.prototype.un=Zu.prototype.J;Zu.prototype.unByKey=Zu.prototype.M;cv.prototype.type=cv.prototype.type;cv.prototype.target=cv.prototype.target;cv.prototype.preventDefault=cv.prototype.preventDefault;cv.prototype.stopPropagation=cv.prototype.stopPropagation;dv.prototype.getActive=dv.prototype.f;dv.prototype.getMap=dv.prototype.l;dv.prototype.setActive=dv.prototype.i;dv.prototype.get=dv.prototype.get;dv.prototype.getKeys=dv.prototype.N;dv.prototype.getProperties=dv.prototype.O;dv.prototype.set=dv.prototype.set;
+dv.prototype.setProperties=dv.prototype.G;dv.prototype.unset=dv.prototype.P;dv.prototype.changed=dv.prototype.u;dv.prototype.dispatchEvent=dv.prototype.b;dv.prototype.getRevision=dv.prototype.K;dv.prototype.on=dv.prototype.I;dv.prototype.once=dv.prototype.L;dv.prototype.un=dv.prototype.J;dv.prototype.unByKey=dv.prototype.M;Tc.prototype.get=Tc.prototype.get;Tc.prototype.getKeys=Tc.prototype.N;Tc.prototype.getProperties=Tc.prototype.O;Tc.prototype.set=Tc.prototype.set;Tc.prototype.setProperties=Tc.prototype.G;
+Tc.prototype.unset=Tc.prototype.P;Tc.prototype.changed=Tc.prototype.u;Tc.prototype.dispatchEvent=Tc.prototype.b;Tc.prototype.getRevision=Tc.prototype.K;Tc.prototype.on=Tc.prototype.I;Tc.prototype.once=Tc.prototype.L;Tc.prototype.un=Tc.prototype.J;Tc.prototype.unByKey=Tc.prototype.M;hd.prototype.getClosestPoint=hd.prototype.vb;hd.prototype.getExtent=hd.prototype.H;hd.prototype.rotate=hd.prototype.rotate;hd.prototype.simplify=hd.prototype.Bb;hd.prototype.transform=hd.prototype.jb;hd.prototype.get=hd.prototype.get;
+hd.prototype.getKeys=hd.prototype.N;hd.prototype.getProperties=hd.prototype.O;hd.prototype.set=hd.prototype.set;hd.prototype.setProperties=hd.prototype.G;hd.prototype.unset=hd.prototype.P;hd.prototype.changed=hd.prototype.u;hd.prototype.dispatchEvent=hd.prototype.b;hd.prototype.getRevision=hd.prototype.K;hd.prototype.on=hd.prototype.I;hd.prototype.once=hd.prototype.L;hd.prototype.un=hd.prototype.J;hd.prototype.unByKey=hd.prototype.M;Vt.prototype.getFirstCoordinate=Vt.prototype.Ib;
+Vt.prototype.getLastCoordinate=Vt.prototype.Jb;Vt.prototype.getLayout=Vt.prototype.Kb;Vt.prototype.rotate=Vt.prototype.rotate;Vt.prototype.getClosestPoint=Vt.prototype.vb;Vt.prototype.getExtent=Vt.prototype.H;Vt.prototype.simplify=Vt.prototype.Bb;Vt.prototype.get=Vt.prototype.get;Vt.prototype.getKeys=Vt.prototype.N;Vt.prototype.getProperties=Vt.prototype.O;Vt.prototype.set=Vt.prototype.set;Vt.prototype.setProperties=Vt.prototype.G;Vt.prototype.unset=Vt.prototype.P;Vt.prototype.changed=Vt.prototype.u;
+Vt.prototype.dispatchEvent=Vt.prototype.b;Vt.prototype.getRevision=Vt.prototype.K;Vt.prototype.on=Vt.prototype.I;Vt.prototype.once=Vt.prototype.L;Vt.prototype.un=Vt.prototype.J;Vt.prototype.unByKey=Vt.prototype.M;Ln.prototype.getClosestPoint=Ln.prototype.vb;Ln.prototype.getExtent=Ln.prototype.H;Ln.prototype.rotate=Ln.prototype.rotate;Ln.prototype.simplify=Ln.prototype.Bb;Ln.prototype.transform=Ln.prototype.jb;Ln.prototype.get=Ln.prototype.get;Ln.prototype.getKeys=Ln.prototype.N;
+Ln.prototype.getProperties=Ln.prototype.O;Ln.prototype.set=Ln.prototype.set;Ln.prototype.setProperties=Ln.prototype.G;Ln.prototype.unset=Ln.prototype.P;Ln.prototype.changed=Ln.prototype.u;Ln.prototype.dispatchEvent=Ln.prototype.b;Ln.prototype.getRevision=Ln.prototype.K;Ln.prototype.on=Ln.prototype.I;Ln.prototype.once=Ln.prototype.L;Ln.prototype.un=Ln.prototype.J;Ln.prototype.unByKey=Ln.prototype.M;zd.prototype.getFirstCoordinate=zd.prototype.Ib;zd.prototype.getLastCoordinate=zd.prototype.Jb;
+zd.prototype.getLayout=zd.prototype.Kb;zd.prototype.rotate=zd.prototype.rotate;zd.prototype.getClosestPoint=zd.prototype.vb;zd.prototype.getExtent=zd.prototype.H;zd.prototype.simplify=zd.prototype.Bb;zd.prototype.transform=zd.prototype.jb;zd.prototype.get=zd.prototype.get;zd.prototype.getKeys=zd.prototype.N;zd.prototype.getProperties=zd.prototype.O;zd.prototype.set=zd.prototype.set;zd.prototype.setProperties=zd.prototype.G;zd.prototype.unset=zd.prototype.P;zd.prototype.changed=zd.prototype.u;
+zd.prototype.dispatchEvent=zd.prototype.b;zd.prototype.getRevision=zd.prototype.K;zd.prototype.on=zd.prototype.I;zd.prototype.once=zd.prototype.L;zd.prototype.un=zd.prototype.J;zd.prototype.unByKey=zd.prototype.M;R.prototype.getFirstCoordinate=R.prototype.Ib;R.prototype.getLastCoordinate=R.prototype.Jb;R.prototype.getLayout=R.prototype.Kb;R.prototype.rotate=R.prototype.rotate;R.prototype.getClosestPoint=R.prototype.vb;R.prototype.getExtent=R.prototype.H;R.prototype.simplify=R.prototype.Bb;
+R.prototype.transform=R.prototype.jb;R.prototype.get=R.prototype.get;R.prototype.getKeys=R.prototype.N;R.prototype.getProperties=R.prototype.O;R.prototype.set=R.prototype.set;R.prototype.setProperties=R.prototype.G;R.prototype.unset=R.prototype.P;R.prototype.changed=R.prototype.u;R.prototype.dispatchEvent=R.prototype.b;R.prototype.getRevision=R.prototype.K;R.prototype.on=R.prototype.I;R.prototype.once=R.prototype.L;R.prototype.un=R.prototype.J;R.prototype.unByKey=R.prototype.M;
+S.prototype.getFirstCoordinate=S.prototype.Ib;S.prototype.getLastCoordinate=S.prototype.Jb;S.prototype.getLayout=S.prototype.Kb;S.prototype.rotate=S.prototype.rotate;S.prototype.getClosestPoint=S.prototype.vb;S.prototype.getExtent=S.prototype.H;S.prototype.simplify=S.prototype.Bb;S.prototype.transform=S.prototype.jb;S.prototype.get=S.prototype.get;S.prototype.getKeys=S.prototype.N;S.prototype.getProperties=S.prototype.O;S.prototype.set=S.prototype.set;S.prototype.setProperties=S.prototype.G;
+S.prototype.unset=S.prototype.P;S.prototype.changed=S.prototype.u;S.prototype.dispatchEvent=S.prototype.b;S.prototype.getRevision=S.prototype.K;S.prototype.on=S.prototype.I;S.prototype.once=S.prototype.L;S.prototype.un=S.prototype.J;S.prototype.unByKey=S.prototype.M;Bn.prototype.getFirstCoordinate=Bn.prototype.Ib;Bn.prototype.getLastCoordinate=Bn.prototype.Jb;Bn.prototype.getLayout=Bn.prototype.Kb;Bn.prototype.rotate=Bn.prototype.rotate;Bn.prototype.getClosestPoint=Bn.prototype.vb;
+Bn.prototype.getExtent=Bn.prototype.H;Bn.prototype.simplify=Bn.prototype.Bb;Bn.prototype.transform=Bn.prototype.jb;Bn.prototype.get=Bn.prototype.get;Bn.prototype.getKeys=Bn.prototype.N;Bn.prototype.getProperties=Bn.prototype.O;Bn.prototype.set=Bn.prototype.set;Bn.prototype.setProperties=Bn.prototype.G;Bn.prototype.unset=Bn.prototype.P;Bn.prototype.changed=Bn.prototype.u;Bn.prototype.dispatchEvent=Bn.prototype.b;Bn.prototype.getRevision=Bn.prototype.K;Bn.prototype.on=Bn.prototype.I;
+Bn.prototype.once=Bn.prototype.L;Bn.prototype.un=Bn.prototype.J;Bn.prototype.unByKey=Bn.prototype.M;T.prototype.getFirstCoordinate=T.prototype.Ib;T.prototype.getLastCoordinate=T.prototype.Jb;T.prototype.getLayout=T.prototype.Kb;T.prototype.rotate=T.prototype.rotate;T.prototype.getClosestPoint=T.prototype.vb;T.prototype.getExtent=T.prototype.H;T.prototype.simplify=T.prototype.Bb;T.prototype.transform=T.prototype.jb;T.prototype.get=T.prototype.get;T.prototype.getKeys=T.prototype.N;
+T.prototype.getProperties=T.prototype.O;T.prototype.set=T.prototype.set;T.prototype.setProperties=T.prototype.G;T.prototype.unset=T.prototype.P;T.prototype.changed=T.prototype.u;T.prototype.dispatchEvent=T.prototype.b;T.prototype.getRevision=T.prototype.K;T.prototype.on=T.prototype.I;T.prototype.once=T.prototype.L;T.prototype.un=T.prototype.J;T.prototype.unByKey=T.prototype.M;C.prototype.getFirstCoordinate=C.prototype.Ib;C.prototype.getLastCoordinate=C.prototype.Jb;C.prototype.getLayout=C.prototype.Kb;
+C.prototype.rotate=C.prototype.rotate;C.prototype.getClosestPoint=C.prototype.vb;C.prototype.getExtent=C.prototype.H;C.prototype.simplify=C.prototype.Bb;C.prototype.transform=C.prototype.jb;C.prototype.get=C.prototype.get;C.prototype.getKeys=C.prototype.N;C.prototype.getProperties=C.prototype.O;C.prototype.set=C.prototype.set;C.prototype.setProperties=C.prototype.G;C.prototype.unset=C.prototype.P;C.prototype.changed=C.prototype.u;C.prototype.dispatchEvent=C.prototype.b;C.prototype.getRevision=C.prototype.K;
+C.prototype.on=C.prototype.I;C.prototype.once=C.prototype.L;C.prototype.un=C.prototype.J;C.prototype.unByKey=C.prototype.M;E.prototype.getFirstCoordinate=E.prototype.Ib;E.prototype.getLastCoordinate=E.prototype.Jb;E.prototype.getLayout=E.prototype.Kb;E.prototype.rotate=E.prototype.rotate;E.prototype.getClosestPoint=E.prototype.vb;E.prototype.getExtent=E.prototype.H;E.prototype.simplify=E.prototype.Bb;E.prototype.transform=E.prototype.jb;E.prototype.get=E.prototype.get;E.prototype.getKeys=E.prototype.N;
+E.prototype.getProperties=E.prototype.O;E.prototype.set=E.prototype.set;E.prototype.setProperties=E.prototype.G;E.prototype.unset=E.prototype.P;E.prototype.changed=E.prototype.u;E.prototype.dispatchEvent=E.prototype.b;E.prototype.getRevision=E.prototype.K;E.prototype.on=E.prototype.I;E.prototype.once=E.prototype.L;E.prototype.un=E.prototype.J;E.prototype.unByKey=E.prototype.M;ko.prototype.readFeatures=ko.prototype.Fa;lo.prototype.readFeatures=lo.prototype.Fa;lo.prototype.readFeatures=lo.prototype.Fa;
+Xe.prototype.get=Xe.prototype.get;Xe.prototype.getKeys=Xe.prototype.N;Xe.prototype.getProperties=Xe.prototype.O;Xe.prototype.set=Xe.prototype.set;Xe.prototype.setProperties=Xe.prototype.G;Xe.prototype.unset=Xe.prototype.P;Xe.prototype.changed=Xe.prototype.u;Xe.prototype.dispatchEvent=Xe.prototype.b;Xe.prototype.getRevision=Xe.prototype.K;Xe.prototype.on=Xe.prototype.I;Xe.prototype.once=Xe.prototype.L;Xe.prototype.un=Xe.prototype.J;Xe.prototype.unByKey=Xe.prototype.M;Ef.prototype.getMap=Ef.prototype.i;
+Ef.prototype.setMap=Ef.prototype.setMap;Ef.prototype.setTarget=Ef.prototype.c;Ef.prototype.get=Ef.prototype.get;Ef.prototype.getKeys=Ef.prototype.N;Ef.prototype.getProperties=Ef.prototype.O;Ef.prototype.set=Ef.prototype.set;Ef.prototype.setProperties=Ef.prototype.G;Ef.prototype.unset=Ef.prototype.P;Ef.prototype.changed=Ef.prototype.u;Ef.prototype.dispatchEvent=Ef.prototype.b;Ef.prototype.getRevision=Ef.prototype.K;Ef.prototype.on=Ef.prototype.I;Ef.prototype.once=Ef.prototype.L;Ef.prototype.un=Ef.prototype.J;
+Ef.prototype.unByKey=Ef.prototype.M;Lf.prototype.getMap=Lf.prototype.i;Lf.prototype.setMap=Lf.prototype.setMap;Lf.prototype.setTarget=Lf.prototype.c;Lf.prototype.get=Lf.prototype.get;Lf.prototype.getKeys=Lf.prototype.N;Lf.prototype.getProperties=Lf.prototype.O;Lf.prototype.set=Lf.prototype.set;Lf.prototype.setProperties=Lf.prototype.G;Lf.prototype.unset=Lf.prototype.P;Lf.prototype.changed=Lf.prototype.u;Lf.prototype.dispatchEvent=Lf.prototype.b;Lf.prototype.getRevision=Lf.prototype.K;
+Lf.prototype.on=Lf.prototype.I;Lf.prototype.once=Lf.prototype.L;Lf.prototype.un=Lf.prototype.J;Lf.prototype.unByKey=Lf.prototype.M;Qf.prototype.getMap=Qf.prototype.i;Qf.prototype.setMap=Qf.prototype.setMap;Qf.prototype.setTarget=Qf.prototype.c;Qf.prototype.get=Qf.prototype.get;Qf.prototype.getKeys=Qf.prototype.N;Qf.prototype.getProperties=Qf.prototype.O;Qf.prototype.set=Qf.prototype.set;Qf.prototype.setProperties=Qf.prototype.G;Qf.prototype.unset=Qf.prototype.P;Qf.prototype.changed=Qf.prototype.u;
+Qf.prototype.dispatchEvent=Qf.prototype.b;Qf.prototype.getRevision=Qf.prototype.K;Qf.prototype.on=Qf.prototype.I;Qf.prototype.once=Qf.prototype.L;Qf.prototype.un=Qf.prototype.J;Qf.prototype.unByKey=Qf.prototype.M;an.prototype.getMap=an.prototype.i;an.prototype.setMap=an.prototype.setMap;an.prototype.setTarget=an.prototype.c;an.prototype.get=an.prototype.get;an.prototype.getKeys=an.prototype.N;an.prototype.getProperties=an.prototype.O;an.prototype.set=an.prototype.set;an.prototype.setProperties=an.prototype.G;
+an.prototype.unset=an.prototype.P;an.prototype.changed=an.prototype.u;an.prototype.dispatchEvent=an.prototype.b;an.prototype.getRevision=an.prototype.K;an.prototype.on=an.prototype.I;an.prototype.once=an.prototype.L;an.prototype.un=an.prototype.J;an.prototype.unByKey=an.prototype.M;Hf.prototype.getMap=Hf.prototype.i;Hf.prototype.setMap=Hf.prototype.setMap;Hf.prototype.setTarget=Hf.prototype.c;Hf.prototype.get=Hf.prototype.get;Hf.prototype.getKeys=Hf.prototype.N;Hf.prototype.getProperties=Hf.prototype.O;
+Hf.prototype.set=Hf.prototype.set;Hf.prototype.setProperties=Hf.prototype.G;Hf.prototype.unset=Hf.prototype.P;Hf.prototype.changed=Hf.prototype.u;Hf.prototype.dispatchEvent=Hf.prototype.b;Hf.prototype.getRevision=Hf.prototype.K;Hf.prototype.on=Hf.prototype.I;Hf.prototype.once=Hf.prototype.L;Hf.prototype.un=Hf.prototype.J;Hf.prototype.unByKey=Hf.prototype.M;fn.prototype.getMap=fn.prototype.i;fn.prototype.setMap=fn.prototype.setMap;fn.prototype.setTarget=fn.prototype.c;fn.prototype.get=fn.prototype.get;
+fn.prototype.getKeys=fn.prototype.N;fn.prototype.getProperties=fn.prototype.O;fn.prototype.set=fn.prototype.set;fn.prototype.setProperties=fn.prototype.G;fn.prototype.unset=fn.prototype.P;fn.prototype.changed=fn.prototype.u;fn.prototype.dispatchEvent=fn.prototype.b;fn.prototype.getRevision=fn.prototype.K;fn.prototype.on=fn.prototype.I;fn.prototype.once=fn.prototype.L;fn.prototype.un=fn.prototype.J;fn.prototype.unByKey=fn.prototype.M;Jf.prototype.getMap=Jf.prototype.i;Jf.prototype.setMap=Jf.prototype.setMap;
+Jf.prototype.setTarget=Jf.prototype.c;Jf.prototype.get=Jf.prototype.get;Jf.prototype.getKeys=Jf.prototype.N;Jf.prototype.getProperties=Jf.prototype.O;Jf.prototype.set=Jf.prototype.set;Jf.prototype.setProperties=Jf.prototype.G;Jf.prototype.unset=Jf.prototype.P;Jf.prototype.changed=Jf.prototype.u;Jf.prototype.dispatchEvent=Jf.prototype.b;Jf.prototype.getRevision=Jf.prototype.K;Jf.prototype.on=Jf.prototype.I;Jf.prototype.once=Jf.prototype.L;Jf.prototype.un=Jf.prototype.J;Jf.prototype.unByKey=Jf.prototype.M;
+kn.prototype.getMap=kn.prototype.i;kn.prototype.setMap=kn.prototype.setMap;kn.prototype.setTarget=kn.prototype.c;kn.prototype.get=kn.prototype.get;kn.prototype.getKeys=kn.prototype.N;kn.prototype.getProperties=kn.prototype.O;kn.prototype.set=kn.prototype.set;kn.prototype.setProperties=kn.prototype.G;kn.prototype.unset=kn.prototype.P;kn.prototype.changed=kn.prototype.u;kn.prototype.dispatchEvent=kn.prototype.b;kn.prototype.getRevision=kn.prototype.K;kn.prototype.on=kn.prototype.I;
+kn.prototype.once=kn.prototype.L;kn.prototype.un=kn.prototype.J;kn.prototype.unByKey=kn.prototype.M;pn.prototype.getMap=pn.prototype.i;pn.prototype.setMap=pn.prototype.setMap;pn.prototype.setTarget=pn.prototype.c;pn.prototype.get=pn.prototype.get;pn.prototype.getKeys=pn.prototype.N;pn.prototype.getProperties=pn.prototype.O;pn.prototype.set=pn.prototype.set;pn.prototype.setProperties=pn.prototype.G;pn.prototype.unset=pn.prototype.P;pn.prototype.changed=pn.prototype.u;pn.prototype.dispatchEvent=pn.prototype.b;
+pn.prototype.getRevision=pn.prototype.K;pn.prototype.on=pn.prototype.I;pn.prototype.once=pn.prototype.L;pn.prototype.un=pn.prototype.J;pn.prototype.unByKey=pn.prototype.M;
+ return OPENLAYERS.ol;
+}));
+
diff --git a/chimere/static/openlayers/OpenLayers.js b/chimere/static/openlayers/OpenLayers.js
deleted file mode 100644
index 669778d..0000000
--- a/chimere/static/openlayers/OpenLayers.js
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*
-
- OpenLayers.js -- OpenLayers Map Viewer Library
-
- Copyright (c) 2006-2013 by OpenLayers Contributors
- Published under the 2-clause BSD license.
- See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
-
- Includes compressed code under the following licenses:
-
- (For uncompressed versions of the code used, please see the
- OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
-
-*/
-
-/**
- * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
- * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- */
-
-/**
- * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
- * Copyright (c) 2006, Yahoo! Inc.
- * All rights reserved.
- *
- * Redistribution and use of this software in source and binary forms, with or
- * without modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission of Yahoo! Inc.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-var OpenLayers={VERSION_NUMBER:"Release 2.13.1",singleFile:!0,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers[^\/]*?\.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e<f;e++)if(c=b[e].getAttribute("src"))if(c=c.match(a)){d=c[1];break}return function(){return d}}(),ImgPath:""};OpenLayers.Class=function(){var a=arguments.length,b=arguments[0],c=arguments[a-1],d="function"==typeof c.initialize?c.initialize:function(){b.prototype.initialize.apply(this,arguments)};1<a?(a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c),OpenLayers.inherit.apply(null,a)):d.prototype=c;return d};
-OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e,c=2;for(d=arguments.length;c<d;c++)e=arguments[c],"function"===typeof e&&(e=e.prototype),OpenLayers.Util.extend(a.prototype,e)};OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.extend=function(a,b){a=a||{};if(b){for(var c in b){var d=b[c];void 0!==d&&(a[c]=d)}"function"==typeof window.Event&&b instanceof window.Event||(!b.hasOwnProperty||!b.hasOwnProperty("toString"))||(a.toString=b.toString)}return a};OpenLayers.String={startsWith:function(a,b){return 0==a.indexOf(b)},contains:function(a,b){return-1!=a.indexOf(b)},trim:function(a){return a.replace(/^\s\s*/,"").replace(/\s\s*$/,"")},camelize:function(a){a=a.split("-");for(var b=a[0],c=1,d=a.length;c<d;c++)var e=a[c],b=b+(e.charAt(0).toUpperCase()+e.substring(1));return b},format:function(a,b,c){b||(b=window);return a.replace(OpenLayers.String.tokenRegEx,function(a,e){for(var f,g=e.split(/\.+/),h=0;h<g.length;h++){0==h&&(f=b);if(void 0===f)break;
-f=f[g[h]]}"function"==typeof f&&(f=c?f.apply(null,c):f());return"undefined"==typeof f?"undefined":f})},tokenRegEx:/\$\{([\w.]+?)\}/g,numberRegEx:/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,isNumeric:function(a){return OpenLayers.String.numberRegEx.test(a)},numericIf:function(a,b){var c=a;!0===b&&(null!=a&&a.replace)&&(a=a.replace(/^\s*|\s*$/g,""));return OpenLayers.String.isNumeric(a)?parseFloat(a):c}};
-OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(a,b){var c=0;0<b&&(c=parseFloat(a.toPrecision(b)));return c},format:function(a,b,c,d){b="undefined"!=typeof b?b:0;c="undefined"!=typeof c?c:OpenLayers.Number.thousandsSeparator;d="undefined"!=typeof d?d:OpenLayers.Number.decimalSeparator;null!=b&&(a=parseFloat(a.toFixed(b)));var e=a.toString().split(".");1==e.length&&null==b&&(b=0);a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2");
-0==b?b=a:(c=1<e.length?e[1]:"0",null!=b&&(c+=Array(b-c.length+1).join("0")),b=a+d+c);return b},zeroPad:function(a,b,c){for(a=a.toString(c||10);a.length<b;)a="0"+a;return a}};
-OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return!1},True:function(){return!0},Void:function(){}};
-OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if("function"!=typeof b)throw new TypeError;for(var f=0;f<e;f++)if(f in a){var g=a[f];b.call(c,g,f,a)&&d.push(g)}}return d}};OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,centerLonLat:null,initialize:function(a,b,c,d){OpenLayers.Util.isArray(a)&&(d=a[3],c=a[2],b=a[1],a=a[0]);null!=a&&(this.left=OpenLayers.Util.toFloat(a));null!=b&&(this.bottom=OpenLayers.Util.toFloat(b));null!=c&&(this.right=OpenLayers.Util.toFloat(c));null!=d&&(this.top=OpenLayers.Util.toFloat(d))},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top)},equals:function(a){var b=!1;null!=
-a&&(b=this.left==a.left&&this.right==a.right&&this.top==a.top&&this.bottom==a.bottom);return b},toString:function(){return[this.left,this.bottom,this.right,this.top].join()},toArray:function(a){return!0===a?[this.bottom,this.left,this.top,this.right]:[this.left,this.bottom,this.right,this.top]},toBBOX:function(a,b){null==a&&(a=6);var c=Math.pow(10,a),d=Math.round(this.left*c)/c,e=Math.round(this.bottom*c)/c,f=Math.round(this.right*c)/c,c=Math.round(this.top*c)/c;return!0===b?e+","+d+","+c+","+f:d+
-","+e+","+f+","+c},toGeometry:function(){return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(this.left,this.bottom),new OpenLayers.Geometry.Point(this.right,this.bottom),new OpenLayers.Geometry.Point(this.right,this.top),new OpenLayers.Geometry.Point(this.left,this.top)])])},getWidth:function(){return this.right-this.left},getHeight:function(){return this.top-this.bottom},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight())},
-getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2)},getCenterLonLat:function(){this.centerLonLat||(this.centerLonLat=new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2));return this.centerLonLat},scale:function(a,b){null==b&&(b=this.getCenterLonLat());var c,d;"OpenLayers.LonLat"==b.CLASS_NAME?(c=b.lon,d=b.lat):(c=b.x,d=b.y);return new OpenLayers.Bounds((this.left-c)*a+c,(this.bottom-d)*a+d,(this.right-c)*a+c,(this.top-d)*a+
-d)},add:function(a,b){if(null==a||null==b)throw new TypeError("Bounds.add cannot receive null values");return new OpenLayers.Bounds(this.left+a,this.bottom+b,this.right+a,this.top+b)},extend:function(a){if(a)switch(a.CLASS_NAME){case "OpenLayers.LonLat":this.extendXY(a.lon,a.lat);break;case "OpenLayers.Geometry.Point":this.extendXY(a.x,a.y);break;case "OpenLayers.Bounds":this.centerLonLat=null;if(null==this.left||a.left<this.left)this.left=a.left;if(null==this.bottom||a.bottom<this.bottom)this.bottom=
-a.bottom;if(null==this.right||a.right>this.right)this.right=a.right;if(null==this.top||a.top>this.top)this.top=a.top}},extendXY:function(a,b){this.centerLonLat=null;if(null==this.left||a<this.left)this.left=a;if(null==this.bottom||b<this.bottom)this.bottom=b;if(null==this.right||a>this.right)this.right=a;if(null==this.top||b>this.top)this.top=b},containsLonLat:function(a,b){"boolean"===typeof b&&(b={inclusive:b});b=b||{};var c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;d&&!c&&(c=d.getWidth(),
-d=Math.round((a.lon-(d.left+d.right)/2)/c),c=this.containsLonLat({lon:a.lon-d*c,lat:a.lat},{inclusive:b.inclusive}));return c},containsPixel:function(a,b){return this.contains(a.x,a.y,b)},contains:function(a,b,c){null==c&&(c=!0);if(null==a||null==b)return!1;a=OpenLayers.Util.toFloat(a);b=OpenLayers.Util.toFloat(b);var d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&a<this.right&&b>this.bottom&&b<this.top},intersectsBounds:function(a,b){"boolean"===typeof b&&(b=
-{inclusive:b});b=b||{};if(b.worldBounds){var c=this.wrapDateLine(b.worldBounds);a=a.wrapDateLine(b.worldBounds)}else c=this;null==b.inclusive&&(b.inclusive=!0);var d=!1,e=c.left==a.right||c.right==a.left||c.top==a.bottom||c.bottom==a.top;if(b.inclusive||!e)var d=a.top>=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top<a.top,e=a.left>=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right,f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right,d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=
-a.bottom&&c.bottom<=a.top||d)&&(e||f);if(b.worldBounds&&!d){var g=b.worldBounds,e=g.getWidth(),f=!g.containsBounds(c),g=!g.containsBounds(a);f&&!g?(a=a.add(-e,0),d=c.intersectsBounds(a,{inclusive:b.inclusive})):g&&!f&&(c=c.add(-e,0),d=a.intersectsBounds(c,{inclusive:b.inclusive}))}return d},containsBounds:function(a,b,c){null==b&&(b=!1);null==c&&(c=!0);var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c);a=this.contains(a.right,a.top,c);return b?
-d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat(),b=b+(a.lat<c.lat?"b":"t");return b+=a.lon<c.lon?"l":"r"},transform:function(a,b){this.centerLonLat=null;var c=OpenLayers.Projection.transform({x:this.left,y:this.bottom},a,b),d=OpenLayers.Projection.transform({x:this.right,y:this.bottom},a,b),e=OpenLayers.Projection.transform({x:this.left,y:this.top},a,b),f=OpenLayers.Projection.transform({x:this.right,y:this.top},a,b);this.left=Math.min(c.x,e.x);this.bottom=Math.min(c.y,
-d.y);this.right=Math.max(d.x,f.x);this.top=Math.max(e.y,f.y);return this},wrapDateLine:function(a,b){b=b||{};var c=b.leftTolerance||0,d=b.rightTolerance||0,e=this.clone();if(a){for(var f=a.getWidth();e.left<a.left&&e.right-d<=a.left;)e=e.add(f,0);for(;e.left+c>=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;c<a.right&&(c>a.left&&e.right-d>a.right)&&(e=e.add(-f,0))}return e},CLASS_NAME:"OpenLayers.Bounds"});
-OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return!0===b?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])};OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b;b=""+("t"==a.charAt(0)?"b":"t");return b+="l"==a.charAt(1)?"r":"l"};OpenLayers.Element={visible:function(a){return"none"!=OpenLayers.Util.getElement(a).style.display},toggle:function(){for(var a=0,b=arguments.length;a<b;a++){var c=OpenLayers.Util.getElement(arguments[a]),d=OpenLayers.Element.visible(c)?"none":"";c.style.display=d}},remove:function(a){a=OpenLayers.Util.getElement(a);a.parentNode.removeChild(a)},getHeight:function(a){a=OpenLayers.Util.getElement(a);return a.offsetHeight},hasClass:function(a,b){var c=a.className;return!!c&&RegExp("(^|\\s)"+b+"(\\s|$)").test(c)},
-addClass:function(a,b){OpenLayers.Element.hasClass(a,b)||(a.className+=(a.className?" ":"")+b);return a},removeClass:function(a,b){var c=a.className;c&&(a.className=OpenLayers.String.trim(c.replace(RegExp("(^|\\s+)"+b+"(\\s+|$)")," ")));return a},toggleClass:function(a,b){OpenLayers.Element.hasClass(a,b)?OpenLayers.Element.removeClass(a,b):OpenLayers.Element.addClass(a,b);return a},getStyle:function(a,b){a=OpenLayers.Util.getElement(a);var c=null;if(a&&a.style){c=a.style[OpenLayers.String.camelize(b)];
-c||(document.defaultView&&document.defaultView.getComputedStyle?c=(c=document.defaultView.getComputedStyle(a,null))?c.getPropertyValue(b):null:a.currentStyle&&(c=a.currentStyle[OpenLayers.String.camelize(b)]));var d=["left","top","right","bottom"];window.opera&&(-1!=OpenLayers.Util.indexOf(d,b)&&"static"==OpenLayers.Element.getStyle(a,"position"))&&(c="auto")}return"auto"==c?null:c}};OpenLayers.LonLat=OpenLayers.Class({lon:0,lat:0,initialize:function(a,b){OpenLayers.Util.isArray(a)&&(b=a[1],a=a[0]);this.lon=OpenLayers.Util.toFloat(a);this.lat=OpenLayers.Util.toFloat(b)},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(a,b){if(null==a||null==b)throw new TypeError("LonLat.add cannot receive null values");return new OpenLayers.LonLat(this.lon+
-OpenLayers.Util.toFloat(a),this.lat+OpenLayers.Util.toFloat(b))},equals:function(a){var b=!1;null!=a&&(b=this.lon==a.lon&&this.lat==a.lat||isNaN(this.lon)&&isNaN(this.lat)&&isNaN(a.lon)&&isNaN(a.lat));return b},transform:function(a,b){var c=OpenLayers.Projection.transform({x:this.lon,y:this.lat},a,b);this.lon=c.x;this.lat=c.y;return this},wrapDateLine:function(a){var b=this.clone();if(a){for(;b.lon<a.left;)b.lon+=a.getWidth();for(;b.lon>a.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"});
-OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(null==a||null==b)throw new TypeError("Pixel.add cannot receive null values");
-return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;null!=a&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};
-(function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;b<c;++b)if(-1!=a[b].src.indexOf("firebug.js")&&console){OpenLayers.Util.extend(OpenLayers.Console,console);break}})();OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){OpenLayers.Lang.code||OpenLayers.Lang.setCode();return OpenLayers.Lang.code},setCode:function(a){var b;a||(a="msie"==OpenLayers.BROWSER_NAME?navigator.userLanguage:navigator.language);a=a.split("-");a[0]=a[0].toLowerCase();"object"==typeof OpenLayers.Lang[a[0]]&&(b=a[0]);if(a[1]){var c=a[0]+"-"+a[1].toUpperCase();"object"==typeof OpenLayers.Lang[c]&&(b=c)}b||(OpenLayers.Console.warn("Failed to find OpenLayers.Lang."+a.join("-")+" dictionary, falling back to default language"),
-b=OpenLayers.Lang.defaultCode);OpenLayers.Lang.code=b},translate:function(a,b){var c=OpenLayers.Lang[OpenLayers.Lang.getCode()];(c=c&&c[a])||(c=a);b&&(c=OpenLayers.String.format(c,b));return c}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.getElement=function(){for(var a=[],b=0,c=arguments.length;b<c;b++){var d=arguments[b];"string"==typeof d&&(d=document.getElementById(d));if(1==arguments.length)return d;a.push(d)}return a};OpenLayers.Util.isElement=function(a){return!(!a||1!==a.nodeType)};OpenLayers.Util.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)};OpenLayers.Util.removeItem=function(a,b){for(var c=a.length-1;0<=c;c--)a[c]==b&&a.splice(c,1);return a};
-OpenLayers.Util.indexOf=function(a,b){if("function"==typeof a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;c<d;c++)if(a[c]==b)return c;return-1};OpenLayers.Util.dotless=/\./g;
-OpenLayers.Util.modifyDOMElement=function(a,b,c,d,e,f,g,h){b&&(a.id=b.replace(OpenLayers.Util.dotless,"_"));c&&(a.style.left=c.x+"px",a.style.top=c.y+"px");d&&(a.style.width=d.w+"px",a.style.height=d.h+"px");e&&(a.style.position=e);f&&(a.style.border=f);g&&(a.style.overflow=g);0<=parseFloat(h)&&1>parseFloat(h)?(a.style.filter="alpha(opacity="+100*h+")",a.style.opacity=h):1==parseFloat(h)&&(a.style.filter="",a.style.opacity="")};
-OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var k=document.createElement("div");d&&(k.style.backgroundImage="url("+d+")");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(k,a,b,c,e,f,g,h);return k};
-OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var k=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(k,a,b,c,e,f,null,g);h&&(k.style.display="none",b=function(){k.style.display="";OpenLayers.Event.stopObservingElement(k)},OpenLayers.Event.observe(k,"load",b),OpenLayers.Event.observe(k,"error",b));k.style.alt=a;k.galleryImg="no";d&&(k.src=d);return k};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;
-OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(null==OpenLayers.Util.alphaHackNeeded){var a=navigator.appVersion.split("MSIE"),a=parseFloat(a[1]),b=!1;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&5.5<=a&&7>a}return OpenLayers.Util.alphaHackNeeded};
-OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,k){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,k);b=a.childNodes[0];e&&(b.src=e);OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);OpenLayers.Util.alphaHack()&&("none"!=a.style.display&&(a.style.display="inline-block"),null==h&&(h="scale"),a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')",0<=parseFloat(a.style.opacity)&&1>parseFloat(a.style.opacity)&&
-(a.style.filter+=" alpha(opacity="+100*a.style.opacity+")"),b.style.filter="alpha(opacity=0)")};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,k){var l=OpenLayers.Util.createDiv();k=OpenLayers.Util.createImage(null,null,null,null,null,null,null,k);k.className="olAlphaImg";l.appendChild(k);OpenLayers.Util.modifyAlphaImageDiv(l,a,b,c,d,e,f,g,h);return l};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b};
-OpenLayers.Util.applyDefaults=function(a,b){a=a||{};var c="function"==typeof window.Event&&b instanceof window.Event,d;for(d in b)if(void 0===a[d]||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];!c&&(b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))&&(a.toString=b.toString);return a};
-OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(null!=d&&"function"!=typeof d){if("object"==typeof d&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g<h;g++)f=d[g],e.push(encodeURIComponent(null===f||void 0===f?"":f));d=e.join(",")}else d=encodeURIComponent(d);b.push(encodeURIComponent(c)+"="+d)}}return b.join("&")};OpenLayers.Util.urlAppend=function(a,b){var c=a;if(b)var d=(a+" ").split(/[?&]/),c=c+(" "===d.pop()?b:d.length?"&"+b:"?"+b);return c};
-OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||OpenLayers._getScriptLocation()+"img/"};OpenLayers.Util.getImageLocation=function(a){return OpenLayers.Util.getImagesLocation()+a};OpenLayers.Util.Try=function(){for(var a=null,b=0,c=arguments.length;b<c;b++){var d=arguments[b];try{a=d();break}catch(e){}}return a};
-OpenLayers.Util.getXmlNodeValue=function(a){var b=null;OpenLayers.Util.Try(function(){b=a.text;b||(b=a.textContent);b||(b=a.firstChild.nodeValue)},function(){b=a.textContent});return b};OpenLayers.Util.mouseLeft=function(a,b){for(var c=a.relatedTarget?a.relatedTarget:a.toElement;c!=b&&null!=c;)c=c.parentNode;return c!=b};OpenLayers.Util.DEFAULT_PRECISION=14;OpenLayers.Util.toFloat=function(a,b){null==b&&(b=OpenLayers.Util.DEFAULT_PRECISION);"number"!==typeof a&&(a=parseFloat(a));return 0===b?a:parseFloat(a.toPrecision(b))};
-OpenLayers.Util.rad=function(a){return a*Math.PI/180};OpenLayers.Util.deg=function(a){return 180*a/Math.PI};OpenLayers.Util.VincentyConstants={a:6378137,b:6356752.3142,f:1/298.257223563};
-OpenLayers.Util.distVincenty=function(a,b){for(var c=OpenLayers.Util.VincentyConstants,d=c.a,e=c.b,c=c.f,f=OpenLayers.Util.rad(b.lon-a.lon),g=Math.atan((1-c)*Math.tan(OpenLayers.Util.rad(a.lat))),h=Math.atan((1-c)*Math.tan(OpenLayers.Util.rad(b.lat))),k=Math.sin(g),g=Math.cos(g),l=Math.sin(h),h=Math.cos(h),m=f,n=2*Math.PI,p=20;1E-12<Math.abs(m-n)&&0<--p;){var q=Math.sin(m),r=Math.cos(m),s=Math.sqrt(h*q*h*q+(g*l-k*h*r)*(g*l-k*h*r));if(0==s)return 0;var r=k*l+g*h*r,t=Math.atan2(s,r),u=Math.asin(g*h*
-q/s),v=Math.cos(u)*Math.cos(u),q=r-2*k*l/v,w=c/16*v*(4+c*(4-3*v)),n=m,m=f+(1-w)*c*Math.sin(u)*(t+w*s*(q+w*r*(-1+2*q*q)))}if(0==p)return NaN;d=v*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(t-c*s*(q+c/4*(r*(-1+2*q*q)-c/6*q*(-3+4*s*s)*(-3+4*q*q))))).toFixed(3)/1E3};
-OpenLayers.Util.destinationVincenty=function(a,b,c){var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b,h=e.f,e=a.lon;a=a.lat;var k=d.rad(b);b=Math.sin(k);k=Math.cos(k);a=(1-h)*Math.tan(d.rad(a));var l=1/Math.sqrt(1+a*a),m=a*l,n=Math.atan2(a,k);a=l*b;for(var p=1-a*a,f=p*(f*f-g*g)/(g*g),q=1+f/16384*(4096+f*(-768+f*(320-175*f))),r=f/1024*(256+f*(-128+f*(74-47*f))),f=c/(g*q),s=2*Math.PI;1E-12<Math.abs(f-s);)var t=Math.cos(2*n+f),u=Math.sin(f),v=Math.cos(f),w=r*u*(t+r/4*(v*(-1+2*t*t)-r/6*t*(-3+4*
-u*u)*(-3+4*t*t))),s=f,f=c/(g*q)+w;c=m*u-l*v*k;g=Math.atan2(m*v+l*u*k,(1-h)*Math.sqrt(a*a+c*c));b=Math.atan2(u*b,l*v-m*u*k);k=h/16*p*(4+h*(4-3*p));t=b-(1-k)*h*a*(f+k*u*(t+k*v*(-1+2*t*t)));Math.atan2(a,-c);return new OpenLayers.LonLat(e+d.deg(t),d.deg(g))};
-OpenLayers.Util.getParameters=function(a,b){b=b||{};a=null===a||void 0===a?window.location.href:a;var c="";if(OpenLayers.String.contains(a,"?"))var d=a.indexOf("?")+1,c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length,c=a.substring(d,c);for(var d={},c=c.split(/[&;]/),e=0,f=c.length;e<f;++e){var g=c[e].split("=");if(g[0]){var h=g[0];try{h=decodeURIComponent(h)}catch(k){h=unescape(h)}g=(g[1]||"").replace(/\+/g," ");try{g=decodeURIComponent(g)}catch(l){g=unescape(g)}!1!==b.splitArgs&&(g=g.split(","));
-1==g.length&&(g=g[0]);d[h]=g}}return d};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(a){a=null==a?"id_":a.replace(OpenLayers.Util.dotless,"_");OpenLayers.Util.lastSeqID+=1;return a+OpenLayers.Util.lastSeqID};OpenLayers.INCHES_PER_UNIT={inches:1,ft:12,mi:63360,m:39.37,km:39370,dd:4374754,yd:36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT.degrees=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT.nmi=1852*OpenLayers.INCHES_PER_UNIT.m;
-OpenLayers.METERS_PER_INCH=0.0254000508001016;
-OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{Inch:OpenLayers.INCHES_PER_UNIT.inches,Meter:1/OpenLayers.METERS_PER_INCH,Foot:0.3048006096012192/OpenLayers.METERS_PER_INCH,IFoot:0.3048/OpenLayers.METERS_PER_INCH,ClarkeFoot:0.3047972651151/OpenLayers.METERS_PER_INCH,SearsFoot:0.30479947153867626/OpenLayers.METERS_PER_INCH,GoldCoastFoot:0.3047997101815088/OpenLayers.METERS_PER_INCH,IInch:0.0254/OpenLayers.METERS_PER_INCH,MicroInch:2.54E-5/OpenLayers.METERS_PER_INCH,Mil:2.54E-8/OpenLayers.METERS_PER_INCH,
-Centimeter:0.01/OpenLayers.METERS_PER_INCH,Kilometer:1E3/OpenLayers.METERS_PER_INCH,Yard:0.9144018288036576/OpenLayers.METERS_PER_INCH,SearsYard:0.914398414616029/OpenLayers.METERS_PER_INCH,IndianYard:0.9143985307444408/OpenLayers.METERS_PER_INCH,IndianYd37:0.91439523/OpenLayers.METERS_PER_INCH,IndianYd62:0.9143988/OpenLayers.METERS_PER_INCH,IndianYd75:0.9143985/OpenLayers.METERS_PER_INCH,IndianFoot:0.30479951/OpenLayers.METERS_PER_INCH,IndianFt37:0.30479841/OpenLayers.METERS_PER_INCH,IndianFt62:0.3047996/
-OpenLayers.METERS_PER_INCH,IndianFt75:0.3047995/OpenLayers.METERS_PER_INCH,Mile:1609.3472186944373/OpenLayers.METERS_PER_INCH,IYard:0.9144/OpenLayers.METERS_PER_INCH,IMile:1609.344/OpenLayers.METERS_PER_INCH,NautM:1852/OpenLayers.METERS_PER_INCH,"Lat-66":110943.31648893273/OpenLayers.METERS_PER_INCH,"Lat-83":110946.25736872235/OpenLayers.METERS_PER_INCH,Decimeter:0.1/OpenLayers.METERS_PER_INCH,Millimeter:0.001/OpenLayers.METERS_PER_INCH,Dekameter:10/OpenLayers.METERS_PER_INCH,Decameter:10/OpenLayers.METERS_PER_INCH,
-Hectometer:100/OpenLayers.METERS_PER_INCH,GermanMeter:1.0000135965/OpenLayers.METERS_PER_INCH,CaGrid:0.999738/OpenLayers.METERS_PER_INCH,ClarkeChain:20.1166194976/OpenLayers.METERS_PER_INCH,GunterChain:20.11684023368047/OpenLayers.METERS_PER_INCH,BenoitChain:20.116782494375872/OpenLayers.METERS_PER_INCH,SearsChain:20.11676512155/OpenLayers.METERS_PER_INCH,ClarkeLink:0.201166194976/OpenLayers.METERS_PER_INCH,GunterLink:0.2011684023368047/OpenLayers.METERS_PER_INCH,BenoitLink:0.20116782494375873/OpenLayers.METERS_PER_INCH,
-SearsLink:0.2011676512155/OpenLayers.METERS_PER_INCH,Rod:5.02921005842012/OpenLayers.METERS_PER_INCH,IntnlChain:20.1168/OpenLayers.METERS_PER_INCH,IntnlLink:0.201168/OpenLayers.METERS_PER_INCH,Perch:5.02921005842012/OpenLayers.METERS_PER_INCH,Pole:5.02921005842012/OpenLayers.METERS_PER_INCH,Furlong:201.1684023368046/OpenLayers.METERS_PER_INCH,Rood:3.778266898/OpenLayers.METERS_PER_INCH,CapeFoot:0.3047972615/OpenLayers.METERS_PER_INCH,Brealey:375/OpenLayers.METERS_PER_INCH,ModAmFt:0.304812252984506/
-OpenLayers.METERS_PER_INCH,Fathom:1.8288/OpenLayers.METERS_PER_INCH,"NautM-UK":1853.184/OpenLayers.METERS_PER_INCH,"50kilometers":5E4/OpenLayers.METERS_PER_INCH,"150kilometers":15E4/OpenLayers.METERS_PER_INCH});
-OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{mm:OpenLayers.INCHES_PER_UNIT.Meter/1E3,cm:OpenLayers.INCHES_PER_UNIT.Meter/100,dm:100*OpenLayers.INCHES_PER_UNIT.Meter,km:1E3*OpenLayers.INCHES_PER_UNIT.Meter,kmi:OpenLayers.INCHES_PER_UNIT.nmi,fath:OpenLayers.INCHES_PER_UNIT.Fathom,ch:OpenLayers.INCHES_PER_UNIT.IntnlChain,link:OpenLayers.INCHES_PER_UNIT.IntnlLink,"us-in":OpenLayers.INCHES_PER_UNIT.inches,"us-ft":OpenLayers.INCHES_PER_UNIT.Foot,"us-yd":OpenLayers.INCHES_PER_UNIT.Yard,"us-ch":OpenLayers.INCHES_PER_UNIT.GunterChain,
-"us-mi":OpenLayers.INCHES_PER_UNIT.Mile,"ind-yd":OpenLayers.INCHES_PER_UNIT.IndianYd37,"ind-ft":OpenLayers.INCHES_PER_UNIT.IndianFt37,"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(a){return 1<a?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;a&&(null==b&&(b="degrees"),c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH));return c};
-OpenLayers.Util.getScaleFromResolution=function(a,b){null==b&&(b="degrees");return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH};
-OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&"absolute"==OpenLayers.Element.getStyle(a,"position")&&(""==a.style.top||""==a.style.left),e=null;if(a.getBoundingClientRect)a=a.getBoundingClientRect(),e=window.pageYOffset||c.scrollTop,b[0]=a.left+(window.pageXOffset||c.scrollLeft),b[1]=a.top+e;else if(document.getBoxObjectFor&&!d)a=document.getBoxObjectFor(a),c=document.getBoxObjectFor(c),
-b[0]=a.screenX-c.screenX,b[1]=a.screenY-c.screenY;else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;)b[0]+=e.offsetLeft,b[1]+=e.offsetTop,e=e.offsetParent;c=OpenLayers.BROWSER_NAME;if("opera"==c||"safari"==c&&"absolute"==OpenLayers.Element.getStyle(a,"position"))b[1]-=document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]-=e.scrollLeft;if("opera"!=c||"TR"!=e.tagName)b[1]-=e.scrollTop;e=e.offsetParent}}return b};
-OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;void 0==a&&(a="msie"==OpenLayers.BROWSER_NAME&&"CSS1Compat"!=document.compatMode?document.body:document.documentElement,arguments.callee.viewportElement=a);return a};
-OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:!0,ignorePort80:!0,ignoreHash:!0,splitArgs:!1});a=OpenLayers.Util.createUrlObject(a,c);b=OpenLayers.Util.createUrlObject(b,c);for(var d in a)if("args"!==d&&a[d]!=b[d])return!1;for(d in a.args){if(a.args[d]!=b.args[d])return!1;delete b.args[d]}for(d in b.args)return!1;return!0};
-OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"",d=c.protocol+"//"+c.host.split(":").shift()+d;0===a.indexOf("/")?a=d+a:(c=c.pathname.split("/"),c.pop(),a=d+c.join("/")+"/"+a)}b.ignoreCase&&(a=a.toLowerCase());c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?"80"==c.port||"0"==c.port?"":c.port:""==c.port||"0"==c.port?"80":c.port;d.hash=b.ignoreHash||"#"===
-c.hash?"":c.hash;var e=c.search;e||(e=a.indexOf("?"),e=-1!=e?a.substr(e):"");d.args=OpenLayers.Util.getParameters(e,{splitArgs:b.splitArgs});d.pathname="/"==c.pathname.charAt(0)?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null,b=a.indexOf("?"),c=a.indexOf("#");return b=-1==b?-1!=c?a.substr(0,c):a:-1!=c?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return-1==a.indexOf("webkit")&&-1!=a.indexOf("gecko")}();
-OpenLayers.CANVAS_SUPPORTED=function(){var a=document.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))}();OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();-1!=b.indexOf("opera")?a="opera":-1!=b.indexOf("msie")?a="msie":-1!=b.indexOf("safari")?a="safari":-1!=b.indexOf("mozilla")&&(a=-1!=b.indexOf("firefox")?"firefox":"mozilla");return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME};
-OpenLayers.Util.getRenderedDimensions=function(a,b,c){var d,e,f=document.createElement("div");f.style.visibility="hidden";for(var g=c&&c.containerElement?c.containerElement:document.body,h=!1,k=null,l=g;l&&"body"!=l.tagName.toLowerCase();){var m=OpenLayers.Element.getStyle(l,"position");if("absolute"==m){h=!0;break}else if(m&&"static"!=m)break;l=l.parentNode}!h||0!==g.clientHeight&&0!==g.clientWidth||(k=document.createElement("div"),k.style.visibility="hidden",k.style.position="absolute",k.style.overflow=
-"visible",k.style.width=document.body.clientWidth+"px",k.style.height=document.body.clientHeight+"px",k.appendChild(f));f.style.position="absolute";b&&(b.w?(d=b.w,f.style.width=d+"px"):b.h&&(e=b.h,f.style.height=e+"px"));c&&c.displayClass&&(f.className=c.displayClass);b=document.createElement("div");b.innerHTML=a;b.style.overflow="visible";if(b.childNodes)for(a=0,c=b.childNodes.length;a<c;a++)b.childNodes[a].style&&(b.childNodes[a].style.overflow="visible");f.appendChild(b);k?g.appendChild(k):g.appendChild(f);
-d||(d=parseInt(b.scrollWidth),f.style.width=d+"px");e||(e=parseInt(b.scrollHeight));f.removeChild(b);k?(k.removeChild(f),g.removeChild(k)):g.removeChild(f);return new OpenLayers.Size(d,e)};
-OpenLayers.Util.getScrollbarWidth=function(){var a=OpenLayers.Util._scrollbarWidth;if(null==a){var b=null,c=null,b=a=0,b=document.createElement("div");b.style.position="absolute";b.style.top="-1000px";b.style.left="-1000px";b.style.width="100px";b.style.height="50px";b.style.overflow="hidden";c=document.createElement("div");c.style.width="100%";c.style.height="200px";b.appendChild(c);document.body.appendChild(b);a=c.offsetWidth;b.style.overflow="scroll";b=c.offsetWidth;document.body.removeChild(document.body.lastChild);
-OpenLayers.Util._scrollbarWidth=a-b;a=OpenLayers.Util._scrollbarWidth}return a};
-OpenLayers.Util.getFormattedLonLat=function(a,b,c){c||(c="dms");a=(a+540)%360-180;var d=Math.abs(a),e=Math.floor(d),f=d=(d-e)/(1/60),d=Math.floor(d),f=Math.round(10*((f-d)/(1/60))),f=f/10;60<=f&&(f-=60,d+=1,60<=d&&(d-=60,e+=1));10>e&&(e="0"+e);e+="\u00b0";0<=c.indexOf("dm")&&(10>d&&(d="0"+d),e+=d+"'",0<=c.indexOf("dms")&&(10>f&&(f="0"+f),e+=f+'"'));return e="lon"==b?e+(0>a?OpenLayers.i18n("W"):OpenLayers.i18n("E")):e+(0>a?OpenLayers.i18n("S"):OpenLayers.i18n("N"))};OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:!1,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a},destroy:function(){},read:function(a){throw Error("Read not implemented.");},write:function(a){throw Error("Write not implemented.");},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.CSWGetRecords=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.CSWGetRecords.DEFAULTS);var b=OpenLayers.Format.CSWGetRecords["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSWGetRecords version: "+a.version;return new b(a)};OpenLayers.Format.CSWGetRecords.DEFAULTS={version:"2.0.2"};OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:!1,displayClass:"",title:"",autoActivate:!1,active:null,handlerOptions:null,handler:null,eventListeners:null,events:null,initialize:function(a){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object)this.events.on(this.eventListeners);null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+
-"_"))},destroy:function(){this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy(),this.events=null);this.eventListeners=null;this.handler&&(this.handler.destroy(),this.handler=null);if(this.handlers){for(var a in this.handlers)this.handlers.hasOwnProperty(a)&&"function"==typeof this.handlers[a].destroy&&this.handlers[a].destroy();this.handlers=null}this.map&&(this.map.removeControl(this),this.map=null);this.div=null},setMap:function(a){this.map=a;this.handler&&
-this.handler.setMap(a)},draw:function(a){null==this.div&&(this.div=OpenLayers.Util.createDiv(this.id),this.div.className=this.displayClass,this.allowSelection||(this.div.className+=" olControlNoSelect",this.div.setAttribute("unselectable","on",0),this.div.onselectstart=OpenLayers.Function.False),""!=this.title&&(this.div.title=this.title));null!=a&&(this.position=a.clone());this.moveTo(this.position);return this.div},moveTo:function(a){null!=a&&null!=this.div&&(this.div.style.left=a.x+"px",this.div.style.top=
-a.y+"px")},activate:function(){if(this.active)return!1;this.handler&&this.handler.activate();this.active=!0;this.map&&OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");this.events.triggerEvent("activate");return!0},deactivate:function(){return this.active?(this.handler&&this.handler.deactivate(),this.active=!1,this.map&&OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active"),this.events.triggerEvent("deactivate"),
-!0):!1},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Event={observers:!1,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(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&1==a.touches.length},isMultiTouch:function(a){return a.touches&&1<a.touches.length},isLeftClick:function(a){return a.which&&1==a.which||a.button&&1==a.button},isRightClick:function(a){return a.which&&3==a.which||a.button&&2==a.button},stop:function(a,
-b){b||OpenLayers.Event.preventDefault(a);a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},preventDefault:function(a){a.preventDefault?a.preventDefault():a.returnValue=!1},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||!1;"keypress"==b&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.attachEvent)&&(b="keydown");
-this.observers||(this.observers={});if(!a._eventCacheID){var e="eventCacheID_";a.id&&(e=a.id+"_"+e);a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])},
-_removeElementObservers:function(a){if(a)for(var b=a.length-1;0<=b;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this,[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){d=d||!1;a=OpenLayers.Util.getElement(a);var e=a._eventCacheID;"keypress"==b&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent)&&(b="keydown");var f=!1,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h<g.length;){var k=g[h];if(k.name==b&&k.observer==c&&k.useCapture==d){g.splice(h,
-1);0==g.length&&delete OpenLayers.Event.observers[e];f=!0;break}h++}f&&(a.removeEventListener?a.removeEventListener(b,c,d):a&&a.detachEvent&&a.detachEvent("on"+b,c));return f},unloadCache:function(){if(OpenLayers.Event&&OpenLayers.Event.observers){for(var a in OpenLayers.Event.observers)OpenLayers.Event._removeElementObservers.apply(this,[OpenLayers.Event.observers[a]]);OpenLayers.Event.observers=!1}},CLASS_NAME:"OpenLayers.Event"};
-OpenLayers.Event.observe(window,"unload",OpenLayers.Event.unloadCache,!1);
-OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:"mouseover mouseout mousedown mouseup mousemove click dblclick rightclick dblrightclick resize focus blur touchstart touchmove touchend keydown".split(" "),listeners:null,object:null,element:null,eventHandler:null,fallThrough:null,includeXY:!1,extensions:null,extensionCount:null,clearMouseListener:null,initialize:function(a,b,c,d,e){OpenLayers.Util.extend(this,e);this.object=a;this.fallThrough=d;this.listeners={};this.extensions={};this.extensionCount=
-{};this._msTouches=[];null!=b&&this.attachToElement(b)},destroy:function(){for(var a in this.extensions)"boolean"!==typeof this.extensions[a]&&this.extensions[a].destroy();this.extensions=null;this.element&&(OpenLayers.Event.stopObservingElement(this.element),this.element.hasScrollEvent&&OpenLayers.Event.stopObserving(window,"scroll",this.clearMouseListener));this.eventHandler=this.fallThrough=this.object=this.listeners=this.element=null},addEventType:function(a){},attachToElement:function(a){this.element?
-OpenLayers.Event.stopObservingElement(this.element):(this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this),this.clearMouseListener=OpenLayers.Function.bind(this.clearMouseCache,this));this.element=a;for(var b=!!window.navigator.msMaxTouchPoints,c,d=0,e=this.BROWSER_EVENTS.length;d<e;d++)c=this.BROWSER_EVENTS[d],OpenLayers.Event.observe(a,c,this.eventHandler),b&&0===c.indexOf("touch")&&this.addMsTouchListener(a,c,this.eventHandler);OpenLayers.Event.observe(a,"dragstart",
-OpenLayers.Event.stop)},on:function(a){for(var b in a)"scope"!=b&&a.hasOwnProperty(b)&&this.register(b,a.scope,a[b])},register:function(a,b,c,d){a in OpenLayers.Events&&!this.extensions[a]&&(this.extensions[a]=new OpenLayers.Events[a](this));if(null!=c){null==b&&(b=this.object);var e=this.listeners[a];e||(e=[],this.listeners[a]=e,this.extensionCount[a]=0);b={obj:b,func:c};d?(e.splice(this.extensionCount[a],0,b),"object"===typeof d&&d.extension&&this.extensionCount[a]++):e.push(b)}},registerPriority:function(a,
-b,c){this.register(a,b,c,!0)},un:function(a){for(var b in a)"scope"!=b&&a.hasOwnProperty(b)&&this.unregister(b,a.scope,a[b])},unregister:function(a,b,c){null==b&&(b=this.object);a=this.listeners[a];if(null!=a)for(var d=0,e=a.length;d<e;d++)if(a[d].obj==b&&a[d].func==c){a.splice(d,1);break}},remove:function(a){null!=this.listeners[a]&&(this.listeners[a]=[])},triggerEvent:function(a,b){var c=this.listeners[a];if(c&&0!=c.length){null==b&&(b={});b.object=this.object;b.element=this.element;b.type||(b.type=
-a);for(var c=c.slice(),d,e=0,f=c.length;e<f&&(d=c[e],d=d.func.apply(d.obj,[b]),void 0==d||!1!=d);e++);this.fallThrough||OpenLayers.Event.stop(b,!0);return d}},handleBrowserEvent:function(a){var b=a.type,c=this.listeners[b];if(c&&0!=c.length){if((c=a.touches)&&c[0]){for(var d=0,e=0,f=c.length,g,h=0;h<f;++h)g=this.getTouchClientXY(c[h]),d+=g.clientX,e+=g.clientY;a.clientX=d/f;a.clientY=e/f}this.includeXY&&(a.xy=this.getMousePosition(a));this.triggerEvent(b,a)}},getTouchClientXY:function(a){var b=window.olMockWin||
-window,c=b.pageXOffset,b=b.pageYOffset,d=a.clientX,e=a.clientY;if(0===a.pageY&&Math.floor(e)>Math.floor(a.pageY)||0===a.pageX&&Math.floor(d)>Math.floor(a.pageX))d-=c,e-=b;else if(e<a.pageY-b||d<a.pageX-c)d=a.pageX-c,e=a.pageY-b;a.olClientX=d;a.olClientY=e;return{clientX:d,clientY:e}},clearMouseCache:function(){this.element.scrolls=null;this.element.lefttop=null;this.element.offsets=null},getMousePosition:function(a){this.includeXY?this.element.hasScrollEvent||(OpenLayers.Event.observe(window,"scroll",
-this.clearMouseListener),this.element.hasScrollEvent=!0):this.clearMouseCache();if(!this.element.scrolls){var b=OpenLayers.Util.getViewportElement();this.element.scrolls=[window.pageXOffset||b.scrollLeft,window.pageYOffset||b.scrollTop]}this.element.lefttop||(this.element.lefttop=[document.documentElement.clientLeft||0,document.documentElement.clientTop||0]);this.element.offsets||(this.element.offsets=OpenLayers.Util.pagePosition(this.element));return new OpenLayers.Pixel(a.clientX+this.element.scrolls[0]-
-this.element.offsets[0]-this.element.lefttop[0],a.clientY+this.element.scrolls[1]-this.element.offsets[1]-this.element.lefttop[1])},addMsTouchListener:function(a,b,c){function d(a){c(OpenLayers.Util.applyDefaults({stopPropagation:function(){for(var a=e.length-1;0<=a;--a)e[a].stopPropagation()},preventDefault:function(){for(var a=e.length-1;0<=a;--a)e[a].preventDefault()},type:b},a))}var e=this._msTouches;switch(b){case "touchstart":return this.addMsTouchListenerStart(a,b,d);case "touchend":return this.addMsTouchListenerEnd(a,
-b,d);case "touchmove":return this.addMsTouchListenerMove(a,b,d);default:throw"Unknown touch event type";}},addMsTouchListenerStart:function(a,b,c){var d=this._msTouches;OpenLayers.Event.observe(a,"MSPointerDown",function(a){for(var b=!1,g=0,h=d.length;g<h;++g)if(d[g].pointerId==a.pointerId){b=!0;break}b||d.push(a);a.touches=d.slice();c(a)});OpenLayers.Event.observe(a,"MSPointerUp",function(a){for(var b=0,c=d.length;b<c;++b)if(d[b].pointerId==a.pointerId){d.splice(b,1);break}})},addMsTouchListenerMove:function(a,
-b,c){var d=this._msTouches;OpenLayers.Event.observe(a,"MSPointerMove",function(a){if(a.pointerType!=a.MSPOINTER_TYPE_MOUSE||0!=a.buttons)if(1!=d.length||d[0].pageX!=a.pageX||d[0].pageY!=a.pageY){for(var b=0,g=d.length;b<g;++b)if(d[b].pointerId==a.pointerId){d[b]=a;break}a.touches=d.slice();c(a)}})},addMsTouchListenerEnd:function(a,b,c){var d=this._msTouches;OpenLayers.Event.observe(a,"MSPointerUp",function(a){for(var b=0,g=d.length;b<g;++b)if(d[b].pointerId==a.pointerId){d.splice(b,1);break}a.touches=
-d.slice();c(a)})},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:"mousedown mouseup click dblclick touchstart touchmove touchend keydown".split(" "),startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(a){this.target=a;for(a=this.events.length-1;0<=a;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:!0})},destroy:function(){for(var a=this.events.length-1;0<=a;--a)this.target.unregister(this.events[a],this,this.buttonClick);
-delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(0<--b&&a);return c},ignore:function(a){var b=3,c=!1;do{if("a"===a.nodeName.toLowerCase()){c=!0;break}a=a.parentNode}while(0<--b&&a);return c},buttonClick:function(a){var b=!0,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if("keydown"===a.type)switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",
-{buttonElement:c}),OpenLayers.Event.stop(a),b=!1}else if(this.startEvt){if(this.completeRegEx.test(a.type)){var b=OpenLayers.Util.pagePosition(c),d=OpenLayers.Util.getViewportElement(),e=window.pageYOffset||d.scrollTop;b[0]-=window.pageXOffset||d.scrollLeft;b[1]-=e;this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})}this.cancelRegEx.test(a.type)&&delete this.startEvt;OpenLayers.Event.stop(a);b=!1}this.startRegEx.test(a.type)&&
-(this.startEvt=a,OpenLayers.Event.stop(a),b=!1)}else b=!this.ignore(OpenLayers.Event.element(a)),delete this.startEvt;return b}});OpenLayers.Util=OpenLayers.Util||{};
-OpenLayers.Util.vendorPrefix=function(){function a(a){return a?a.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()}).replace(/^ms-/,"-ms-"):null}function b(a,b){if(void 0===g[b]){var c,e=0,f=d.length,p="undefined"!==typeof a.cssText;for(g[b]=null;e<f;e++)if((c=d[e])?(p||(c=c.toLowerCase()),c=c+b.charAt(0).toUpperCase()+b.slice(1)):c=b,void 0!==a[c]){g[b]=c;break}}return g[b]}function c(a){return b(e,a)}var d=["","O","ms","Moz","Webkit"],e=document.createElement("div").style,f={},g={};return{css:function(b){if(void 0===
-f[b]){var d=b.replace(/(-[\s\S])/g,function(a){return a.charAt(1).toUpperCase()}),d=c(d);f[b]=a(d)}return f[b]},js:b,style:c,cssCache:f,jsCache:g}}();OpenLayers.Animation=function(a){var b=OpenLayers.Util.vendorPrefix.js(a,"requestAnimationFrame"),c=!!b,d=function(){var c=a[b]||function(b,c){a.setTimeout(b,16)};return function(b,d){c.apply(a,[b,d])}}(),e=0,f={};return{isNative:c,requestFrame:d,start:function(a,b,c){b=0<b?b:Number.POSITIVE_INFINITY;var l=++e,m=+new Date;f[l]=function(){f[l]&&+new Date-m<=b?(a(),f[l]&&d(f[l],c)):delete f[l]};d(f[l],c);return l},stop:function(a){delete f[a]}}}(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,minFrameRate:null,startTime:null,animationId:null,playing:!1,initialize:function(a){this.easing=a?a:OpenLayers.Easing.Expo.easeOut},start:function(a,b,c,d){this.playing=!0;this.begin=a;this.finish=b;this.duration=c;this.callbacks=d.callbacks;this.minFrameRate=d.minFrameRate||30;this.time=0;this.startTime=(new Date).getTime();OpenLayers.Animation.stop(this.animationId);this.animationId=null;
-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(){this.playing&&(this.callbacks&&this.callbacks.done&&this.callbacks.done.call(this,this.finish),OpenLayers.Animation.stop(this.animationId),this.animationId=null,this.playing=!1)},play:function(){var a={},b;for(b in this.begin){var c=this.begin[b],d=this.finish[b];if(null==c||null==d||isNaN(c)||isNaN(d))throw new TypeError("invalid value for Tween");
-a[b]=this.easing.apply(this,[this.time,c,d-c,this.duration])}this.time++;this.callbacks&&this.callbacks.eachStep&&((new Date).getTime()-this.startTime)/this.time<=1E3/this.minFrameRate&&this.callbacks.eachStep.call(this,a);this.time>this.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"};
-OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return 0==a?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return 0==a?b:a==d?b+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"};
-OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return 1>(a/=d/2)?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.projCode=a;"object"==typeof Proj4js&&(this.proj=new Proj4js.Proj(a))},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(a){var b=!1;a&&(a instanceof OpenLayers.Projection||(a=new OpenLayers.Projection(a)),"object"==
-typeof Proj4js&&this.proj.defData&&a.proj.defData?b=this.proj.defData.replace(this.titleRegEx,"")==a.proj.defData.replace(this.titleRegEx,""):a.getCode&&(b=this.getCode(),a=a.getCode(),b=b==a||!!OpenLayers.Projection.transforms[b]&&OpenLayers.Projection.transforms[b][a]===OpenLayers.Projection.nullTransform));return b},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:!0},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7]}};
-OpenLayers.Projection.addTransform=function(a,b,c){if(c===OpenLayers.Projection.nullTransform){var d=OpenLayers.Projection.defaults[a];d&&!OpenLayers.Projection.defaults[b]&&(OpenLayers.Projection.defaults[b]=d)}OpenLayers.Projection.transforms[a]||(OpenLayers.Projection.transforms[a]={});OpenLayers.Projection.transforms[a][b]=c};
-OpenLayers.Projection.transform=function(a,b,c){if(b&&c)if(b instanceof OpenLayers.Projection||(b=new OpenLayers.Projection(b)),c instanceof OpenLayers.Projection||(c=new OpenLayers.Projection(c)),b.proj&&c.proj)a=Proj4js.transform(b.proj,c.proj,a);else{b=b.getCode();c=c.getCode();var d=OpenLayers.Projection.transforms;if(d[b]&&d[b][c])d[b][c](a)}return a};OpenLayers.Projection.nullTransform=function(a){return a};
-(function(){function a(a){a.x=180*a.x/d;a.y=180/Math.PI*(2*Math.atan(Math.exp(a.y/d*Math.PI))-Math.PI/2);return a}function b(a){a.x=a.x*d/180;var b=Math.log(Math.tan((90+a.y)*Math.PI/360))/Math.PI*d;a.y=Math.max(-2.003750834E7,Math.min(b,2.003750834E7));return a}function c(c,d){var e=OpenLayers.Projection.addTransform,f=OpenLayers.Projection.nullTransform,g,p,q,r,s;g=0;for(p=d.length;g<p;++g)for(q=d[g],e(c,q,b),e(q,c,a),s=g+1;s<p;++s)r=d[s],e(q,r,f),e(r,q,f)}var d=2.003750834E7,e=["EPSG:900913","EPSG:3857",
-"EPSG:102113","EPSG:102100"],f=["CRS:84","urn:ogc:def:crs:EPSG:6.6:4326","EPSG:4326"],g;for(g=e.length-1;0<=g;--g)c(e[g],f);for(g=f.length-1;0<=g;--g)c(f[g],e)})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1E3},id:null,fractionalZoom:!1,events:null,allOverlays:!1,div:null,dragging:!1,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,fallThrough:!1,autoUpdateSize:!0,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(a,b){1===arguments.length&&"object"===typeof a&&(a=(b=a)&&b.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({},b);OpenLayers.Util.extend(this,b);OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection]);!this.maxExtent||this.maxExtent instanceof OpenLayers.Bounds||(this.maxExtent=new OpenLayers.Bounds(this.maxExtent));
-!this.minExtent||this.minExtent instanceof OpenLayers.Bounds||(this.minExtent=new OpenLayers.Bounds(this.minExtent));!this.restrictedExtent||this.restrictedExtent instanceof OpenLayers.Bounds||(this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent));!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(a);this.div||(this.div=document.createElement("div"),
-this.div.style.height="1px",this.div.style.width="1px");OpenLayers.Element.addClass(this.div,"olMap");var c=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(c,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:!0});OpenLayers.TileManager&&null!==
-this.tileManager&&(this.tileManager instanceof OpenLayers.TileManager||(this.tileManager=new OpenLayers.TileManager(this.tileManager)),this.tileManager.addMap(this));c=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(c);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);
-!0===this.autoUpdateSize&&(this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this),OpenLayers.Event.observe(window,"resize",this.updateSizeDestroy));if(this.theme){for(var c=!0,d=document.getElementsByTagName("link"),e=0,f=d.length;e<f;++e)if(OpenLayers.Util.isEquivalentUrl(d.item(e).href,this.theme)){c=!1;break}c&&(c=document.createElement("link"),c.setAttribute("rel","stylesheet"),c.setAttribute("type","text/css"),c.setAttribute("href",this.theme),document.getElementsByTagName("head")[0].appendChild(c))}null==
-this.controls&&(this.controls=[],null!=OpenLayers.Control&&(OpenLayers.Control.Navigation?this.controls.push(new OpenLayers.Control.Navigation):OpenLayers.Control.TouchNavigation&&this.controls.push(new OpenLayers.Control.TouchNavigation),OpenLayers.Control.Zoom?this.controls.push(new OpenLayers.Control.Zoom):OpenLayers.Control.PanZoom&&this.controls.push(new OpenLayers.Control.PanZoom),OpenLayers.Control.ArgParser&&this.controls.push(new OpenLayers.Control.ArgParser),OpenLayers.Control.Attribution&&
-this.controls.push(new OpenLayers.Control.Attribution)));e=0;for(f=this.controls.length;e<f;e++)this.addControlToMap(this.controls[e]);this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,"unload",this.unloadDestroy);b&&b.layers&&(delete this.center,delete this.zoom,this.addLayers(b.layers),b.center&&!this.getCenter()&&this.setCenter(b.center,b.zoom));this.panMethod&&(this.panTween=new OpenLayers.Tween(this.panMethod));this.zoomMethod&&this.applyTransform.transform&&
-(this.zoomTween=new OpenLayers.Tween(this.zoomMethod))},getViewport:function(){return this.viewPortDiv},render:function(a){this.div=OpenLayers.Util.getElement(a);OpenLayers.Element.addClass(this.div,"olMap");this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);this.div.appendChild(this.viewPortDiv);this.updateSize()},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy)return!1;this.panTween&&(this.panTween.stop(),this.panTween=null);this.zoomTween&&(this.zoomTween.stop(),
-this.zoomTween=null);OpenLayers.Event.stopObserving(window,"unload",this.unloadDestroy);this.unloadDestroy=null;this.updateSizeDestroy&&OpenLayers.Event.stopObserving(window,"resize",this.updateSizeDestroy);this.paddingForPopups=null;if(null!=this.controls){for(var a=this.controls.length-1;0<=a;--a)this.controls[a].destroy();this.controls=null}if(null!=this.layers){for(a=this.layers.length-1;0<=a;--a)this.layers[a].destroy(!1);this.layers=null}this.viewPortDiv&&this.viewPortDiv.parentNode&&this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
-this.viewPortDiv=null;this.tileManager&&(this.tileManager.removeMap(this),this.tileManager=null);this.eventListeners&&(this.events.un(this.eventListeners),this.eventListeners=null);this.events.destroy();this.options=this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:!0})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d="function"==
-typeof c.test;return OpenLayers.Array.filter(this[a],function(a){return a[b]==c||d&&c.test(a[b])})},getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;c<d;c++){var e=
-this.layers[c];if(e.id==a){b=e;break}}return b},setLayerZIndex:function(a,b){a.setZIndex(this.Z_INDEX_BASE[a.isBaseLayer?"BaseLayer":"Overlay"]+5*b)},resetLayersZIndex:function(){for(var a=0,b=this.layers.length;a<b;a++)this.setLayerZIndex(this.layers[a],a)},addLayer:function(a){for(var b=0,c=this.layers.length;b<c;b++)if(this.layers[b]==a)return!1;if(!1===this.events.triggerEvent("preaddlayer",{layer:a}))return!1;this.allOverlays&&(a.isBaseLayer=!1);a.div.className="olLayerDiv";a.div.style.overflow=
-"";this.setLayerZIndex(a,this.layers.length);a.isFixed?this.viewPortDiv.appendChild(a.div):this.layerContainerDiv.appendChild(a.div);this.layers.push(a);a.setMap(this);a.isBaseLayer||this.allOverlays&&!this.baseLayer?null==this.baseLayer?this.setBaseLayer(a):a.setVisibility(!1):a.redraw();this.events.triggerEvent("addlayer",{layer:a});a.events.triggerEvent("added",{map:this,layer:a});a.afterAdd();return!0},addLayers:function(a){for(var b=0,c=a.length;b<c;b++)this.addLayer(a[b])},removeLayer:function(a,
-b){if(!1!==this.events.triggerEvent("preremovelayer",{layer:a})){null==b&&(b=!0);a.isFixed?this.viewPortDiv.removeChild(a.div):this.layerContainerDiv.removeChild(a.div);OpenLayers.Util.removeItem(this.layers,a);a.removeMap(this);a.map=null;if(this.baseLayer==a&&(this.baseLayer=null,b))for(var c=0,d=this.layers.length;c<d;c++){var e=this.layers[c];if(e.isBaseLayer||this.allOverlays){this.setBaseLayer(e);break}}this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:a});a.events.triggerEvent("removed",
-{map:this,layer:a})}},getNumLayers:function(){return this.layers.length},getLayerIndex:function(a){return OpenLayers.Util.indexOf(this.layers,a)},setLayerIndex:function(a,b){var c=this.getLayerIndex(a);0>b?b=0:b>this.layers.length&&(b=this.layers.length);if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c<d;c++)this.setLayerZIndex(this.layers[c],c);this.events.triggerEvent("changelayer",{layer:a,property:"order"});this.allOverlays&&(0===b?this.setBaseLayer(a):
-this.baseLayer!==this.layers[0]&&this.setBaseLayer(this.layers[0]))}},raiseLayer:function(a,b){var c=this.getLayerIndex(a)+b;this.setLayerIndex(a,c)},setBaseLayer:function(a){if(a!=this.baseLayer&&-1!=OpenLayers.Util.indexOf(this.layers,a)){var b=this.getCachedCenter(),c=OpenLayers.Util.getResolutionFromScale(this.getScale(),a.units);null==this.baseLayer||this.allOverlays||this.baseLayer.setVisibility(!1);this.baseLayer=a;if(!this.allOverlays||this.baseLayer.visibility)this.baseLayer.setVisibility(!0),
-!1===this.baseLayer.inRange&&this.baseLayer.redraw();null!=b&&(a=this.getZoomForResolution(c||this.resolution,!0),this.setCenter(b,a,!1,!0));this.events.triggerEvent("changebaselayer",{layer:this.baseLayer})}},addControl:function(a,b){this.controls.push(a);this.addControlToMap(a,b)},addControls:function(a,b){for(var c=1===arguments.length?[]:b,d=0,e=a.length;d<e;d++)this.addControl(a[d],c[d]?c[d]:null)},addControlToMap:function(a,b){a.outsideViewport=null!=a.div;this.displayProjection&&!a.displayProjection&&
-(a.displayProjection=this.displayProjection);a.setMap(this);var c=a.draw(b);c&&!a.outsideViewport&&(c.style.zIndex=this.Z_INDEX_BASE.Control+this.controls.length,this.viewPortDiv.appendChild(c));a.autoActivate&&a.activate()},getControl:function(a){for(var b=null,c=0,d=this.controls.length;c<d;c++){var e=this.controls[c];if(e.id==a){b=e;break}}return b},removeControl:function(a){a&&a==this.getControl(a.id)&&(a.div&&a.div.parentNode==this.viewPortDiv&&this.viewPortDiv.removeChild(a.div),OpenLayers.Util.removeItem(this.controls,
-a))},addPopup:function(a,b){if(b)for(var c=this.popups.length-1;0<=c;--c)this.removePopup(this.popups[c]);a.map=this;this.popups.push(a);if(c=a.draw())c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length,this.layerContainerDiv.appendChild(c)},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;null!=this.size&&(a=this.size.clone());return a},updateSize:function(){var a=this.getCurrentSize();
-if(a&&!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();null==b&&(this.size=b=a);if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a<b;a++)this.layers[a].onMapResize();a=this.getCachedCenter();null!=this.baseLayer&&null!=a&&(b=this.getZoom(),this.zoom=null,this.setCenter(a,b))}}this.events.triggerEvent("updatesize")},getCurrentSize:function(){var a=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(0==a.w&&0==a.h||isNaN(a.w)&&isNaN(a.h))a.w=this.div.offsetWidth,
-a.h=this.div.offsetHeight;if(0==a.w&&0==a.h||isNaN(a.w)&&isNaN(a.h))a.w=parseInt(this.div.style.width),a.h=parseInt(this.div.style.height);return a},calculateBounds:function(a,b){var c=null;null==a&&(a=this.getCachedCenter());null==b&&(b=this.getResolution());if(null!=a&&null!=b)var c=this.size.w*b/2,d=this.size.h*b/2,c=new OpenLayers.Bounds(a.lon-c,a.lat-d,a.lon+c,a.lat+d);return c},getCenter:function(){var a=null,b=this.getCachedCenter();b&&(a=b.clone());return a},getCachedCenter:function(){!this.center&&
-this.size&&(this.center=this.getLonLatFromViewPortPx({x:this.size.w/2,y:this.size.h/2}));return this.center},getZoom:function(){return this.zoom},pan:function(a,b,c){c=OpenLayers.Util.applyDefaults(c,{animate:!0,dragging:!1});if(c.dragging)0==a&&0==b||this.moveByPx(a,b);else{var d=this.getViewPortPxFromLonLat(this.getCachedCenter());a=d.add(a,b);if(this.dragging||!a.equals(d))d=this.getLonLatFromViewPortPx(a),c.animate?this.panTo(d):(this.moveTo(d),this.dragging&&(this.dragging=!1,this.events.triggerEvent("moveend")))}},
-panTo:function(a){if(this.panTween&&this.getExtent().scale(this.panRatio).containsLonLat(a)){var b=this.getCachedCenter();if(!a.equals(b)){var b=this.getPixelFromLonLat(b),c=this.getPixelFromLonLat(a),d=0,e=0;this.panTween.start({x:0,y:0},{x:c.x-b.x,y:c.y-b.y},this.panDuration,{callbacks:{eachStep:OpenLayers.Function.bind(function(a){this.moveByPx(a.x-d,a.y-e);d=Math.round(a.x);e=Math.round(a.y)},this),done:OpenLayers.Function.bind(function(b){this.moveTo(a);this.dragging=!1;this.events.triggerEvent("moveend")},
-this)}})}}else this.setCenter(a)},setCenter:function(a,b,c,d){this.panTween&&this.panTween.stop();this.zoomTween&&this.zoomTween.stop();this.moveTo(a,b,{dragging:c,forceZoomChange:d})},moveByPx:function(a,b){var c=this.size.w/2,d=this.size.h/2,e=c+a,f=d+b,g=this.baseLayer.wrapDateLine,h=0,k=0;this.restrictedExtent&&(h=c,k=d,g=!1);a=g||e<=this.maxPx.x-h&&e>=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-k&&f>=this.minPx.y+k?Math.round(b):0;if(a||b){this.dragging||(this.dragging=!0,this.events.triggerEvent("movestart"));
-this.center=null;a&&(this.layerContainerOriginPx.x-=a,this.minPx.x-=a,this.maxPx.x-=a);b&&(this.layerContainerOriginPx.y-=b,this.minPx.y-=b,this.maxPx.y-=b);this.applyTransform();d=0;for(e=this.layers.length;d<e;++d)c=this.layers[d],c.visibility&&(c===this.baseLayer||c.inRange)&&(c.moveByPx(a,b),c.events.triggerEvent("move"));this.events.triggerEvent("move")}},adjustZoom:function(a){if(this.baseLayer&&this.baseLayer.wrapDateLine){var b=this.baseLayer.resolutions,c=this.getMaxExtent().getWidth()/this.size.w;
-if(this.getResolutionForZoom(a)>c)if(this.fractionalZoom)a=this.getZoomForResolution(c);else for(var d=a|0,e=b.length;d<e;++d)if(b[d]<=c){a=d;break}}return a},getMinZoom:function(){return this.adjustZoom(0)},moveTo:function(a,b,c){null==a||a instanceof OpenLayers.LonLat||(a=new OpenLayers.LonLat(a));c||(c={});null!=b&&(b=parseFloat(b),this.fractionalZoom||(b=Math.round(b)));var d=b;b=this.adjustZoom(b);b!==d&&(a=this.getCenter());var d=c.dragging||this.dragging,e=c.forceZoomChange;this.getCachedCenter()||
-this.isValidLonLat(a)||(a=this.maxExtent.getCenterLonLat(),this.center=a.clone());if(null!=this.restrictedExtent){null==a&&(a=this.center);null==b&&(b=this.getZoom());var f=this.getResolutionForZoom(b),f=this.calculateBounds(a,f);if(!this.restrictedExtent.containsBounds(f)){var g=this.restrictedExtent.getCenterLonLat();f.getWidth()>this.restrictedExtent.getWidth()?a=new OpenLayers.LonLat(g.lon,a.lat):f.left<this.restrictedExtent.left?a=a.add(this.restrictedExtent.left-f.left,0):f.right>this.restrictedExtent.right&&
-(a=a.add(this.restrictedExtent.right-f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottom<this.restrictedExtent.bottom?a=a.add(0,this.restrictedExtent.bottom-f.bottom):f.top>this.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart",{zoomChanged:e});f&&(!e&&this.center&&this.centerLayerContainer(a),
-this.center=a.clone());a=e?this.getResolutionForZoom(b):this.getResolution();if(e||null==this.layerContainerOrigin){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerOriginPx.x=0;this.layerContainerOriginPx.y=0;this.applyTransform();var f=this.getMaxExtent({restricted:!0}),h=f.getCenterLonLat(),g=this.center.lon-h.lon,h=h.lat-this.center.lat,k=Math.round(f.getWidth()/a),l=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-k)/2-g/a,y:(this.size.h-l)/2-h/a};this.maxPx={x:this.minPx.x+
-Math.round(f.getWidth()/a),y:this.minPx.y+Math.round(f.getHeight()/a)}}e&&(this.zoom=b,this.resolution=a);a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;0<=b;--b)f=this.layers[b],f===this.baseLayer||f.isBaseLayer||(g=f.calculateInRange(),f.inRange!=g&&((f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"})),
-g&&f.visibility&&(f.moveTo(a,e,c.dragging),c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e})));this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b<c;b++)this.popups[b].updatePosition();this.events.triggerEvent("zoomend")}}},centerLayerContainer:function(a){var b=this.getViewPortPxFromLonLat(this.layerContainerOrigin),c=this.getViewPortPxFromLonLat(a);if(null!=b&&null!=c){var d=this.layerContainerOriginPx.x;a=this.layerContainerOriginPx.y;
-var e=Math.round(b.x-c.x),b=Math.round(b.y-c.y);this.applyTransform(this.layerContainerOriginPx.x=e,this.layerContainerOriginPx.y=b);d-=e;a-=b;this.minPx.x-=d;this.maxPx.x-=d;this.minPx.y-=a;this.maxPx.y-=a}},isValidZoomLevel:function(a){return null!=a&&0<=a&&a<this.getNumZoomLevels()},isValidLonLat:function(a){var b=!1;null!=a&&(b=this.getMaxExtent(),b=b.containsLonLat(a,{worldBounds:this.baseLayer.wrapDateLine&&b}));return b},getProjection:function(){var a=this.getProjectionObject();return a?a.getCode():
-null},getProjectionObject:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.projection);return a},getMaxResolution:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.maxResolution);return a},getMaxExtent:function(a){var b=null;a&&a.restricted&&this.restrictedExtent?b=this.restrictedExtent:null!=this.baseLayer&&(b=this.baseLayer.maxExtent);return b},getNumZoomLevels:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.numZoomLevels);return a},getExtent:function(){var a=
-null;null!=this.baseLayer&&(a=this.baseLayer.getExtent());return a},getResolution:function(){var a=null;null!=this.baseLayer?a=this.baseLayer.getResolution():!0===this.allOverlays&&0<this.layers.length&&(a=this.layers[0].getResolution());return a},getUnits:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.units);return a},getScale:function(){var a=null;null!=this.baseLayer&&(a=this.getResolution(),a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units));return a},getZoomForExtent:function(a,
-b){var c=null;null!=this.baseLayer&&(c=this.baseLayer.getZoomForExtent(a,b));return c},getResolutionForZoom:function(a){var b=null;this.baseLayer&&(b=this.baseLayer.getResolutionForZoom(a));return b},getZoomForResolution:function(a,b){var c=null;null!=this.baseLayer&&(c=this.baseLayer.getZoomForResolution(a,b));return c},zoomTo:function(a,b){var c=this;if(c.isValidZoomLevel(a))if(c.baseLayer.wrapDateLine&&(a=c.adjustZoom(a)),c.zoomTween){var d=c.getResolution(),e=c.getResolutionForZoom(a),f={scale:1},
-d={scale:d/e};c.zoomTween.playing&&c.zoomTween.duration<3*c.zoomDuration?c.zoomTween.finish={scale:c.zoomTween.finish.scale*d.scale}:(b||(e=c.getSize(),b={x:e.w/2,y:e.h/2}),c.zoomTween.start(f,d,c.zoomDuration,{minFrameRate:50,callbacks:{eachStep:function(a){var d=c.layerContainerOriginPx;a=a.scale;c.applyTransform(d.x+((a-1)*(d.x-b.x)|0),d.y+((a-1)*(d.y-b.y)|0),a)},done:function(a){c.applyTransform();a=c.getResolution()/a.scale;var d=c.getZoomForResolution(a,!0);c.moveTo(c.getZoomTargetCenter(b,
-a),d,!0)}}}))}else f=b?c.getZoomTargetCenter(b,c.getResolutionForZoom(a)):null,c.setCenter(f,a)},zoomIn:function(){this.zoomTo(this.getZoom()+1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,b){a instanceof OpenLayers.Bounds||(a=new OpenLayers.Bounds(a));var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right<a.left;)a.right+=c.getWidth();c=a.getCenterLonLat().wrapDateLine(c)}this.setCenter(c,this.getZoomForExtent(a,b))},
-zoomToMaxExtent:function(a){a=this.getMaxExtent({restricted:a?a.restricted:!0});this.zoomToExtent(a)},zoomToScale:function(a,b){var c=OpenLayers.Util.getResolutionFromScale(a,this.baseLayer.units),d=this.size.w*c/2,c=this.size.h*c/2,e=this.getCachedCenter(),d=new OpenLayers.Bounds(e.lon-d,e.lat-c,e.lon+d,e.lat+c);this.zoomToExtent(d,b)},getLonLatFromViewPortPx:function(a){var b=null;null!=this.baseLayer&&(b=this.baseLayer.getLonLatFromViewPortPx(a));return b},getViewPortPxFromLonLat:function(a){var b=
-null;null!=this.baseLayer&&(b=this.baseLayer.getViewPortPxFromLonLat(a));return b},getZoomTargetCenter:function(a,b){var c=null,d=this.getSize(),e=d.w/2-a.x,d=a.y-d.h/2,f=this.getLonLatFromPixel(a);f&&(c=new OpenLayers.LonLat(f.lon+e*b,f.lat+d*b));return c},getLonLatFromPixel:function(a){return this.getLonLatFromViewPortPx(a)},getPixelFromLonLat:function(a){a=this.getViewPortPxFromLonLat(a);a.x=Math.round(a.x);a.y=Math.round(a.y);return a},getGeodesicPixelSize:function(a){var b=a?this.getLonLatFromPixel(a):
-this.getCachedCenter()||new OpenLayers.LonLat(0,0),c=this.getResolution();a=b.add(-c/2,0);var d=b.add(c/2,0),e=b.add(0,-c/2),b=b.add(0,c/2),c=new OpenLayers.Projection("EPSG:4326"),f=this.getProjectionObject()||c;f.equals(c)||(a.transform(f,c),d.transform(f,c),e.transform(f,c),b.transform(f,c));return new OpenLayers.Size(OpenLayers.Util.distVincenty(a,d),OpenLayers.Util.distVincenty(e,b))},getViewPortPxFromLayerPx:function(a){var b=null;null!=a&&(b=a.add(this.layerContainerOriginPx.x,this.layerContainerOriginPx.y));
-return b},getLayerPxFromViewPortPx:function(a){var b=null;null!=a&&(b=a.add(-this.layerContainerOriginPx.x,-this.layerContainerOriginPx.y),isNaN(b.x)||isNaN(b.y))&&(b=null);return b},getLonLatFromLayerPx:function(a){a=this.getViewPortPxFromLayerPx(a);return this.getLonLatFromViewPortPx(a)},getLayerPxFromLonLat:function(a){a=this.getPixelFromLonLat(a);return this.getLayerPxFromViewPortPx(a)},applyTransform:function(a,b,c){c=c||1;var d=this.layerContainerOriginPx,e=1!==c;a=a||d.x;b=b||d.y;var f=this.layerContainerDiv.style,
-g=this.applyTransform.transform,h=this.applyTransform.template;if(void 0===g&&(g=OpenLayers.Util.vendorPrefix.style("transform"),this.applyTransform.transform=g)){var k=OpenLayers.Element.getStyle(this.viewPortDiv,OpenLayers.Util.vendorPrefix.css("transform"));k&&"none"===k||(h=["translate3d(",",0) ","scale3d(",",1)"],f[g]=[h[0],"0,0",h[1]].join(""));h&&~f[g].indexOf(h[0])||(h=["translate(",") ","scale(",")"]);this.applyTransform.template=h}null===g||"translate3d("!==h[0]&&!0!==e?(f.left=a+"px",f.top=
-b+"px",null!==g&&(f[g]="")):(!0===e&&"translate("===h[0]&&(a-=d.x,b-=d.y,f.left=d.x+"px",f.top=d.y+"px"),f[g]=[h[0],a,"px,",b,"px",h[1],h[2],c,",",c,h[3]].join(""))},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:!1,evt:null,touch:!1,initialize:function(a,b,c){OpenLayers.Util.extend(this,c);this.control=a;this.callbacks=b;(a=this.map||a.map)&&this.setMap(a);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},setMap:function(a){this.map=a},checkModifiers:function(a){return null==this.keyMask?!0:((a.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(a.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(a.altKey?OpenLayers.Handler.MOD_ALT:
-0)|(a.metaKey?OpenLayers.Handler.MOD_META:0))==this.keyMask},activate:function(){if(this.active)return!1;for(var a=OpenLayers.Events.prototype.BROWSER_EVENTS,b=0,c=a.length;b<c;b++)this[a[b]]&&this.register(a[b],this[a[b]]);return this.active=!0},deactivate:function(){if(!this.active)return!1;for(var a=OpenLayers.Events.prototype.BROWSER_EVENTS,b=0,c=a.length;b<c;b++)this[a[b]]&&this.unregister(a[b],this[a[b]]);this.active=this.touch=!1;return!0},startTouch:function(){if(!this.touch){this.touch=!0;
-for(var a="mousedown mouseup mousemove click dblclick mouseout".split(" "),b=0,c=a.length;b<c;b++)this[a[b]]&&this.unregister(a[b],this[a[b]])}},callback:function(a,b){a&&this.callbacks[a]&&this.callbacks[a].apply(this.control,b)},register:function(a,b){this.map.events.registerPriority(a,this,b);this.map.events.registerPriority(a,this,this.setEvent)},unregister:function(a,b){this.map.events.unregister(a,this,b);this.map.events.unregister(a,this,this.setEvent)},setEvent:function(a){this.evt=a;return!0},
-destroy:function(){this.deactivate();this.control=this.map=null},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Handler.MOD_META=8;OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:!0,"double":!1,pixelTolerance:0,dblclickTolerance:13,stopSingle:!1,stopDouble:!1,timerId:null,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(a){this.startTouch();this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return!0},touchmove:function(a){this.last=this.getEventInfo(a);return!0},touchend:function(a){this.down&&(a.xy=this.last.xy,a.lastTouches=this.last.touches,this.handleSingle(a),
-this.down=null);return!0},mousedown:function(a){this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return!0},mouseup:function(a){var b=!0;this.checkModifiers(a)&&(this.control.handleRightClicks&&OpenLayers.Event.isRightClick(a))&&(b=this.rightclick(a));return b},rightclick:function(a){if(this.passesTolerance(a)){if(null!=this.rightclickTimerId)return this.clearTimer(),this.callback("dblrightclick",[a]),!this.stopDouble;a=this["double"]?OpenLayers.Util.extend({},a):this.callback("rightclick",
-[a]);a=OpenLayers.Function.bind(this.delayedRightCall,this,a);this.rightclickTimerId=window.setTimeout(a,this.delay)}return!this.stopSingle},delayedRightCall:function(a){this.rightclickTimerId=null;a&&this.callback("rightclick",[a])},click:function(a){this.last||(this.last=this.getEventInfo(a));this.handleSingle(a);return!this.stopSingle},dblclick:function(a){this.handleDouble(a);return!this.stopDouble},handleDouble:function(a){this.passesDblclickTolerance(a)&&(this["double"]&&this.callback("dblclick",
-[a]),this.clearTimer())},handleSingle:function(a){this.passesTolerance(a)&&(null!=this.timerId?(this.last.touches&&1===this.last.touches.length&&(this["double"]&&OpenLayers.Event.preventDefault(a),this.handleDouble(a)),this.last.touches&&2===this.last.touches.length||this.clearTimer()):(this.first=this.getEventInfo(a),a=this.single?OpenLayers.Util.extend({},a):null,this.queuePotentialClick(a)))},queuePotentialClick:function(a){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,
-this,a),this.delay)},passesTolerance:function(a){var b=!0;if(null!=this.pixelTolerance&&this.down&&this.down.xy&&(b=this.pixelTolerance>=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length){a=0;for(var c=this.down.touches.length;a<c;++a)if(this.getTouchDistance(this.down.touches[a],this.last.touches[a])>this.pixelTolerance){b=!1;break}}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,
-2))},passesDblclickTolerance:function(a){a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);null!=this.rightclickTimerId&&(window.clearTimeout(this.rightclickTimerId),this.rightclickTimerId=null)},delayedCall:function(a){this.timerId=null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,
-e=0;e<c;e++)d=a.touches[e],b[e]={clientX:d.olClientX,clientY:d.olClientY}}return{xy:a.xy,touches:b}},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.clearTimer(),this.last=this.first=this.down=null,a=!0);return a},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!0,dragging:!1,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:!1,documentEvents:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(!0===this.documentDrag){var d=this;this._docMove=function(a){d.mousemove({xy:{x:a.clientX,y:a.clientY},element:document})};this._docUp=function(a){d.mouseup({xy:{x:a.clientX,y:a.clientY}})}}},
-dragstart:function(a){var b=!0;this.dragging=!1;this.checkModifiers(a)&&(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))?(this.started=!0,this.last=this.start=a.xy,OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown"),this.down(a),this.callback("down",[a.xy]),OpenLayers.Event.preventDefault(a),this.oldOnselectstart||(this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True),document.onselectstart=OpenLayers.Function.False,b=!this.stopDown):
-(this.started=!1,this.last=this.start=null);return b},dragmove:function(a){this.lastMoveEvt=a;!this.started||(this.timeoutId||a.xy.x==this.last.x&&a.xy.y==this.last.y)||(!0===this.documentDrag&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents()),0<this.interval&&(this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval)),this.dragging=!0,this.move(a),this.callback("move",[a.xy]),this.oldOnselectstart||(this.oldOnselectstart=
-document.onselectstart,document.onselectstart=OpenLayers.Function.False),this.last=a.xy);return!0},dragend:function(a){if(this.started){!0===this.documentDrag&&this.documentEvents&&(this.adjustXY(a),this.removeDocumentEvents());var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart=this.oldOnselectstart}return!0},down:function(a){},move:function(a){},
-up:function(a){},out:function(a){},mousedown:function(a){return this.dragstart(a)},touchstart:function(a){this.startTouch();return this.dragstart(a)},mousemove:function(a){return this.dragmove(a)},touchmove:function(a){return this.dragmove(a)},removeTimeout:function(){this.timeoutId=null;this.dragging&&this.mousemove(this.lastMoveEvt)},mouseup:function(a){return this.dragend(a)},touchend:function(a){a.xy=this.last;return this.dragend(a)},mouseout:function(a){if(this.started&&OpenLayers.Util.mouseLeft(a,
-this.map.viewPortDiv))if(!0===this.documentDrag)this.addDocumentEvents();else{var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(a);this.callback("out",[]);b&&this.callback("done",[a.xy]);document.onselectstart&&(document.onselectstart=this.oldOnselectstart)}return!0},click:function(a){return this.start==this.last},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.dragging=
-!1,a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.dragging=this.started=!1,this.last=this.start=null,a=!0,OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown"));return a},adjustXY:function(a){var b=OpenLayers.Util.pagePosition(this.map.viewPortDiv);a.xy.x-=b[0];a.xy.y-=b[1]},addDocumentEvents:function(){OpenLayers.Element.addClass(document.body,"olDragDown");this.documentEvents=!0;OpenLayers.Event.observe(document,"mousemove",
-this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp)},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=!1;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp)},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{element:null,ovmap:null,size:{w:180,h:90},layers:null,minRectSize:15,minRectDisplayClass:"RectReplacement",minRatio:8,maxRatio:32,mapOptions:null,autoPan:!1,handlers:null,resolutionFactor:1,maximized:!1,maximizeTitle:"",minimizeTitle:"",initialize:function(a){this.layers=[];this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,[a])},destroy:function(){this.mapDiv&&(this.handlers.click&&this.handlers.click.destroy(),
-this.handlers.drag&&this.handlers.drag.destroy(),this.ovmap&&this.ovmap.viewPortDiv.removeChild(this.extentRectangle),this.extentRectangle=null,this.rectEvents&&(this.rectEvents.destroy(),this.rectEvents=null),this.ovmap&&(this.ovmap.destroy(),this.ovmap=null),this.element.removeChild(this.mapDiv),this.mapDiv=null,this.div.removeChild(this.element),this.element=null,this.maximizeDiv&&(this.div.removeChild(this.maximizeDiv),this.maximizeDiv=null),this.minimizeDiv&&(this.div.removeChild(this.minimizeDiv),
-this.minimizeDiv=null),this.map.events.un({buttonclick:this.onButtonClick,moveend:this.update,changebaselayer:this.baseLayerDraw,scope:this}),OpenLayers.Control.prototype.destroy.apply(this,arguments))},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(0===this.layers.length)if(this.map.baseLayer)this.layers=[this.map.baseLayer.clone()];else return this.map.events.register("changebaselayer",this,this.baseLayerDraw),this.div;this.element=document.createElement("div");this.element.className=
-this.displayClass+"Element";this.element.style.display="none";this.mapDiv=document.createElement("div");this.mapDiv.style.width=this.size.w+"px";this.mapDiv.style.height=this.size.h+"px";this.mapDiv.style.position="relative";this.mapDiv.style.overflow="hidden";this.mapDiv.id=OpenLayers.Util.createUniqueID("overviewMap");this.extentRectangle=document.createElement("div");this.extentRectangle.style.position="absolute";this.extentRectangle.style.zIndex=1E3;this.extentRectangle.className=this.displayClass+
-"ExtentRectangle";this.element.appendChild(this.mapDiv);this.div.appendChild(this.element);if(this.outsideViewport)this.element.style.display="";else{this.div.className+=" "+this.displayClass+"Container";var a=OpenLayers.Util.getImageLocation("layer-switcher-maximize.png");this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+"MaximizeButton",null,null,a,"absolute");this.maximizeDiv.style.display="none";this.maximizeDiv.className=this.displayClass+"MaximizeButton olButton";this.maximizeTitle&&
-(this.maximizeDiv.title=this.maximizeTitle);this.div.appendChild(this.maximizeDiv);a=OpenLayers.Util.getImageLocation("layer-switcher-minimize.png");this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv",null,null,a,"absolute");this.minimizeDiv.style.display="none";this.minimizeDiv.className=this.displayClass+"MinimizeButton olButton";this.minimizeTitle&&(this.minimizeDiv.title=this.minimizeTitle);this.div.appendChild(this.minimizeDiv);this.minimizeControl()}this.map.getExtent()&&
-this.update();this.map.events.on({buttonclick:this.onButtonClick,moveend:this.update,scope:this});this.maximized&&this.maximizeControl();return this.div},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",this,this.baseLayerDraw)},rectDrag:function(a){var b=this.handlers.drag.last.x-a.x,c=this.handlers.drag.last.y-a.y;if(0!=b||0!=c){var d=this.rectPxBounds.top,e=this.rectPxBounds.left;a=Math.abs(this.rectPxBounds.getHeight());var f=this.rectPxBounds.getWidth(),c=Math.max(0,
-d-c),c=Math.min(c,this.ovmap.size.h-this.hComp-a),b=Math.max(0,e-b),b=Math.min(b,this.ovmap.size.w-this.wComp-f);this.setRectPxBounds(new OpenLayers.Bounds(b,c+a,b+f,c))}},mapDivClick:function(a){var b=this.rectPxBounds.getCenterPixel(),c=a.xy.x-b.x,d=a.xy.y-b.y,e=this.rectPxBounds.top,f=this.rectPxBounds.left;a=Math.abs(this.rectPxBounds.getHeight());b=this.rectPxBounds.getWidth();d=Math.max(0,e+d);d=Math.min(d,this.ovmap.size.h-a);c=Math.max(0,f+c);c=Math.min(c,this.ovmap.size.w-b);this.setRectPxBounds(new OpenLayers.Bounds(c,
-d+a,c+b,d));this.updateMapToRect()},onButtonClick:function(a){a.buttonElement===this.minimizeDiv?this.minimizeControl():a.buttonElement===this.maximizeDiv&&this.maximizeControl()},maximizeControl:function(a){this.element.style.display="";this.showToggle(!1);null!=a&&OpenLayers.Event.stop(a)},minimizeControl:function(a){this.element.style.display="none";this.showToggle(!0);null!=a&&OpenLayers.Event.stop(a)},showToggle:function(a){this.maximizeDiv&&(this.maximizeDiv.style.display=a?"":"none");this.minimizeDiv&&
-(this.minimizeDiv.style.display=a?"none":"")},update:function(){null==this.ovmap&&this.createMap();!this.autoPan&&this.isSuitableOverview()||this.updateOverview();this.updateRectToMap()},isSuitableOverview:function(){var a=this.map.getExtent(),b=this.map.getMaxExtent(),a=new OpenLayers.Bounds(Math.max(a.left,b.left),Math.max(a.bottom,b.bottom),Math.min(a.right,b.right),Math.min(a.top,b.top));this.ovmap.getProjection()!=this.map.getProjection()&&(a=a.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject()));
-b=this.ovmap.getResolution()/this.map.getResolution();return b>this.minRatio&&b<=this.maxRatio&&this.ovmap.getExtent().containsBounds(a)},updateOverview:function(){var a=this.map.getResolution(),b=this.ovmap.getResolution(),c=b/a;c>this.maxRatio?b=this.minRatio*a:c<=this.minRatio&&(b=this.maxRatio*a);this.ovmap.getProjection()!=this.map.getProjection()?(a=this.map.center.clone(),a.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject())):a=this.map.center;this.ovmap.setCenter(a,
-this.ovmap.getZoomForResolution(b*this.resolutionFactor));this.updateRectToMap()},createMap:function(){var a=OpenLayers.Util.extend({controls:[],maxResolution:"auto",fallThrough:!1},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,a);this.ovmap.viewPortDiv.appendChild(this.extentRectangle);OpenLayers.Event.stopObserving(window,"unload",this.ovmap.unloadDestroy);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=(this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
-"border-left-width"))+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-right-width")))?this.wComp:2;this.hComp=(this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-top-width"))+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-bottom-width")))?this.hComp:2;this.handlers.drag=new OpenLayers.Handler.Drag(this,{move:this.rectDrag,done:this.updateMapToRect},{map:this.ovmap});this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.mapDivClick},
-{single:!0,"double":!1,stopSingle:!0,stopDouble:!0,pixelTolerance:1,map:this.ovmap});this.handlers.click.activate();this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,!0);this.rectEvents.register("mouseover",this,function(a){this.handlers.drag.active||this.map.dragging||this.handlers.drag.activate()});this.rectEvents.register("mouseout",this,function(a){this.handlers.drag.dragging||this.handlers.drag.deactivate()});if(this.ovmap.getProjection()!=this.map.getProjection()){var a=this.map.getProjectionObject().getUnits()||
-this.map.units||this.map.baseLayer.units,b=this.ovmap.getProjectionObject().getUnits()||this.ovmap.units||this.ovmap.baseLayer.units;this.resolutionFactor=a&&b?OpenLayers.INCHES_PER_UNIT[a]/OpenLayers.INCHES_PER_UNIT[b]:1}},updateRectToMap:function(){var a;a=this.ovmap.getProjection()!=this.map.getProjection()?this.map.getExtent().transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject()):this.map.getExtent();(a=this.getRectBoundsFromMapBounds(a))&&this.setRectPxBounds(a)},updateMapToRect:function(){var a=
-this.getMapBoundsFromRectBounds(this.rectPxBounds);this.ovmap.getProjection()!=this.map.getProjection()&&(a=a.transform(this.ovmap.getProjectionObject(),this.map.getProjectionObject()));this.map.panTo(a.getCenterLonLat())},setRectPxBounds:function(a){var b=Math.max(a.top,0),c=Math.max(a.left,0),d=Math.min(a.top+Math.abs(a.getHeight()),this.ovmap.size.h-this.hComp);a=Math.min(a.left+a.getWidth(),this.ovmap.size.w-this.wComp);var e=Math.max(a-c,0),f=Math.max(d-b,0);e<this.minRectSize||f<this.minRectSize?
-(this.extentRectangle.className=this.displayClass+this.minRectDisplayClass,e=c+e/2-this.minRectSize/2,this.extentRectangle.style.top=Math.round(b+f/2-this.minRectSize/2)+"px",this.extentRectangle.style.left=Math.round(e)+"px",this.extentRectangle.style.height=this.minRectSize+"px",this.extentRectangle.style.width=this.minRectSize+"px"):(this.extentRectangle.className=this.displayClass+"ExtentRectangle",this.extentRectangle.style.top=Math.round(b)+"px",this.extentRectangle.style.left=Math.round(c)+
-"px",this.extentRectangle.style.height=Math.round(f)+"px",this.extentRectangle.style.width=Math.round(e)+"px");this.rectPxBounds=new OpenLayers.Bounds(Math.round(c),Math.round(d),Math.round(a),Math.round(b))},getRectBoundsFromMapBounds:function(a){var b=this.getOverviewPxFromLonLat({lon:a.left,lat:a.bottom});a=this.getOverviewPxFromLonLat({lon:a.right,lat:a.top});var c=null;b&&a&&(c=new OpenLayers.Bounds(b.x,b.y,a.x,a.y));return c},getMapBoundsFromRectBounds:function(a){var b=this.getLonLatFromOverviewPx({x:a.left,
-y:a.bottom});a=this.getLonLatFromOverviewPx({x:a.right,y:a.top});return new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat)},getLonLatFromOverviewPx:function(a){var b=this.ovmap.size,c=this.ovmap.getResolution(),d=this.ovmap.getExtent().getCenterLonLat();return{lon:d.lon+(a.x-b.w/2)*c,lat:d.lat-(a.y-b.h/2)*c}},getOverviewPxFromLonLat:function(a){var b=this.ovmap.getResolution(),c=this.ovmap.getExtent();if(c)return{x:Math.round(1/b*(a.lon-c.left)),y:Math.round(1/b*(c.top-a.lat))}},CLASS_NAME:"OpenLayers.Control.OverviewMap"});OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:1,alwaysInRange:null,RESOLUTION_PROPERTIES:"scales resolutions maxScale minScale maxResolution minResolution numZoomLevels maxZoomLevel".split(" "),events:null,map:null,isBaseLayer:!1,alpha:!1,displayInLayerSwitcher:!0,visibility:!0,attribution:null,inRange:!1,imageSize:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,
-numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:!1,wrapDateLine:!1,metadata:null,initialize:function(a,b){this.metadata={};b=OpenLayers.Util.extend({},b);null!=this.alwaysInRange&&(b.alwaysInRange=this.alwaysInRange);this.addOptions(b);this.name=a;if(null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"),this.div=OpenLayers.Util.createDiv(this.id),this.div.style.width="100%",this.div.style.height="100%",this.div.dir="ltr",this.events=new OpenLayers.Events(this,
-this.div),this.eventListeners instanceof Object))this.events.on(this.eventListeners)},destroy:function(a){null==a&&(a=!0);null!=this.map&&this.map.removeLayer(this,a);this.options=this.div=this.name=this.map=this.projection=null;this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy());this.events=this.eventListeners=null},clone:function(a){null==a&&(a=new OpenLayers.Layer(this.name,this.getOptions()));OpenLayers.Util.applyDefaults(a,this);a.map=null;return a},
-getOptions:function(){var a={},b;for(b in this.options)a[b]=this[b];return a},setName:function(a){a!=this.name&&(this.name=a,null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"name"}))},addOptions:function(a,b){null==this.options&&(this.options={});a&&("string"==typeof a.projection&&(a.projection=new OpenLayers.Projection(a.projection)),a.projection&&OpenLayers.Util.applyDefaults(a,OpenLayers.Projection.defaults[a.projection.getCode()]),!a.maxExtent||a.maxExtent instanceof
-OpenLayers.Bounds||(a.maxExtent=new OpenLayers.Bounds(a.maxExtent)),!a.minExtent||a.minExtent instanceof OpenLayers.Bounds||(a.minExtent=new OpenLayers.Bounds(a.minExtent)));OpenLayers.Util.extend(this.options,a);OpenLayers.Util.extend(this,a);this.projection&&this.projection.getUnits()&&(this.units=this.projection.getUnits());if(this.map){var c=this.map.getResolution(),d=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]),e;for(e in a)if(a.hasOwnProperty(e)&&0<=OpenLayers.Util.indexOf(d,
-e)){this.initResolutions();b&&this.map.baseLayer===this&&(this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(c),!1,!0),this.map.events.triggerEvent("changebaselayer",{layer:this}));break}}},onMapResize:function(){},redraw:function(){var a=!1;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();b&&(this.inRange&&this.visibility)&&(this.moveTo(b,!0,!1),this.events.triggerEvent("moveend",{zoomChanged:!0}),a=!0)}return a},moveTo:function(a,b,c){a=this.visibility;
-this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(a,b){},setMap:function(a){null==this.map&&(this.map=a,this.maxExtent=this.maxExtent||this.map.maxExtent,this.minExtent=this.minExtent||this.map.minExtent,this.projection=this.projection||this.map.projection,"string"==typeof this.projection&&(this.projection=new OpenLayers.Projection(this.projection)),this.units=this.projection.getUnits()||this.units||this.map.units,this.initResolutions(),this.isBaseLayer||(this.inRange=this.calculateInRange(),
-this.div.style.display=this.visibility&&this.inRange?"":"none"),this.setTileSize())},afterAdd:function(){},removeMap:function(a){},getImageSize:function(a){return this.imageSize||this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();this.gutter&&(this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter))},getVisibility:function(){return this.visibility},setVisibility:function(a){a!=this.visibility&&(this.visibility=a,this.display(a),
-this.redraw(),null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"}),this.events.triggerEvent("visibilitychanged"))},display:function(a){a!=("none"!=this.div.style.display)&&(this.div.style.display=a&&this.calculateInRange()?"block":"none")},calculateInRange:function(){var a=!1;this.alwaysInRange?a=!0:this.map&&(a=this.map.getResolution(),a=a>=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){a!=this.isBaseLayer&&(this.isBaseLayer=
-a,null!=this.map&&this.map.events.triggerEvent("changebaselayer",{layer:this}))},initResolutions:function(){var a,b,c,d={},e=!0;a=0;for(b=this.RESOLUTION_PROPERTIES.length;a<b;a++)c=this.RESOLUTION_PROPERTIES[a],d[c]=this.options[c],e&&this.options[c]&&(e=!1);null==this.options.alwaysInRange&&(this.alwaysInRange=e);null==d.resolutions&&(d.resolutions=this.resolutionsFromScales(d.scales));null==d.resolutions&&(d.resolutions=this.calculateResolutions(d));if(null==d.resolutions){a=0;for(b=this.RESOLUTION_PROPERTIES.length;a<
-b;a++)c=this.RESOLUTION_PROPERTIES[a],d[c]=null!=this.options[c]?this.options[c]:this.map[c];null==d.resolutions&&(d.resolutions=this.resolutionsFromScales(d.scales));null==d.resolutions&&(d.resolutions=this.calculateResolutions(d))}var f;this.options.maxResolution&&"auto"!==this.options.maxResolution&&(f=this.options.maxResolution);this.options.minScale&&(f=OpenLayers.Util.getResolutionFromScale(this.options.minScale,this.units));var g;this.options.minResolution&&"auto"!==this.options.minResolution&&
-(g=this.options.minResolution);this.options.maxScale&&(g=OpenLayers.Util.getResolutionFromScale(this.options.maxScale,this.units));d.resolutions&&(d.resolutions.sort(function(a,b){return b-a}),f||(f=d.resolutions[0]),g||(g=d.resolutions[d.resolutions.length-1]));if(this.resolutions=d.resolutions){b=this.resolutions.length;this.scales=Array(b);for(a=0;a<b;a++)this.scales[a]=OpenLayers.Util.getScaleFromResolution(this.resolutions[a],this.units);this.numZoomLevels=b}if(this.minResolution=g)this.maxScale=
-OpenLayers.Util.getScaleFromResolution(g,this.units);if(this.maxResolution=f)this.minScale=OpenLayers.Util.getScaleFromResolution(f,this.units)},resolutionsFromScales:function(a){if(null!=a){var b,c,d;d=a.length;b=Array(d);for(c=0;c<d;c++)b[c]=OpenLayers.Util.getResolutionFromScale(a[c],this.units);return b}},calculateResolutions:function(a){var b,c,d=a.maxResolution;null!=a.minScale?d=OpenLayers.Util.getResolutionFromScale(a.minScale,this.units):"auto"==d&&null!=this.maxExtent&&(b=this.map.getSize(),
-c=this.maxExtent.getWidth()/b.w,b=this.maxExtent.getHeight()/b.h,d=Math.max(c,b));c=a.minResolution;null!=a.maxScale?c=OpenLayers.Util.getResolutionFromScale(a.maxScale,this.units):"auto"==a.minResolution&&null!=this.minExtent&&(b=this.map.getSize(),c=this.minExtent.getWidth()/b.w,b=this.minExtent.getHeight()/b.h,c=Math.max(c,b));"number"!==typeof d&&("number"!==typeof c&&null!=this.maxExtent)&&(d=this.map.getTileSize(),d=Math.max(this.maxExtent.getWidth()/d.w,this.maxExtent.getHeight()/d.h));b=a.maxZoomLevel;
-a=a.numZoomLevels;"number"===typeof c&&"number"===typeof d&&void 0===a?a=Math.floor(Math.log(d/c)/Math.log(2))+1:void 0===a&&null!=b&&(a=b+1);if(!("number"!==typeof a||0>=a||"number"!==typeof d&&"number"!==typeof c)){b=Array(a);var e=2;"number"==typeof c&&"number"==typeof d&&(e=Math.pow(d/c,1/(a-1)));var f;if("number"===typeof d)for(f=0;f<a;f++)b[f]=d/Math.pow(e,f);else for(f=0;f<a;f++)b[a-1-f]=c*Math.pow(e,f);return b}},getResolution:function(){var a=this.map.getZoom();return this.getResolutionForZoom(a)},
-getExtent:function(){return this.map.calculateBounds()},getZoomForExtent:function(a,b){var c=this.map.getSize(),c=Math.max(a.getWidth()/c.w,a.getHeight()/c.h);return this.getZoomForResolution(c,b)},getDataExtent:function(){},getResolutionForZoom:function(a){a=Math.max(0,Math.min(a,this.resolutions.length-1));if(this.map.fractionalZoom){var b=Math.floor(a),c=Math.ceil(a);a=this.resolutions[b]-(a-b)*(this.resolutions[b]-this.resolutions[c])}else a=this.resolutions[Math.round(a)];return a},getZoomForResolution:function(a,
-b){var c,d;if(this.map.fractionalZoom){var e=0,f=this.resolutions[e],g=this.resolutions[this.resolutions.length-1],h;c=0;for(d=this.resolutions.length;c<d;++c)if(h=this.resolutions[c],h>=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=0<c?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;c=0;for(d=this.resolutions.length;c<d;c++)if(b){e=Math.abs(this.resolutions[c]-a);if(e>f)break;f=e}else if(this.resolutions[c]<a)break;c=Math.max(0,c-1)}return c},getLonLatFromViewPortPx:function(a){var b=null,c=this.map;if(null!=
-a&&c.minPx){var b=c.getResolution(),d=c.getMaxExtent({restricted:!0}),b=new OpenLayers.LonLat((a.x-c.minPx.x)*b+d.left,(c.minPx.y-a.y)*b+d.top);this.wrapDateLine&&(b=b.wrapDateLine(this.maxExtent))}return b},getViewPortPxFromLonLat:function(a,b){var c=null;null!=a&&(b=b||this.map.getResolution(),c=this.map.calculateBounds(null,b),c=new OpenLayers.Pixel(1/b*(a.lon-c.left),1/b*(c.top-a.lat)));return c},setOpacity:function(a){if(a!=this.opacity){this.opacity=a;for(var b=this.div.childNodes,c=0,d=b.length;c<
-d;++c){var e=b[c].firstChild||b[c],f=b[c].lastChild;f&&"iframe"===f.nodeName.toLowerCase()&&(e=f.parentNode);OpenLayers.Util.modifyDOMElement(e,null,null,null,null,null,null,a)}null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"})}},getZIndex:function(){return this.div.style.zIndex},setZIndex:function(a){this.div.style.zIndex=a},adjustBounds:function(a){if(this.gutter){var b=this.gutter*this.map.getResolution();a=new OpenLayers.Bounds(a.left-b,a.bottom-b,a.right+
-b,a.top+b)}this.wrapDateLine&&(b={rightTolerance:this.getResolution(),leftTolerance:this.getResolution()},a=a.wrapDateLine(this.maxExtent,b));return a},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Layer.SphericalMercator={getExtent:function(){var a=null;return a=this.sphericalMercator?this.map.calculateBounds():OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this)},getLonLatFromViewPortPx:function(a){return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this,arguments)},getViewPortPxFromLonLat:function(a){return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this,arguments)},initMercatorParameters:function(){this.RESOLUTIONS=[];for(var a=0;a<=this.MAX_ZOOM_LEVEL;++a)this.RESOLUTIONS[a]=
-156543.03390625/Math.pow(2,a);this.units="m";this.projection=this.projection||"EPSG:900913"},forwardMercator:function(){var a=new OpenLayers.Projection("EPSG:4326"),b=new OpenLayers.Projection("EPSG:900913");return function(c,d){var e=OpenLayers.Projection.transform({x:c,y:d},a,b);return new OpenLayers.LonLat(e.x,e.y)}}(),inverseMercator:function(){var a=new OpenLayers.Projection("EPSG:4326"),b=new OpenLayers.Projection("EPSG:900913");return function(c,d){var e=OpenLayers.Projection.transform({x:c,
-y:d},b,a);return new OpenLayers.LonLat(e.x,e.y)}}()};OpenLayers.Layer.EventPane=OpenLayers.Class(OpenLayers.Layer,{smoothDragPan:!0,isBaseLayer:!0,isFixed:!0,pane:null,mapObject:null,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);null==this.pane&&(this.pane=OpenLayers.Util.createDiv(this.div.id+"_EventPane"))},destroy:function(){this.pane=this.mapObject=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Layer.prototype.setMap.apply(this,arguments);this.pane.style.zIndex=
-parseInt(this.div.style.zIndex)+1;this.pane.style.display=this.div.style.display;this.pane.style.width="100%";this.pane.style.height="100%";"msie"==OpenLayers.BROWSER_NAME&&(this.pane.style.background="url("+OpenLayers.Util.getImageLocation("blank.gif")+")");this.isFixed?this.map.viewPortDiv.appendChild(this.pane):this.map.layerContainerDiv.appendChild(this.pane);this.loadMapObject();null==this.mapObject&&this.loadWarningMessage()},removeMap:function(a){this.pane&&this.pane.parentNode&&this.pane.parentNode.removeChild(this.pane);
-OpenLayers.Layer.prototype.removeMap.apply(this,arguments)},loadWarningMessage:function(){this.div.style.backgroundColor="darkblue";var a=this.map.getSize(),b=Math.min(a.w,300),c=Math.min(a.h,200),b=new OpenLayers.Size(b,c),a=(new OpenLayers.Pixel(a.w/2,a.h/2)).add(-b.w/2,-b.h/2),a=OpenLayers.Util.createDiv(this.name+"_warning",a,b,null,null,null,"auto");a.style.padding="7px";a.style.backgroundColor="yellow";a.innerHTML=this.getWarningHTML();this.div.appendChild(a)},getWarningHTML:function(){return""},
-display:function(a){OpenLayers.Layer.prototype.display.apply(this,arguments);this.pane.style.display=this.div.style.display},setZIndex:function(a){OpenLayers.Layer.prototype.setZIndex.apply(this,arguments);this.pane.style.zIndex=parseInt(this.div.style.zIndex)+1},moveByPx:function(a,b){OpenLayers.Layer.prototype.moveByPx.apply(this,arguments);this.dragPanMapObject?this.dragPanMapObject(a,-b):this.moveTo(this.map.getCachedCenter())},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,
-arguments);if(null!=this.mapObject){var d=this.map.getCenter(),e=this.map.getZoom();if(null!=d){var f=this.getMapObjectCenter(),f=this.getOLLonLatFromMapObjectLonLat(f),g=this.getMapObjectZoom(),g=this.getOLZoomFromMapObjectZoom(g);d.equals(f)&&e==g||(!b&&f&&this.dragPanMapObject&&this.smoothDragPan?(e=this.map.getViewPortPxFromLonLat(f),d=this.map.getViewPortPxFromLonLat(d),this.dragPanMapObject(d.x-e.x,e.y-d.y)):(d=this.getMapObjectLonLatFromOLLonLat(d),e=this.getMapObjectZoomFromOLZoom(e),this.setMapObjectCenter(d,
-e,c)))}}},getLonLatFromViewPortPx:function(a){var b=null;null!=this.mapObject&&null!=this.getMapObjectCenter()&&(a=this.getMapObjectPixelFromOLPixel(a),a=this.getMapObjectLonLatFromMapObjectPixel(a),b=this.getOLLonLatFromMapObjectLonLat(a));return b},getViewPortPxFromLonLat:function(a){var b=null;null!=this.mapObject&&null!=this.getMapObjectCenter()&&(a=this.getMapObjectLonLatFromOLLonLat(a),a=this.getMapObjectPixelFromMapObjectLonLat(a),b=this.getOLPixelFromMapObjectPixel(a));return b},getOLLonLatFromMapObjectLonLat:function(a){var b=
-null;null!=a&&(b=this.getLongitudeFromMapObjectLonLat(a),a=this.getLatitudeFromMapObjectLonLat(a),b=new OpenLayers.LonLat(b,a));return b},getMapObjectLonLatFromOLLonLat:function(a){var b=null;null!=a&&(b=this.getMapObjectLonLatFromLonLat(a.lon,a.lat));return b},getOLPixelFromMapObjectPixel:function(a){var b=null;null!=a&&(b=this.getXFromMapObjectPixel(a),a=this.getYFromMapObjectPixel(a),b=new OpenLayers.Pixel(b,a));return b},getMapObjectPixelFromOLPixel:function(a){var b=null;null!=a&&(b=this.getMapObjectPixelFromXY(a.x,
-a.y));return b},CLASS_NAME:"OpenLayers.Layer.EventPane"});OpenLayers.Layer.FixedZoomLevels=OpenLayers.Class({initialize:function(){},initResolutions:function(){for(var a=["minZoomLevel","maxZoomLevel","numZoomLevels"],b=0,c=a.length;b<c;b++){var d=a[b];this[d]=null!=this.options[d]?this.options[d]:this.map[d]}if(null==this.minZoomLevel||this.minZoomLevel<this.MIN_ZOOM_LEVEL)this.minZoomLevel=this.MIN_ZOOM_LEVEL;a=this.MAX_ZOOM_LEVEL-this.minZoomLevel+1;b=null==this.options.numZoomLevels&&null!=this.options.maxZoomLevel||null==this.numZoomLevels&&null!=this.maxZoomLevel?
-this.maxZoomLevel-this.minZoomLevel+1:this.numZoomLevels;this.numZoomLevels=null!=b?Math.min(b,a):a;this.maxZoomLevel=this.minZoomLevel+this.numZoomLevels-1;if(null!=this.RESOLUTIONS){a=0;this.resolutions=[];for(b=this.minZoomLevel;b<=this.maxZoomLevel;b++)this.resolutions[a++]=this.RESOLUTIONS[b];this.maxResolution=this.resolutions[0];this.minResolution=this.resolutions[this.resolutions.length-1]}},getResolution:function(){if(null!=this.resolutions)return OpenLayers.Layer.prototype.getResolution.apply(this,
-arguments);var a=null,b=this.map.getSize(),c=this.getExtent();null!=b&&null!=c&&(a=Math.max(c.getWidth()/b.w,c.getHeight()/b.h));return a},getExtent:function(){var a=this.map.getSize(),b=this.getLonLatFromViewPortPx({x:0,y:0}),a=this.getLonLatFromViewPortPx({x:a.w,y:a.h});return null!=b&&null!=a?new OpenLayers.Bounds(b.lon,a.lat,a.lon,b.lat):null},getZoomForResolution:function(a){if(null!=this.resolutions)return OpenLayers.Layer.prototype.getZoomForResolution.apply(this,arguments);var b=OpenLayers.Layer.prototype.getExtent.apply(this,
-[]);return this.getZoomForExtent(b)},getOLZoomFromMapObjectZoom:function(a){var b=null;null!=a&&(b=a-this.minZoomLevel,this.map.baseLayer!==this&&(b=this.map.baseLayer.getZoomForResolution(this.getResolutionForZoom(b))));return b},getMapObjectZoomFromOLZoom:function(a){var b=null;null!=a&&(b=a+this.minZoomLevel,this.map.baseLayer!==this&&(b=this.getZoomForResolution(this.map.baseLayer.getResolutionForZoom(b))));return b},CLASS_NAME:"OpenLayers.Layer.FixedZoomLevels"});OpenLayers.Layer.Google=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:0,MAX_ZOOM_LEVEL:21,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,6.866455078125E-4,3.4332275390625E-4,1.71661376953125E-4,8.58306884765625E-5,4.291534423828125E-5,2.145767211914062E-5,1.072883605957031E-5,5.36441802978515E-6,2.68220901489257E-6,1.341104507446289E-6,6.705522537231445E-7],
-type:null,wrapDateLine:!0,sphericalMercator:!1,version:null,initialize:function(a,b){b=b||{};b.version||(b.version="function"===typeof GMap2?"2":"3");var c=OpenLayers.Layer.Google["v"+b.version.replace(/\./g,"_")];if(c)OpenLayers.Util.applyDefaults(b,c);else throw"Unsupported Google Maps API version: "+b.version;OpenLayers.Util.applyDefaults(b,c.DEFAULTS);b.maxExtent&&(b.maxExtent=b.maxExtent.clone());OpenLayers.Layer.EventPane.prototype.initialize.apply(this,[a,b]);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
-[a,b]);this.sphericalMercator&&(OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator),this.initMercatorParameters())},clone:function(){return new OpenLayers.Layer.Google(this.name,this.getOptions())},setVisibility:function(a){var b=null==this.opacity?1:this.opacity;OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this,arguments);this.setOpacity(b)},display:function(a){this._dragging||this.setGMapVisibility(a);OpenLayers.Layer.EventPane.prototype.display.apply(this,arguments)},moveTo:function(a,
-b,c){this._dragging=c;OpenLayers.Layer.EventPane.prototype.moveTo.apply(this,arguments);delete this._dragging},setOpacity:function(a){a!==this.opacity&&(null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"}),this.opacity=a);if(this.getVisibility()){var b=this.getMapContainer();OpenLayers.Util.modifyDOMElement(b,null,null,null,null,null,null,a)}},destroy:function(){if(this.map){this.setGMapVisibility(!1);var a=OpenLayers.Layer.Google.cache[this.map.id];a&&1>=a.count&&
-this.removeGMapElements()}OpenLayers.Layer.EventPane.prototype.destroy.apply(this,arguments)},removeGMapElements:function(){var a=OpenLayers.Layer.Google.cache[this.map.id];if(a){var b=this.mapObject&&this.getMapContainer();b&&b.parentNode&&b.parentNode.removeChild(b);(b=a.termsOfUse)&&b.parentNode&&b.parentNode.removeChild(b);(a=a.poweredBy)&&a.parentNode&&a.parentNode.removeChild(a);this.mapObject&&(window.google&&google.maps&&google.maps.event&&google.maps.event.clearListeners)&&google.maps.event.clearListeners(this.mapObject,
-"tilesloaded")}},removeMap:function(a){this.visibility&&this.mapObject&&this.setGMapVisibility(!1);var b=OpenLayers.Layer.Google.cache[a.id];b&&(1>=b.count?(this.removeGMapElements(),delete OpenLayers.Layer.Google.cache[a.id]):--b.count);delete this.termsOfUse;delete this.poweredBy;delete this.mapObject;delete this.dragObject;OpenLayers.Layer.EventPane.prototype.removeMap.apply(this,arguments)},getOLBoundsFromMapObjectBounds:function(a){var b=null;null!=a&&(b=a.getSouthWest(),a=a.getNorthEast(),this.sphericalMercator?
-(b=this.forwardMercator(b.lng(),b.lat()),a=this.forwardMercator(a.lng(),a.lat())):(b=new OpenLayers.LonLat(b.lng(),b.lat()),a=new OpenLayers.LonLat(a.lng(),a.lat())),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat));return b},getWarningHTML:function(){return OpenLayers.i18n("googleWarning")},getMapObjectCenter:function(){return this.mapObject.getCenter()},getMapObjectZoom:function(){return this.mapObject.getZoom()},getLongitudeFromMapObjectLonLat:function(a){return this.sphericalMercator?this.forwardMercator(a.lng(),
-a.lat()).lon:a.lng()},getLatitudeFromMapObjectLonLat:function(a){return this.sphericalMercator?this.forwardMercator(a.lng(),a.lat()).lat:a.lat()},getXFromMapObjectPixel:function(a){return a.x},getYFromMapObjectPixel:function(a){return a.y},CLASS_NAME:"OpenLayers.Layer.Google"});OpenLayers.Layer.Google.cache={};
-OpenLayers.Layer.Google.v2={termsOfUse:null,poweredBy:null,dragObject:null,loadMapObject:function(){this.type||(this.type=G_NORMAL_MAP);var a,b,c,d=OpenLayers.Layer.Google.cache[this.map.id];if(d)a=d.mapObject,b=d.termsOfUse,c=d.poweredBy,++d.count;else{var d=this.map.viewPortDiv,e=document.createElement("div");e.id=this.map.id+"_GMap2Container";e.style.position="absolute";e.style.width="100%";e.style.height="100%";d.appendChild(e);try{a=new GMap2(e),b=e.lastChild,d.appendChild(b),b.style.zIndex=
-"1100",b.style.right="",b.style.bottom="",b.className="olLayerGoogleCopyright",c=e.lastChild,d.appendChild(c),c.style.zIndex="1100",c.style.right="",c.style.bottom="",c.className="olLayerGooglePoweredBy gmnoprint"}catch(f){throw f;}OpenLayers.Layer.Google.cache[this.map.id]={mapObject:a,termsOfUse:b,poweredBy:c,count:1}}this.mapObject=a;this.termsOfUse=b;this.poweredBy=c;-1===OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),this.type)&&this.mapObject.addMapType(this.type);"function"==typeof a.getDragObject?
-this.dragObject=a.getDragObject():this.dragPanMapObject=null;!1===this.isBaseLayer&&this.setGMapVisibility("none"!==this.div.style.display)},onMapResize:function(){if(this.visibility&&this.mapObject.isLoaded())this.mapObject.checkResize();else{if(!this._resized)var a=this,b=GEvent.addListener(this.mapObject,"load",function(){GEvent.removeListener(b);delete a._resized;a.mapObject.checkResize();a.moveTo(a.map.getCenter(),a.map.getZoom())});this._resized=!0}},setGMapVisibility:function(a){var b=OpenLayers.Layer.Google.cache[this.map.id];
-if(b){var c=this.mapObject.getContainer();!0===a?(this.mapObject.setMapType(this.type),c.style.display="",this.termsOfUse.style.left="",this.termsOfUse.style.display="",this.poweredBy.style.display="",b.displayed=this.id):(b.displayed===this.id&&delete b.displayed,b.displayed||(c.style.display="none",this.termsOfUse.style.display="none",this.termsOfUse.style.left="-9999px",this.poweredBy.style.display="none"))}},getMapContainer:function(){return this.mapObject.getContainer()},getMapObjectBoundsFromOLBounds:function(a){var b=
-null;null!=a&&(b=this.sphericalMercator?this.inverseMercator(a.bottom,a.left):new OpenLayers.LonLat(a.bottom,a.left),a=this.sphericalMercator?this.inverseMercator(a.top,a.right):new OpenLayers.LonLat(a.top,a.right),b=new GLatLngBounds(new GLatLng(b.lat,b.lon),new GLatLng(a.lat,a.lon)));return b},setMapObjectCenter:function(a,b){this.mapObject.setCenter(a,b)},dragPanMapObject:function(a,b){this.dragObject.moveBy(new GSize(-a,b))},getMapObjectLonLatFromMapObjectPixel:function(a){return this.mapObject.fromContainerPixelToLatLng(a)},
-getMapObjectPixelFromMapObjectLonLat:function(a){return this.mapObject.fromLatLngToContainerPixel(a)},getMapObjectZoomFromMapObjectBounds:function(a){return this.mapObject.getBoundsZoomLevel(a)},getMapObjectLonLatFromLonLat:function(a,b){var c;this.sphericalMercator?(c=this.inverseMercator(a,b),c=new GLatLng(c.lat,c.lon)):c=new GLatLng(b,a);return c},getMapObjectPixelFromXY:function(a,b){return new GPoint(a,b)}};OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(a){window.ActiveXObject&&(this.xmldom=new ActiveXObject("Microsoft.XMLDOM"));OpenLayers.Format.prototype.initialize.apply(this,[a]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var b in this.namespaces)this.namespaceAlias[this.namespaces[b]]=b},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,
-arguments)},setNamespace:function(a,b){this.namespaces[a]=b;this.namespaceAlias[b]=a},read:function(a){var b=a.indexOf("<");0<b&&(a=a.substring(b));b=OpenLayers.Util.Try(OpenLayers.Function.bind(function(){var b;b=window.ActiveXObject&&!this.xmldom?new ActiveXObject("Microsoft.XMLDOM"):this.xmldom;b.loadXML(a);return b},this),function(){return(new DOMParser).parseFromString(a,"text/xml")},function(){var b=new XMLHttpRequest;b.open("GET","data:text/xml;charset=utf-8,"+encodeURIComponent(a),!1);b.overrideMimeType&&
-b.overrideMimeType("text/xml");b.send(null);return b.responseXML});this.keepData&&(this.data=b);return b},write:function(a){if(this.xmldom)a=a.xml;else{var b=new XMLSerializer;if(1==a.nodeType){var c=document.implementation.createDocument("","",null);c.importNode&&(a=c.importNode(a,!0));c.appendChild(a);a=b.serializeToString(c)}else a=b.serializeToString(a)}return a},createElementNS:function(a,b){return this.xmldom?"string"==typeof a?this.xmldom.createNode(1,b,a):this.xmldom.createNode(1,b,""):document.createElementNS(a,
-b)},createDocumentFragment:function(){return this.xmldom?this.xmldom.createDocumentFragment():document.createDocumentFragment()},createTextNode:function(a){"string"!==typeof a&&(a=String(a));return this.xmldom?this.xmldom.createTextNode(a):document.createTextNode(a)},getElementsByTagNameNS:function(a,b,c){var d=[];if(a.getElementsByTagNameNS)d=a.getElementsByTagNameNS(b,c);else{a=a.getElementsByTagName("*");for(var e,f,g=0,h=a.length;g<h;++g)if(e=a[g],f=e.prefix?e.prefix+":"+c:c,"*"==c||f==e.nodeName)"*"!=
-b&&b!=e.namespaceURI||d.push(e)}return d},getAttributeNodeNS:function(a,b,c){var d=null;if(a.getAttributeNodeNS)d=a.getAttributeNodeNS(b,c);else{a=a.attributes;for(var e,f,g=0,h=a.length;g<h;++g)if(e=a[g],e.namespaceURI==b&&(f=e.prefix?e.prefix+":"+c:c,f==e.nodeName)){d=e;break}}return d},getAttributeNS:function(a,b,c){var d="";if(a.getAttributeNS)d=a.getAttributeNS(b,c)||"";else if(a=this.getAttributeNodeNS(a,b,c))d=a.nodeValue;return d},getChildValue:function(a,b){var c=b||"";if(a)for(var d=a.firstChild;d;d=
-d.nextSibling)switch(d.nodeType){case 3:case 4:c+=d.nodeValue}return c},isSimpleContent:function(a){var b=!0;for(a=a.firstChild;a;a=a.nextSibling)if(1===a.nodeType){b=!1;break}return b},contentType:function(a){var b=!1,c=!1,d=OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;for(a=a.firstChild;a;a=a.nextSibling){switch(a.nodeType){case 1:c=!0;break;case 8:break;default:b=!0}if(c&&b)break}if(c&&b)d=OpenLayers.Format.XML.CONTENT_TYPE.MIXED;else{if(c)return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;if(b)return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE}return d},
-hasAttributeNS:function(a,b,c){var d=!1;return d=a.hasAttributeNS?a.hasAttributeNS(b,c):!!this.getAttributeNodeNS(a,b,c)},setAttributeNS:function(a,b,c,d){if(a.setAttributeNS)a.setAttributeNS(b,c,d);else if(this.xmldom)b?(b=a.ownerDocument.createNode(2,c,b),b.nodeValue=d,a.setAttributeNode(b)):a.setAttribute(c,d);else throw"setAttributeNS not implemented";},createElementNSPlus:function(a,b){b=b||{};var c=b.uri||this.namespaces[b.prefix];c||(c=a.indexOf(":"),c=this.namespaces[a.substring(0,c)]);c||
-(c=this.namespaces[this.defaultPrefix]);c=this.createElementNS(c,a);b.attributes&&this.setAttributes(c,b.attributes);var d=b.value;null!=d&&c.appendChild(this.createTextNode(d));return c},setAttributes:function(a,b){var c,d,e;for(e in b)null!=b[e]&&b[e].toString&&(c=b[e].toString(),d=this.namespaces[e.substring(0,e.indexOf(":"))]||null,this.setAttributeNS(a,d,e,c))},readNode:function(a,b){b||(b={});var c=this.readers[a.namespaceURI?this.namespaceAlias[a.namespaceURI]:this.defaultPrefix];if(c){var d=
-a.localName||a.nodeName.split(":").pop();(c=c[d]||c["*"])&&c.apply(this,[a,b])}return b},readChildNodes:function(a,b){b||(b={});for(var c=a.childNodes,d,e=0,f=c.length;e<f;++e)d=c[e],1==d.nodeType&&this.readNode(d,b);return b},writeNode:function(a,b,c){var d,e=a.indexOf(":");0<e?(d=a.substring(0,e),a=a.substring(e+1)):d=c?this.namespaceAlias[c.namespaceURI]:this.defaultPrefix;b=this.writers[d][a].apply(this,[b]);c&&c.appendChild(b);return b},getChildEl:function(a,b,c){return a&&this.getThisOrNextEl(a.firstChild,
-b,c)},getNextEl:function(a,b,c){return a&&this.getThisOrNextEl(a.nextSibling,b,c)},getThisOrNextEl:function(a,b,c){a:for(;a;a=a.nextSibling)switch(a.nodeType){case 1:if(!(b&&b!==(a.localName||a.nodeName.split(":").pop())||c&&c!==a.namespaceURI))break a;a=null;break a;case 3:if(/^\s*$/.test(a.nodeValue))break;case 4:case 6:case 12:case 10:case 11:a=null;break a}return a||null},lookupNamespaceURI:function(a,b){var c=null;if(a)if(a.lookupNamespaceURI)c=a.lookupNamespaceURI(b);else a:switch(a.nodeType){case 1:if(null!==
-a.namespaceURI&&a.prefix===b){c=a.namespaceURI;break a}if(c=a.attributes.length)for(var d,e=0;e<c;++e)if(d=a.attributes[e],"xmlns"===d.prefix&&d.name==="xmlns:"+b){c=d.value||null;break a}else if("xmlns"===d.name&&null===b){c=d.value||null;break a}c=this.lookupNamespaceURI(a.parentNode,b);break a;case 2:c=this.lookupNamespaceURI(a.ownerElement,b);break a;case 9:c=this.lookupNamespaceURI(a.documentElement,b);break a;case 6:case 12:case 10:case 11:break a;default:c=this.lookupNamespaceURI(a.parentNode,
-b)}return c},getXMLDoc:function(){OpenLayers.Format.XML.document||this.xmldom||(document.implementation&&document.implementation.createDocument?OpenLayers.Format.XML.document=document.implementation.createDocument("","",null):!this.xmldom&&window.ActiveXObject&&(this.xmldom=new ActiveXObject("Microsoft.XMLDOM")));return OpenLayers.Format.XML.document||this.xmldom},CLASS_NAME:"OpenLayers.Format.XML"});OpenLayers.Format.XML.CONTENT_TYPE={EMPTY:0,SIMPLE:1,COMPLEX:2,MIXED:3};
-OpenLayers.Format.XML.lookupNamespaceURI=OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI,OpenLayers.Format.XML.prototype);OpenLayers.Format.XML.document=null;OpenLayers.Format.WFST=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.WFST.DEFAULTS);var b=OpenLayers.Format.WFST["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFST version: "+a.version;return new b(a)};OpenLayers.Format.WFST.DEFAULTS={version:"1.0.0"};OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:null,popup:null,initialize:function(a,b,c){this.layer=a;this.lonlat=b;this.data=null!=c?c:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){null!=this.layer&&null!=this.layer.map&&null!=this.popup&&this.layer.map.removePopup(this.popup);null!=this.layer&&null!=this.marker&&this.layer.removeMarker(this.marker);this.data=this.lonlat=this.id=this.layer=null;null!=this.marker&&
-(this.destroyMarker(this.marker),this.marker=null);null!=this.popup&&(this.destroyPopup(this.popup),this.popup=null)},onScreen:function(){var a=!1;null!=this.layer&&null!=this.layer.map&&(a=this.layer.map.getExtent().containsLonLat(this.lonlat));return a},createMarker:function(){null!=this.lonlat&&(this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon));return this.marker},destroyMarker:function(){this.marker.destroy()},createPopup:function(a){null!=this.lonlat&&(this.popup||(this.popup=new (this.popupClass?
-this.popupClass:OpenLayers.Popup.Anchored)(this.id+"_popup",this.lonlat,this.data.popupSize,this.data.popupContentHTML,this.marker?this.marker.icon:null,a)),null!=this.data.overflow&&(this.popup.contentDiv.style.overflow=this.data.overflow),this.popup.feature=this);return this.popup},destroyPopup:function(){this.popup&&(this.popup.feature=null,this.popup.destroy(),this.popup=null)},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.State={UNKNOWN:"Unknown",INSERT:"Insert",UPDATE:"Update",DELETE:"Delete"};
-OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",modified:null,initialize:function(a,b,c){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,b]);this.lonlat=null;this.geometry=a?a:null;this.state=null;this.attributes={};b&&(this.attributes=OpenLayers.Util.extend(this.attributes,b));this.style=c?c:null},destroy:function(){this.layer&&(this.layer.removeFeatures(this),this.layer=
-null);this.modified=this.geometry=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments)},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style)},onScreen:function(a){var b=!1;this.layer&&this.layer.map&&(b=this.layer.map.getExtent(),a?(a=this.geometry.getBounds(),b=b.intersectsBounds(a)):b=b.toGeometry().intersects(this.geometry));return b},getVisibility:function(){return!(this.style&&"none"==this.style.display||!this.layer||
-this.layer&&this.layer.styleMap&&"none"==this.layer.styleMap.createSymbolizer(this,this.renderIntent).display||this.layer&&!this.layer.getVisibility())},createMarker:function(){return null},destroyMarker:function(){},createPopup:function(){return null},atPoint:function(a,b,c){var d=!1;this.geometry&&(d=this.geometry.atPoint(a,b,c));return d},destroyPopup:function(){},move:function(a){if(this.layer&&this.geometry.move){a="OpenLayers.LonLat"==a.CLASS_NAME?this.layer.getViewPortPxFromLonLat(a):a;var b=
-this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()),c=this.layer.map.getResolution();this.geometry.move(c*(a.x-b.x),c*(b.y-a.y));this.layer.drawFeature(this);return b}},toState:function(a){if(a==OpenLayers.State.UPDATE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=a}else if(a==OpenLayers.State.INSERT)switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=a}else if(a==OpenLayers.State.DELETE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state=
-a}else a==OpenLayers.State.UNKNOWN&&(this.state=a)},CLASS_NAME:"OpenLayers.Feature.Vector"});
-OpenLayers.Feature.Vector.style={"default":{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},select:{fillColor:"blue",fillOpacity:0.4,
-hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},temporary:{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1,
-strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},"delete":{display:"none"}};OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:!1,propertyStyles:null,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.rules=[];b&&b.rules&&this.addRules(b.rules);this.setDefaultStyle(a||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;a<b;a++)this.rules[a].destroy(),
-this.rules[a]=null;this.defaultStyle=this.rules=null},createSymbolizer:function(a){for(var b=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),a),c=this.rules,d,e=[],f=!1,g=0,h=c.length;g<h;g++)d=c[g],d.evaluate(a)&&(d instanceof OpenLayers.Rule&&d.elseFilter?e.push(d):(f=!0,this.applySymbolizer(d,b,a)));if(!1==f&&0<e.length)for(f=!0,g=0,h=e.length;g<h;g++)this.applySymbolizer(e[g],b,a);0<c.length&&!1==f&&(b.display="none");null!=b.label&&"string"!==typeof b.label&&
-(b.label=String(b.label));return b},applySymbolizer:function(a,b,c){var d=c.geometry?this.getSymbolizerPrefix(c.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];a=a.symbolizer[d]||a.symbolizer;!0===this.defaultsPerSymbolizer&&(d=this.defaultStyle,OpenLayers.Util.applyDefaults(a,{pointRadius:d.pointRadius}),!0!==a.stroke&&!0!==a.graphic||OpenLayers.Util.applyDefaults(a,{strokeWidth:d.strokeWidth,strokeColor:d.strokeColor,strokeOpacity:d.strokeOpacity,strokeDashstyle:d.strokeDashstyle,strokeLinecap:d.strokeLinecap}),
-!0!==a.fill&&!0!==a.graphic||OpenLayers.Util.applyDefaults(a,{fillColor:d.fillColor,fillOpacity:d.fillOpacity}),!0===a.graphic&&OpenLayers.Util.applyDefaults(a,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset}));
-return this.createLiterals(OpenLayers.Util.extend(b,a),c)},createLiterals:function(a,b){var c=OpenLayers.Util.extend({},b.attributes||b.data);OpenLayers.Util.extend(c,this.context);for(var d in this.propertyStyles)a[d]=OpenLayers.Style.createLiteral(a[d],c,b,d);return a},findPropertyStyles:function(){var a={};this.addPropertyStyles(a,this.defaultStyle);for(var b=this.rules,c,d,e=0,f=b.length;e<f;e++){c=b[e].symbolizer;for(var g in c)if(d=c[g],"object"==typeof d)this.addPropertyStyles(a,d);else{this.addPropertyStyles(a,
-c);break}}return a},addPropertyStyles:function(a,b){var c,d;for(d in b)c=b[d],"string"==typeof c&&c.match(/\$\{\w+\}/)&&(a[d]=!0);return a},addRules:function(a){Array.prototype.push.apply(this.rules,a);this.propertyStyles=this.findPropertyStyles()},setDefaultStyle:function(a){this.defaultStyle=a;this.propertyStyles=this.findPropertyStyles()},getSymbolizerPrefix:function(a){for(var b=OpenLayers.Style.SYMBOLIZER_PREFIXES,c=0,d=b.length;c<d;c++)if(-1!=a.CLASS_NAME.indexOf(b[c]))return b[c]},clone:function(){var a=
-OpenLayers.Util.extend({},this);if(this.rules){a.rules=[];for(var b=0,c=this.rules.length;b<c;++b)a.rules.push(this.rules[b].clone())}a.context=this.context&&OpenLayers.Util.extend({},this.context);b=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(b,a)},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(a,b,c,d){"string"==typeof a&&-1!=a.indexOf("${")&&(a=OpenLayers.String.format(a,b,[c,d]),a=isNaN(a)||!a?a:parseFloat(a));return a};
-OpenLayers.Style.SYMBOLIZER_PREFIXES=["Point","Line","Polygon","Text","Raster"];OpenLayers.Filter=OpenLayers.Class({initialize:function(a){OpenLayers.Util.extend(this,a)},destroy:function(){},evaluate:function(a){return!0},clone:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.CQL?OpenLayers.Format.CQL.prototype.write(this):Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,evaluate:function(a){var b=!1;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(a.geometry){var c=this.value;"OpenLayers.Bounds"==this.value.CLASS_NAME&&(c=this.value.toGeometry());a.geometry.intersects(c)&&(b=!0)}break;default:throw Error("evaluate is not implemented for this filter type.");}return b},clone:function(){var a=
-OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(a)},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Filter.FeatureId=OpenLayers.Class(OpenLayers.Filter,{fids:null,type:"FID",initialize:function(a){this.fids=[];OpenLayers.Filter.prototype.initialize.apply(this,[a])},evaluate:function(a){for(var b=0,c=this.fids.length;b<c;b++)if((a.fid||a.id)==this.fids[b])return!0;return!1},clone:function(){var a=new OpenLayers.Filter.FeatureId;OpenLayers.Util.extend(a,this);a.fids=this.fids.slice();return a},CLASS_NAME:"OpenLayers.Filter.FeatureId"});OpenLayers.Format.WFST.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs",gml:"http://www.opengis.net/gml",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows"},defaultPrefix:"wfs",version:null,schemaLocations:null,srsName:null,extractAttributes:!0,xy:!0,stateName:null,initialize:function(a){this.stateName={};this.stateName[OpenLayers.State.INSERT]="wfs:Insert";this.stateName[OpenLayers.State.UPDATE]=
-"wfs:Update";this.stateName[OpenLayers.State.DELETE]="wfs:Delete";OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},getSrsName:function(a,b){var c=b&&b.srsName;c||(c=a&&a.layer?a.layer.projection.getCode():this.srsName);return c},read:function(a,b){b=b||{};OpenLayers.Util.applyDefaults(b,{output:"features"});"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var c={};a&&this.readNode(a,c,!0);c.features&&"features"===b.output&&
-(c=c.features);return c},readers:{wfs:{FeatureCollection:function(a,b){b.features=[];this.readChildNodes(a,b)}}},write:function(a,b){var c=this.writeNode("wfs:Transaction",{features:a,options:b}),d=this.schemaLocationAttr();d&&this.setAttributeNS(c,this.namespaces.xsi,"xsi:schemaLocation",d);return OpenLayers.Format.XML.prototype.write.apply(this,[c])},writers:{wfs:{GetFeature:function(a){var b=this.createElementNSPlus("wfs:GetFeature",{attributes:{service:"WFS",version:this.version,handle:a&&a.handle,
-outputFormat:a&&a.outputFormat,maxFeatures:a&&a.maxFeatures,"xsi:schemaLocation":this.schemaLocationAttr(a)}});if("string"==typeof this.featureType)this.writeNode("Query",a,b);else for(var c=0,d=this.featureType.length;c<d;c++)a.featureType=this.featureType[c],this.writeNode("Query",a,b);return b},Transaction:function(a){a=a||{};var b=a.options||{},c=this.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version,handle:b.handle}}),d,e=a.features;if(e){!0===b.multi&&OpenLayers.Util.extend(this.geometryTypes,
-{"OpenLayers.Geometry.Point":"MultiPoint","OpenLayers.Geometry.LineString":!0===this.multiCurve?"MultiCurve":"MultiLineString","OpenLayers.Geometry.Polygon":!0===this.multiSurface?"MultiSurface":"MultiPolygon"});var f,g;a=0;for(d=e.length;a<d;++a)g=e[a],(f=this.stateName[g.state])&&this.writeNode(f,{feature:g,options:b},c);!0===b.multi&&this.setGeometryTypes()}if(b.nativeElements)for(a=0,d=b.nativeElements.length;a<d;++a)this.writeNode("wfs:Native",b.nativeElements[a],c);return c},Native:function(a){return this.createElementNSPlus("wfs:Native",
-{attributes:{vendorId:a.vendorId,safeToIgnore:a.safeToIgnore},value:a.value})},Insert:function(a){var b=a.feature;a=a.options;a=this.createElementNSPlus("wfs:Insert",{attributes:{handle:a&&a.handle}});this.srsName=this.getSrsName(b);this.writeNode("feature:_typeName",b,a);return a},Update:function(a){var b=a.feature;a=a.options;a=this.createElementNSPlus("wfs:Update",{attributes:{handle:a&&a.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+this.featureType}});this.featureNS&&a.setAttribute("xmlns:"+
-this.featurePrefix,this.featureNS);var c=b.modified;null===this.geometryName||c&&void 0===c.geometry||(this.srsName=this.getSrsName(b),this.writeNode("Property",{name:this.geometryName,value:b.geometry},a));for(var d in b.attributes)void 0===b.attributes[d]||c&&c.attributes&&(!c.attributes||void 0===c.attributes[d])||this.writeNode("Property",{name:d,value:b.attributes[d]},a);this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[b.fid]}),a);return a},Property:function(a){var b=this.createElementNSPlus("wfs:Property");
-this.writeNode("Name",a.name,b);null!==a.value&&this.writeNode("Value",a.value,b);return b},Name:function(a){return this.createElementNSPlus("wfs:Name",{value:a})},Value:function(a){var b;a instanceof OpenLayers.Geometry?(b=this.createElementNSPlus("wfs:Value"),a=this.writeNode("feature:_geometry",a).firstChild,b.appendChild(a)):b=this.createElementNSPlus("wfs:Value",{value:a});return b},Delete:function(a){var b=a.feature;a=a.options;a=this.createElementNSPlus("wfs:Delete",{attributes:{handle:a&&
-a.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+this.featureType}});this.featureNS&&a.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[b.fid]}),a);return a}}},schemaLocationAttr:function(a){a=OpenLayers.Util.extend({featurePrefix:this.featurePrefix,schema:this.schema},a);var b=OpenLayers.Util.extend({},this.schemaLocations);a.schema&&(b[a.featurePrefix]=a.schema);a=[];var c,d;for(d in b)(c=this.namespaces[d])&&
-a.push(c+" "+b[d]);return a.join(" ")||void 0},setFilterProperty:function(a){if(a.filters)for(var b=0,c=a.filters.length;b<c;++b)OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this,a.filters[b]);else a instanceof OpenLayers.Filter.Spatial&&!a.property&&(a.property=this.geometryName)},CLASS_NAME:"OpenLayers.Format.WFST.v1"});OpenLayers.Format.OGCExceptionReport=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},defaultPrefix:"ogc",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b={exceptionReport:null};a.documentElement&&(this.readChildNodes(a,b),null===b.exceptionReport&&(b=(new OpenLayers.Format.OWSCommon).read(a)));return b},readers:{ogc:{ServiceExceptionReport:function(a,
-b){b.exceptionReport={exceptions:[]};this.readChildNodes(a,b.exceptionReport)},ServiceException:function(a,b){var c={code:a.getAttribute("code"),locator:a.getAttribute("locator"),text:this.getChildValue(a)};b.exceptions.push(c)}}},CLASS_NAME:"OpenLayers.Format.OGCExceptionReport"});OpenLayers.Format.XML.VersionedOGC=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:null,version:null,profile:null,allowFallback:!1,name:null,stringifyOutput:!1,parser:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);a=this.CLASS_NAME;this.name=a.substring(a.lastIndexOf(".")+1)},getVersion:function(a,b){var c;a?(c=this.version,c||(c=a.getAttribute("version"),c||(c=this.defaultVersion))):c=b&&b.version||this.version||this.defaultVersion;return c},getParser:function(a){a=
-a||this.defaultVersion;var b=this.profile?"_"+this.profile:"";if(!this.parser||this.parser.VERSION!=a){var c=OpenLayers.Format[this.name]["v"+a.replace(/\./g,"_")+b];if(!c&&(""!==b&&this.allowFallback&&(b="",c=OpenLayers.Format[this.name]["v"+a.replace(/\./g,"_")]),!c))throw"Can't find a "+this.name+" parser for version "+a+b;this.parser=new c(this.options)}return this.parser},write:function(a,b){var c=this.getVersion(null,b);this.parser=this.getParser(c);c=this.parser.write(a,b);return!1===this.stringifyOutput?
-c:OpenLayers.Format.XML.prototype.write.apply(this,[c])},read:function(a,b){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var c=this.getVersion(a.documentElement);this.parser=this.getParser(c);var d=this.parser.read(a,b),e=this.parser.errorProperty||null;null!==e&&void 0===d[e]&&(e=new OpenLayers.Format.OGCExceptionReport,d.error=e.read(a));d.version=c;return d},CLASS_NAME:"OpenLayers.Format.XML.VersionedOGC"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(a){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[a])},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this)},evaluate:function(a){var b,c;switch(this.type){case OpenLayers.Filter.Logical.AND:b=0;for(c=this.filters.length;b<c;b++)if(!1==this.filters[b].evaluate(a))return!1;return!0;case OpenLayers.Filter.Logical.OR:b=0;for(c=this.filters.length;b<
-c;b++)if(!0==this.filters[b].evaluate(a))return!0;return!1;case OpenLayers.Filter.Logical.NOT:return!this.filters[0].evaluate(a)}},clone:function(){for(var a=[],b=0,c=this.filters.length;b<c;++b)a.push(this.filters[b].clone());return new OpenLayers.Filter.Logical({type:this.type,filters:a})},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:!0,lowerBoundary:null,upperBoundary:null,initialize:function(a){OpenLayers.Filter.prototype.initialize.apply(this,[a]);this.type===OpenLayers.Filter.Comparison.LIKE&&void 0===a.matchCase&&(this.matchCase=null)},evaluate:function(a){a instanceof OpenLayers.Feature.Vector&&(a=a.attributes);var b=!1;a=a[this.property];switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:b=this.value;
-b=this.matchCase||"string"!=typeof a||"string"!=typeof b?a==b:a.toUpperCase()==b.toUpperCase();break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:b=this.value;b=this.matchCase||"string"!=typeof a||"string"!=typeof b?a!=b:a.toUpperCase()!=b.toUpperCase();break;case OpenLayers.Filter.Comparison.LESS_THAN:b=a<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:b=a>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:b=a<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:b=
-a>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:b=a>=this.lowerBoundary&&a<=this.upperBoundary;break;case OpenLayers.Filter.Comparison.LIKE:b=RegExp(this.value,"gi").test(a);break;case OpenLayers.Filter.Comparison.IS_NULL:b=null===a}return b},value2regex:function(a,b,c){if("."==a)throw Error("'.' is an unsupported wildCard character for OpenLayers.Filter.Comparison");a=a?a:"*";b=b?b:".";this.value=this.value.replace(RegExp("\\"+(c?c:"!")+"(.|$)","g"),"\\$1");this.value=this.value.replace(RegExp("\\"+
-b,"g"),".");this.value=this.value.replace(RegExp("\\"+a,"g"),".*");this.value=this.value.replace(RegExp("\\\\.\\*","g"),"\\"+a);return this.value=this.value.replace(RegExp("\\\\\\.","g"),"\\"+b)},regex2value:function(){var a=this.value,a=a.replace(/!/g,"!!"),a=a.replace(/(\\)?\\\./g,function(a,c){return c?a:"!."}),a=a.replace(/(\\)?\\\*/g,function(a,c){return c?a:"!*"}),a=a.replace(/\\\\/g,"\\");return a=a.replace(/\.\*/g,"*")},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison,
-this)},CLASS_NAME:"OpenLayers.Filter.Comparison"});OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Filter.Comparison.IS_NULL="NULL";OpenLayers.Format.Filter=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Date={dateRegEx:/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/,toISOString:function(){return"toISOString"in Date.prototype?function(a){return a.toISOString()}:function(a){return isNaN(a.getTime())?"Invalid Date":a.getUTCFullYear()+"-"+OpenLayers.Number.zeroPad(a.getUTCMonth()+1,2)+"-"+OpenLayers.Number.zeroPad(a.getUTCDate(),2)+"T"+OpenLayers.Number.zeroPad(a.getUTCHours(),2)+":"+OpenLayers.Number.zeroPad(a.getUTCMinutes(),
-2)+":"+OpenLayers.Number.zeroPad(a.getUTCSeconds(),2)+"."+OpenLayers.Number.zeroPad(a.getUTCMilliseconds(),3)+"Z"}}(),parse:function(a){var b;if((a=a.match(this.dateRegEx))&&(a[1]||a[7])){b=parseInt(a[1],10)||0;var c=parseInt(a[2],10)-1||0,d=parseInt(a[3],10)||1;b=new Date(Date.UTC(b,c,d));if(c=a[7]){var d=parseInt(a[4],10),e=parseInt(a[5],10),f=parseFloat(a[6]),g=f|0,f=Math.round(1E3*(f-g));b.setUTCHours(d,e,g,f);"Z"!==c&&(c=parseInt(c,10),a=parseInt(a[8],10)||0,a=-1E3*(60*60*c+60*a),b=new Date(b.getTime()+
-a))}}else b=new Date("invalid");return b}};OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){var b={};this.readers.ogc.Filter.apply(this,[a,b]);return b.filter},readers:{ogc:{_expression:function(a){for(var b="",c=a.firstChild;c;c=
-c.nextSibling)switch(c.nodeType){case 1:a=this.readNode(c);a.property?b+="${"+a.property+"}":void 0!==a.value&&(b+=a.value);break;case 3:case 4:b+=c.nodeValue}return b},Filter:function(a,b){var c={fids:[],filters:[]};this.readChildNodes(a,c);0<c.fids.length?b.filter=new OpenLayers.Filter.FeatureId({fids:c.fids}):0<c.filters.length&&(b.filter=c.filters[0])},FeatureId:function(a,b){var c=a.getAttribute("fid");c&&b.fids.push(c)},And:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND});
-this.readChildNodes(a,c);b.filters.push(c)},Or:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(a,c);b.filters.push(c)},Not:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThan:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThan:function(a,
-b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},
-PropertyIsBetween:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(a,c);b.filters.push(c)},Literal:function(a,b){b.value=OpenLayers.String.numericIf(this.getChildValue(a),!0)},PropertyName:function(a,b){b.property=this.getChildValue(a)},LowerBoundary:function(a,b){b.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,a),!0)},UpperBoundary:function(a,b){b.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,
-a),!0)},Intersects:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.INTERSECTS)},Within:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.WITHIN)},Contains:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.CONTAINS)},DWithin:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.DWITHIN)},Distance:function(a,b){b.distance=parseInt(this.getChildValue(a));b.distanceUnits=a.getAttribute("units")},Function:function(a,b){},PropertyIsNull:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.IS_NULL});
-this.readChildNodes(a,c);b.filters.push(c)}}},readSpatial:function(a,b,c){c=new OpenLayers.Filter.Spatial({type:c});this.readChildNodes(a,c);c.value=c.components[0];delete c.components;b.filters.push(c)},encodeLiteral:function(a){a instanceof Date&&(a=OpenLayers.Date.toISOString(a));return a},writeOgcExpression:function(a,b){a instanceof OpenLayers.Filter.Function?this.writeNode("Function",a,b):this.writeNode("Literal",a,b);return b},write:function(a){return this.writers.ogc.Filter.apply(this,[a])},
-writers:{ogc:{Filter:function(a){var b=this.createElementNSPlus("ogc:Filter");this.writeNode(this.getFilterType(a),a,b);return b},_featureIds:function(a){for(var b=this.createDocumentFragment(),c=0,d=a.fids.length;c<d;++c)this.writeNode("ogc:FeatureId",a.fids[c],b);return b},FeatureId:function(a){return this.createElementNSPlus("ogc:FeatureId",{attributes:{fid:a}})},And:function(a){for(var b=this.createElementNSPlus("ogc:And"),c,d=0,e=a.filters.length;d<e;++d)c=a.filters[d],this.writeNode(this.getFilterType(c),
-c,b);return b},Or:function(a){for(var b=this.createElementNSPlus("ogc:Or"),c,d=0,e=a.filters.length;d<e;++d)c=a.filters[d],this.writeNode(this.getFilterType(c),c,b);return b},Not:function(a){var b=this.createElementNSPlus("ogc:Not");a=a.filters[0];this.writeNode(this.getFilterType(a),a,b);return b},PropertyIsLessThan:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLessThan");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsGreaterThan:function(a){var b=
-this.createElementNSPlus("ogc:PropertyIsGreaterThan");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLessThanOrEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsGreaterThanOrEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);
-return b},PropertyIsBetween:function(a){var b=this.createElementNSPlus("ogc:PropertyIsBetween");this.writeNode("PropertyName",a,b);this.writeNode("LowerBoundary",a,b);this.writeNode("UpperBoundary",a,b);return b},PropertyName:function(a){return this.createElementNSPlus("ogc:PropertyName",{value:a.property})},Literal:function(a){return this.createElementNSPlus("ogc:Literal",{value:(this.encodeLiteral||OpenLayers.Format.Filter.v1.prototype.encodeLiteral)(a)})},LowerBoundary:function(a){var b=this.createElementNSPlus("ogc:LowerBoundary");
-this.writeOgcExpression(a.lowerBoundary,b);return b},UpperBoundary:function(a){var b=this.createElementNSPlus("ogc:UpperBoundary");this.writeNode("Literal",a.upperBoundary,b);return b},INTERSECTS:function(a){return this.writeSpatial(a,"Intersects")},WITHIN:function(a){return this.writeSpatial(a,"Within")},CONTAINS:function(a){return this.writeSpatial(a,"Contains")},DWITHIN:function(a){var b=this.writeSpatial(a,"DWithin");this.writeNode("Distance",a,b);return b},Distance:function(a){return this.createElementNSPlus("ogc:Distance",
-{attributes:{units:a.distanceUnits},value:a.distance})},Function:function(a){var b=this.createElementNSPlus("ogc:Function",{attributes:{name:a.name}});a=a.params;for(var c=0,d=a.length;c<d;c++)this.writeOgcExpression(a[c],b);return b},PropertyIsNull:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNull");this.writeNode("PropertyName",a,b);return b}}},getFilterType:function(a){var b=this.filterMap[a.type];if(!b)throw"Filter writing not supported for rule type: "+a.type;return b},filterMap:{"&&":"And",
-"||":"Or","!":"Not","==":"PropertyIsEqualTo","!=":"PropertyIsNotEqualTo","<":"PropertyIsLessThan",">":"PropertyIsGreaterThan","<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike",NULL:"PropertyIsNull",BBOX:"BBOX",DWITHIN:"DWITHIN",WITHIN:"WITHIN",CONTAINS:"CONTAINS",INTERSECTS:"INTERSECTS",FID:"_featureIds"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){this.bounds=this.id=null},clone:function(){return new OpenLayers.Geometry},setBounds:function(a){a&&(this.bounds=a.clone())},clearBounds:function(){this.bounds=null;this.parent&&this.parent.clearBounds()},extendBounds:function(a){this.getBounds()?this.bounds.extend(a):this.setBounds(a)},getBounds:function(){null==this.bounds&&this.calculateBounds();
-return this.bounds},calculateBounds:function(){},distanceTo:function(a,b){},getVertices:function(a){},atPoint:function(a,b,c){var d=!1;null!=this.getBounds()&&null!=a&&(b=null!=b?b:0,c=null!=c?c:0,d=(new OpenLayers.Bounds(this.bounds.left-b,this.bounds.bottom-c,this.bounds.right+b,this.bounds.top+c)).containsLonLat(a));return d},getLength:function(){return 0},getArea:function(){return 0},getCentroid:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.WKT?OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this)):
-Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(a){var b;if(OpenLayers.Format&&OpenLayers.Format.WKT){var c=OpenLayers.Geometry.fromWKT.format;c||(c=new OpenLayers.Format.WKT,OpenLayers.Geometry.fromWKT.format=c);a=c.read(a);if(a instanceof OpenLayers.Feature.Vector)b=a.geometry;else if(OpenLayers.Util.isArray(a)){b=a.length;for(var c=Array(b),d=0;d<b;++d)c[d]=a[d].geometry;b=new OpenLayers.Geometry.Collection(c)}}return b};
-OpenLayers.Geometry.segmentsIntersect=function(a,b,c){var d=c&&c.point;c=c&&c.tolerance;var e=!1,f=a.x1-b.x1,g=a.y1-b.y1,h=a.x2-a.x1,k=a.y2-a.y1,l=b.y2-b.y1,m=b.x2-b.x1,n=l*h-m*k,l=m*g-l*f,g=h*g-k*f;0==n?0==l&&0==g&&(e=!0):(f=l/n,n=g/n,0<=f&&(1>=f&&0<=n&&1>=n)&&(d?(h=a.x1+f*h,n=a.y1+f*k,e=new OpenLayers.Geometry.Point(h,n)):e=!0));if(c)if(e){if(d)a:for(a=[a,b],b=0;2>b;++b)for(f=a[b],k=1;3>k;++k)if(h=f["x"+k],n=f["y"+k],d=Math.sqrt(Math.pow(h-e.x,2)+Math.pow(n-e.y,2)),d<c){e.x=h;e.y=n;break a}}else a:for(a=
-[a,b],b=0;2>b;++b)for(h=a[b],n=a[(b+1)%2],k=1;3>k;++k)if(f={x:h["x"+k],y:h["y"+k]},g=OpenLayers.Geometry.distanceToSegment(f,n),g.distance<c){e=d?new OpenLayers.Geometry.Point(f.x,f.y):!0;break a}return e};OpenLayers.Geometry.distanceToSegment=function(a,b){var c=OpenLayers.Geometry.distanceSquaredToSegment(a,b);c.distance=Math.sqrt(c.distance);return c};
-OpenLayers.Geometry.distanceSquaredToSegment=function(a,b){var c=a.x,d=a.y,e=b.x1,f=b.y1,g=b.x2,h=b.y2,k=g-e,l=h-f,m=(k*(c-e)+l*(d-f))/(Math.pow(k,2)+Math.pow(l,2));0>=m||(1<=m?(e=g,f=h):(e+=m*k,f+=m*l));return{distance:Math.pow(e-c,2)+Math.pow(f-d,2),x:e,y:f,along:m}};OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(a,b){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(a);this.y=parseFloat(b)},clone:function(a){null==a&&(a=new OpenLayers.Geometry.Point(this.x,this.y));OpenLayers.Util.applyDefaults(a,this);return a},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y)},distanceTo:function(a,b){var c=!(b&&!1===b.edge)&&b&&b.details,d,e,f,g,h;a instanceof
-OpenLayers.Geometry.Point?(e=this.x,f=this.y,g=a.x,h=a.y,d=Math.sqrt(Math.pow(e-g,2)+Math.pow(f-h,2)),d=c?{x0:e,y0:f,x1:g,y1:h,distance:d}:d):(d=a.distanceTo(this,b),c&&(d={x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0,distance:d.distance}));return d},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},toShortString:function(){return this.x+", "+this.y},move:function(a,b){this.x+=a;this.y+=b;this.clearBounds()},rotate:function(a,b){a*=
-Math.PI/180;var c=this.distanceTo(b),d=a+Math.atan2(this.y-b.y,this.x-b.x);this.x=b.x+c*Math.cos(d);this.y=b.y+c*Math.sin(d);this.clearBounds()},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y)},resize:function(a,b,c){this.x=b.x+a*(void 0==c?1:c)*(this.x-b.x);this.y=b.y+a*(this.y-b.y);this.clearBounds();return this},intersects:function(a){var b=!1;return b="OpenLayers.Geometry.Point"==a.CLASS_NAME?this.equals(a):a.intersects(this)},transform:function(a,b){a&&b&&(OpenLayers.Projection.transform(this,
-a,b),this.bounds=null);return this},getVertices:function(a){return[this]},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(a){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];null!=a&&this.addComponents(a)},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments)},clone:function(){for(var a=eval("new "+this.CLASS_NAME+"()"),b=0,c=this.components.length;b<c;b++)a.addComponent(this.components[b].clone());
-OpenLayers.Util.applyDefaults(a,this);return a},getComponentsString:function(){for(var a=[],b=0,c=this.components.length;b<c;b++)a.push(this.components[b].toShortString());return a.join(",")},calculateBounds:function(){this.bounds=null;var a=new OpenLayers.Bounds,b=this.components;if(b)for(var c=0,d=b.length;c<d;c++)a.extend(b[c].getBounds());null!=a.left&&(null!=a.bottom&&null!=a.right&&null!=a.top)&&this.setBounds(a)},addComponents:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b<
-c;b++)this.addComponent(a[b])},addComponent:function(a,b){var c=!1;if(a&&(null==this.componentTypes||-1<OpenLayers.Util.indexOf(this.componentTypes,a.CLASS_NAME))){if(null!=b&&b<this.components.length){var c=this.components.slice(0,b),d=this.components.slice(b,this.components.length);c.push(a);this.components=c.concat(d)}else this.components.push(a);a.parent=this;this.clearBounds();c=!0}return c},removeComponents:function(a){var b=!1;OpenLayers.Util.isArray(a)||(a=[a]);for(var c=a.length-1;0<=c;--c)b=
-this.removeComponent(a[c])||b;return b},removeComponent:function(a){OpenLayers.Util.removeItem(this.components,a);this.clearBounds();return!0},getLength:function(){for(var a=0,b=0,c=this.components.length;b<c;b++)a+=this.components[b].getLength();return a},getArea:function(){for(var a=0,b=0,c=this.components.length;b<c;b++)a+=this.components[b].getArea();return a},getGeodesicArea:function(a){for(var b=0,c=0,d=this.components.length;c<d;c++)b+=this.components[c].getGeodesicArea(a);return b},getCentroid:function(a){if(!a)return this.components.length&&
-this.components[0].getCentroid();a=this.components.length;if(!a)return!1;for(var b=[],c=[],d=0,e=Number.MAX_VALUE,f,g=0;g<a;++g){f=this.components[g];var h=f.getArea();f=f.getCentroid(!0);isNaN(h)||(isNaN(f.x)||isNaN(f.y))||(b.push(h),d+=h,e=h<e&&0<h?h:e,c.push(f))}a=b.length;if(0===d){for(g=0;g<a;++g)b[g]=1;d=b.length}else{for(g=0;g<a;++g)b[g]/=e;d/=e}for(var k=e=0,g=0;g<a;++g)f=c[g],h=b[g],e+=f.x*h,k+=f.y*h;return new OpenLayers.Geometry.Point(e/d,k/d)},getGeodesicLength:function(a){for(var b=0,
-c=0,d=this.components.length;c<d;c++)b+=this.components[c].getGeodesicLength(a);return b},move:function(a,b){for(var c=0,d=this.components.length;c<d;c++)this.components[c].move(a,b)},rotate:function(a,b){for(var c=0,d=this.components.length;c<d;++c)this.components[c].rotate(a,b)},resize:function(a,b,c){for(var d=0;d<this.components.length;++d)this.components[d].resize(a,b,c);return this},distanceTo:function(a,b){for(var c=!(b&&!1===b.edge)&&b&&b.details,d,e,f,g=Number.POSITIVE_INFINITY,h=0,k=this.components.length;h<
-k&&!(d=this.components[h].distanceTo(a,b),f=c?d.distance:d,f<g&&(g=f,e=d,0==g));++h);return e},equals:function(a){var b=!0;if(a&&a.CLASS_NAME&&this.CLASS_NAME==a.CLASS_NAME)if(OpenLayers.Util.isArray(a.components)&&a.components.length==this.components.length)for(var c=0,d=this.components.length;c<d;++c){if(!this.components[c].equals(a.components[c])){b=!1;break}}else b=!1;else b=!1;return b},transform:function(a,b){if(a&&b){for(var c=0,d=this.components.length;c<d;c++)this.components[c].transform(a,
-b);this.bounds=null}return this},intersects:function(a){for(var b=!1,c=0,d=this.components.length;c<d&&!(b=a.intersects(this.components[c]));++c);return b},getVertices:function(a){for(var b=[],c=0,d=this.components.length;c<d;++c)Array.prototype.push.apply(b,this.components[c].getVertices(a));return b},CLASS_NAME:"OpenLayers.Geometry.Collection"});OpenLayers.Geometry.MultiPoint=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Point"],addPoint:function(a,b){this.addComponent(a,b)},removePoint:function(a){this.removeComponent(a)},CLASS_NAME:"OpenLayers.Geometry.MultiPoint"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],getLength:function(){var a=0;if(this.components&&1<this.components.length)for(var b=1,c=this.components.length;b<c;b++)a+=this.components[b-1].distanceTo(this.components[b]);return a},getGeodesicLength:function(a){var b=this;if(a){var c=new OpenLayers.Projection("EPSG:4326");c.equals(a)||(b=this.clone().transform(a,c))}a=0;if(b.components&&1<b.components.length)for(var d,e=1,f=b.components.length;e<
-f;e++)c=b.components[e-1],d=b.components[e],a+=OpenLayers.Util.distVincenty({lon:c.x,lat:c.y},{lon:d.x,lat:d.y});return 1E3*a},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(a){var b=this.components&&2<this.components.length;b&&OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);return b},intersects:function(a){var b=!1,c=a.CLASS_NAME;if("OpenLayers.Geometry.LineString"==c||"OpenLayers.Geometry.LinearRing"==c||"OpenLayers.Geometry.Point"==c){var d=this.getSortedSegments();a="OpenLayers.Geometry.Point"==c?[{x1:a.x,y1:a.y,x2:a.x,y2:a.y}]:a.getSortedSegments();
-var e,f,g,h,k,l,m,n=0,p=d.length;a:for(;n<p;++n){c=d[n];e=c.x1;f=c.x2;g=c.y1;h=c.y2;var q=0,r=a.length;for(;q<r;++q){k=a[q];if(k.x1>f)break;if(!(k.x2<e||(l=k.y1,m=k.y2,Math.min(l,m)>Math.max(g,h)||Math.max(l,m)<Math.min(g,h)||!OpenLayers.Geometry.segmentsIntersect(c,k)))){b=!0;break a}}}}else b=a.intersects(this);return b},getSortedSegments:function(){for(var a=this.components.length-1,b=Array(a),c,d,e=0;e<a;++e)c=this.components[e],d=this.components[e+1],b[e]=c.x<d.x?{x1:c.x,y1:c.y,x2:d.x,y2:d.y}:
-{x1:d.x,y1:d.y,x2:c.x,y2:c.y};return b.sort(function(a,b){return a.x1-b.x1})},splitWithSegment:function(a,b){for(var c=!(b&&!1===b.edge),d=b&&b.tolerance,e=[],f=this.getVertices(),g=[],h=[],k=!1,l,m,n,p={point:!0,tolerance:d},q=null,r=0,s=f.length-2;r<=s;++r)if(d=f[r],g.push(d.clone()),l=f[r+1],m={x1:d.x,y1:d.y,x2:l.x,y2:l.y},m=OpenLayers.Geometry.segmentsIntersect(a,m,p),m instanceof OpenLayers.Geometry.Point&&((n=m.x===a.x1&&m.y===a.y1||m.x===a.x2&&m.y===a.y2||m.equals(d)||m.equals(l)?!0:!1)||c))m.equals(h[h.length-
-1])||h.push(m.clone()),0===r&&m.equals(d)||m.equals(l)||(k=!0,m.equals(d)||g.push(m),e.push(new OpenLayers.Geometry.LineString(g)),g=[m.clone()]);k&&(g.push(l.clone()),e.push(new OpenLayers.Geometry.LineString(g)));if(0<h.length)var t=a.x1<a.x2?1:-1,u=a.y1<a.y2?1:-1,q={lines:e,points:h.sort(function(a,b){return t*a.x-t*b.x||u*a.y-u*b.y})};return q},split:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h;if(a instanceof OpenLayers.Geometry.LineString){var k=this.getVertices(),l,m,n,p,q,r=[];g=[];for(var s=
-0,t=k.length-2;s<=t;++s){l=k[s];m=k[s+1];n={x1:l.x,y1:l.y,x2:m.x,y2:m.y};h=h||[a];d&&r.push(l.clone());for(var u=0;u<h.length;++u)if(p=h[u].splitWithSegment(n,b))if(q=p.lines,0<q.length&&(q.unshift(u,1),Array.prototype.splice.apply(h,q),u+=q.length-2),d)for(var v=0,w=p.points.length;v<w;++v)q=p.points[v],q.equals(l)||(r.push(q),g.push(new OpenLayers.Geometry.LineString(r)),r=q.equals(m)?[]:[q.clone()])}d&&(0<g.length&&0<r.length)&&(r.push(m.clone()),g.push(new OpenLayers.Geometry.LineString(r)))}else c=
-a.splitWith(this,b);h&&1<h.length?f=!0:h=[];g&&1<g.length?e=!0:g=[];if(f||e)c=d?[g,h]:h;return c},splitWith:function(a,b){return a.split(this,b)},getVertices:function(a){return!0===a?[this.components[0],this.components[this.components.length-1]]:!1===a?this.components.slice(1,this.components.length-1):this.components.slice()},distanceTo:function(a,b){var c=!(b&&!1===b.edge)&&b&&b.details,d,e={},f=Number.POSITIVE_INFINITY;if(a instanceof OpenLayers.Geometry.Point){for(var g=this.getSortedSegments(),
-h=a.x,k=a.y,l,m=0,n=g.length;m<n;++m)if(l=g[m],d=OpenLayers.Geometry.distanceToSegment(a,l),d.distance<f){if(f=d.distance,e=d,0===f)break}else if(l.x2>h&&(k>l.y1&&k<l.y2||k<l.y1&&k>l.y2))break;e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:k}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){var g=this.getSortedSegments(),h=a.getSortedSegments(),p,q,r=h.length,s={point:!0},m=0,n=g.length;a:for(;m<n;++m){k=g[m];l=k.x1;q=k.y1;for(var t=0;t<r;++t)if(d=h[t],p=OpenLayers.Geometry.segmentsIntersect(k,
-d,s)){f=0;e={distance:0,x0:p.x,y0:p.y,x1:p.x,y1:p.y};break a}else d=OpenLayers.Geometry.distanceToSegment({x:l,y:q},d),d.distance<f&&(f=d.distance,e={distance:f,x0:l,y0:q,x1:d.x,y1:d.y})}c||(e=e.distance);0!==f&&k&&(d=a.distanceTo(new OpenLayers.Geometry.Point(k.x2,k.y2),b),m=c?d.distance:d,m<f&&(e=c?{distance:f,x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0}:m))}else e=a.distanceTo(this,b),c&&(e={distance:e.distance,x0:e.x1,y0:e.y1,x1:e.x0,y1:e.y0});return e},simplify:function(a){if(this&&null!==this){var b=this.getVertices();
-if(3>b.length)return this;var c=function(a,b,d,k){for(var l=0,m=0,n=b,p;n<d;n++){p=a[b];var q=a[d],r=a[n],r=Math.abs(0.5*(p.x*q.y+q.x*r.y+r.x*p.y-q.x*p.y-r.x*q.y-p.x*r.y));p=Math.sqrt(Math.pow(p.x-q.x,2)+Math.pow(p.y-q.y,2));p=2*(r/p);p>l&&(l=p,m=n)}l>k&&m!=b&&(e.push(m),c(a,b,m,k),c(a,m,d,k))},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);)d--,e.push(d);c(b,0,d,a);a=[];e.sort(function(a,b){return a-b});for(d=0;d<e.length;d++)a.push(b[e[d]]);return new OpenLayers.Geometry.LineString(a)}return this},
-CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],split:function(a,b){for(var c=null,d=b&&b.mutual,e,f,g,h,k=[],l=[a],m=0,n=this.components.length;m<n;++m){f=this.components[m];g=!1;for(var p=0;p<l.length;++p)if(e=f.split(l[p],b)){if(d){g=e[0];for(var q=0,r=g.length;q<r;++q)0===q&&k.length?k[k.length-1].addComponent(g[q]):k.push(new OpenLayers.Geometry.MultiLineString([g[q]]));g=!0;e=e[1]}if(e.length){e.unshift(p,
-1);Array.prototype.splice.apply(l,e);break}}g||(k.length?k[k.length-1].addComponent(f.clone()):k=[new OpenLayers.Geometry.MultiLineString(f.clone())])}k&&1<k.length?g=!0:k=[];l&&1<l.length?h=!0:l=[];if(g||h)c=d?[k,l]:l;return c},splitWith:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h,k,l;if(a instanceof OpenLayers.Geometry.LineString){l=[];k=[a];for(var m=0,n=this.components.length;m<n;++m){g=!1;f=this.components[m];for(var p=0;p<k.length;++p)if(e=k[p].split(f,b)){d&&(g=e[0],g.length&&(g.unshift(p,
-1),Array.prototype.splice.apply(k,g),p+=g.length-2),e=e[1],0===e.length&&(e=[f.clone()]));g=0;for(var q=e.length;g<q;++g)0===g&&l.length?l[l.length-1].addComponent(e[g]):l.push(new OpenLayers.Geometry.MultiLineString([e[g]]));g=!0}g||(l.length?l[l.length-1].addComponent(f.clone()):l=[new OpenLayers.Geometry.MultiLineString([f.clone()])])}}else c=a.split(this);k&&1<k.length?h=!0:k=[];l&&1<l.length?g=!0:l=[];if(h||g)c=d?[k,l]:l;return c},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(a,b){var c=!1,d=this.components.pop();null==b&&a.equals(d)||(c=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments));OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]);return c},removeComponent:function(a){var b=this.components&&3<this.components.length;b&&(this.components.pop(),OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
-arguments),OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]));return b},move:function(a,b){for(var c=0,d=this.components.length;c<d-1;c++)this.components[c].move(a,b)},rotate:function(a,b){for(var c=0,d=this.components.length;c<d-1;++c)this.components[c].rotate(a,b)},resize:function(a,b,c){for(var d=0,e=this.components.length;d<e-1;++d)this.components[d].resize(a,b,c);return this},transform:function(a,b){if(a&&b){for(var c=0,d=this.components.length;c<d-1;c++)this.components[c].transform(a,
-b);this.bounds=null}return this},getCentroid:function(){if(this.components){var a=this.components.length;if(0<a&&2>=a)return this.components[0].clone();if(2<a){var b=0,c=0,d=this.components[0].x,e=this.components[0].y,f=-1*this.getArea();if(0!=f){for(var g=0;g<a-1;g++)var h=this.components[g],k=this.components[g+1],b=b+(h.x+k.x-2*d)*((h.x-d)*(k.y-e)-(k.x-d)*(h.y-e)),c=c+(h.y+k.y-2*e)*((h.x-d)*(k.y-e)-(k.x-d)*(h.y-e));b=d+b/(6*f);a=e+c/(6*f)}else{for(g=0;g<a-1;g++)b+=this.components[g].x,c+=this.components[g].y;
-b/=a-1;a=c/(a-1)}return new OpenLayers.Geometry.Point(b,a)}return null}},getArea:function(){var a=0;if(this.components&&2<this.components.length){for(var b=a=0,c=this.components.length;b<c-1;b++)var d=this.components[b],e=this.components[b+1],a=a+(d.x+e.x)*(e.y-d.y);a=-a/2}return a},getGeodesicArea:function(a){var b=this;if(a){var c=new OpenLayers.Projection("EPSG:4326");c.equals(a)||(b=this.clone().transform(a,c))}a=0;c=b.components&&b.components.length;if(2<c){for(var d,e,f=0;f<c-1;f++)d=b.components[f],
-e=b.components[f+1],a+=OpenLayers.Util.rad(e.x-d.x)*(2+Math.sin(OpenLayers.Util.rad(d.y))+Math.sin(OpenLayers.Util.rad(e.y)));a=40680631590769*a/2}return a},containsPoint:function(a){var b=OpenLayers.Number.limitSigDigs,c=b(a.x,14);a=b(a.y,14);for(var d=this.components.length-1,e,f,g,h,k,l=0,m=0;m<d;++m)if(e=this.components[m],g=b(e.x,14),e=b(e.y,14),f=this.components[m+1],h=b(f.x,14),f=b(f.y,14),e==f){if(a==e&&(g<=h&&c>=g&&c<=h||g>=h&&c<=g&&c>=h)){l=-1;break}}else{k=b((a-f)*((h-g)/(f-e))+h,14);if(k==
-c&&(e<f&&a>=e&&a<=f||e>f&&a<=e&&a>=f)){l=-1;break}k<=c||g!=h&&(k<Math.min(g,h)||k>Math.max(g,h))||(e<f&&a>=e&&a<f||e>f&&a<e&&a>=f)&&++l}return-1==l?1:!!(l&1)},intersects:function(a){var b=!1;if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME)b=a.intersects(this);else if("OpenLayers.Geometry.LinearRing"==a.CLASS_NAME)b=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[a]);else for(var c=0,d=a.components.length;c<
-d&&!(b=a.components[c].intersects(this));++c);return b},getVertices:function(a){return!0===a?[]:this.components.slice(0,this.components.length-1)},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],getArea:function(){var a=0;if(this.components&&0<this.components.length)for(var a=a+Math.abs(this.components[0].getArea()),b=1,c=this.components.length;b<c;b++)a-=Math.abs(this.components[b].getArea());return a},getGeodesicArea:function(a){var b=0;if(this.components&&0<this.components.length)for(var b=b+Math.abs(this.components[0].getGeodesicArea(a)),c=1,d=this.components.length;c<
-d;c++)b-=Math.abs(this.components[c].getGeodesicArea(a));return b},containsPoint:function(a){var b=this.components.length,c=!1;if(0<b&&(c=this.components[0].containsPoint(a),1!==c&&c&&1<b))for(var d,e=1;e<b;++e)if(d=this.components[e].containsPoint(a)){c=1===d?1:!1;break}return c},intersects:function(a){var b=!1,c,d;if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME||"OpenLayers.Geometry.LinearRing"==a.CLASS_NAME){c=0;for(d=
-this.components.length;c<d&&!(b=a.intersects(this.components[c]));++c);if(!b)for(c=0,d=a.components.length;c<d&&!(b=this.containsPoint(a.components[c]));++c);}else for(c=0,d=a.components.length;c<d&&!(b=this.intersects(a.components[c]));++c);if(!b&&"OpenLayers.Geometry.Polygon"==a.CLASS_NAME){var e=this.components[0];c=0;for(d=e.components.length;c<d&&!(b=a.containsPoint(e.components[c]));++c);}return b},distanceTo:function(a,b){return b&&!1===b.edge&&this.intersects(a)?0:OpenLayers.Geometry.Collection.prototype.distanceTo.apply(this,
-[a,b])},CLASS_NAME:"OpenLayers.Geometry.Polygon"});OpenLayers.Geometry.Polygon.createRegularPolygon=function(a,b,c,d){var e=Math.PI*(1/c-0.5);d&&(e+=d/180*Math.PI);for(var f,g=[],h=0;h<c;++h)f=e+2*h*Math.PI/c,d=a.x+b*Math.cos(f),f=a.y+b*Math.sin(f),g.push(new OpenLayers.Geometry.Point(d,f));a=new OpenLayers.Geometry.LinearRing(g);return new OpenLayers.Geometry.Polygon([a])};OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Format.GML=OpenLayers.Class(OpenLayers.Format.XML,{featureNS:"http://mapserver.gis.umn.edu/mapserver",featurePrefix:"feature",featureName:"featureMember",layerName:"features",geometryName:"geometry",collectionName:"FeatureCollection",gmlns:"http://www.opengis.net/gml",extractAttributes:!0,xy:!0,initialize:function(a){this.regExes={trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g};OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==
-typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a=this.getElementsByTagNameNS(a.documentElement,this.gmlns,this.featureName);for(var b=[],c=0;c<a.length;c++){var d=this.parseFeature(a[c]);d&&b.push(d)}return b},parseFeature:function(a){for(var b="MultiPolygon Polygon MultiLineString LineString MultiPoint Point Envelope".split(" "),c,d,e,f=0;f<b.length;++f)if(c=b[f],d=this.getElementsByTagNameNS(a,this.gmlns,c),0<d.length){if(e=this.parseGeometry[c.toLowerCase()])e=e.apply(this,
-[d[0]]),this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection);else throw new TypeError("Unsupported geometry type: "+c);break}var g;c=this.getElementsByTagNameNS(a,this.gmlns,"Box");for(f=0;f<c.length;++f)b=c[f],d=this.parseGeometry.box.apply(this,[b]),b=b.parentNode,"boundedBy"===(b.localName||b.nodeName.split(":").pop())?g=d:e=d.toGeometry();var h;this.extractAttributes&&(h=this.parseAttributes(a));h=new OpenLayers.Feature.Vector(e,h);h.bounds=
-g;h.gml={featureType:a.firstChild.nodeName.split(":")[1],featureNS:a.firstChild.namespaceURI,featureNSPrefix:a.firstChild.prefix};a=a.firstChild;for(var k;a&&(1!=a.nodeType||!(k=a.getAttribute("fid")||a.getAttribute("id")));)a=a.nextSibling;h.fid=k;return h},parseGeometry:{point:function(a){var b,c;c=[];b=this.getElementsByTagNameNS(a,this.gmlns,"pos");0<b.length&&(c=b[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));0==c.length&&(b=this.getElementsByTagNameNS(a,
-this.gmlns,"coordinates"),0<b.length&&(c=b[0].firstChild.nodeValue,c=c.replace(this.regExes.removeSpace,""),c=c.split(",")));0==c.length&&(b=this.getElementsByTagNameNS(a,this.gmlns,"coord"),0<b.length&&(a=this.getElementsByTagNameNS(b[0],this.gmlns,"X"),b=this.getElementsByTagNameNS(b[0],this.gmlns,"Y"),0<a.length&&0<b.length&&(c=[a[0].firstChild.nodeValue,b[0].firstChild.nodeValue])));2==c.length&&(c[2]=null);return this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],
-c[0],c[2])},multipoint:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"Point");var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.point.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiPoint(b)},linestring:function(a,b){var c,d;d=[];var e=[];c=this.getElementsByTagNameNS(a,this.gmlns,"posList");if(0<c.length){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.split(this.regExes.splitSpace);var f=parseInt(c[0].getAttribute("dimension")),
-g,h,k;for(c=0;c<d.length/f;++c)g=c*f,h=d[g],k=d[g+1],g=2==f?null:d[g+2],this.xy?e.push(new OpenLayers.Geometry.Point(h,k,g)):e.push(new OpenLayers.Geometry.Point(k,h,g))}if(0==d.length&&(c=this.getElementsByTagNameNS(a,this.gmlns,"coordinates"),0<c.length))for(d=this.getChildValue(c[0]),d=d.replace(this.regExes.trimSpace,""),d=d.replace(this.regExes.trimComma,","),f=d.split(this.regExes.splitSpace),c=0;c<f.length;++c)d=f[c].split(","),2==d.length&&(d[2]=null),this.xy?e.push(new OpenLayers.Geometry.Point(d[0],
-d[1],d[2])):e.push(new OpenLayers.Geometry.Point(d[1],d[0],d[2]));d=null;0!=e.length&&(d=b?new OpenLayers.Geometry.LinearRing(e):new OpenLayers.Geometry.LineString(e));return d},multilinestring:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"LineString");var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.linestring.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiLineString(b)},polygon:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"LinearRing");
-var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.linestring.apply(this,[a[d],!0]))&&b.push(c);return new OpenLayers.Geometry.Polygon(b)},multipolygon:function(a){a=this.getElementsByTagNameNS(a,this.gmlns,"Polygon");var b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.polygon.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiPolygon(b)},envelope:function(a){var b=[],c,d,e=this.getElementsByTagNameNS(a,this.gmlns,"lowerCorner");if(0<e.length){c=
-[];0<e.length&&(c=e[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));2==c.length&&(c[2]=null);var f=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}a=this.getElementsByTagNameNS(a,this.gmlns,"upperCorner");if(0<a.length){c=[];0<a.length&&(c=a[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));2==c.length&&(c[2]=null);var g=this.xy?new OpenLayers.Geometry.Point(c[0],
-c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}f&&g&&(b.push(new OpenLayers.Geometry.Point(f.x,f.y)),b.push(new OpenLayers.Geometry.Point(g.x,f.y)),b.push(new OpenLayers.Geometry.Point(g.x,g.y)),b.push(new OpenLayers.Geometry.Point(f.x,g.y)),b.push(new OpenLayers.Geometry.Point(f.x,f.y)),b=new OpenLayers.Geometry.LinearRing(b),d=new OpenLayers.Geometry.Polygon([b]));return d},box:function(a){var b=this.getElementsByTagNameNS(a,this.gmlns,"coordinates"),c=a=null;0<b.length&&(b=b[0].firstChild.nodeValue,
-b=b.split(" "),2==b.length&&(a=b[0].split(","),c=b[1].split(",")));if(null!==a&&null!==c)return new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(c[0]),parseFloat(c[1]))}},parseAttributes:function(a){var b={};a=a.firstChild;for(var c,d,e;a;){if(1==a.nodeType){a=a.childNodes;for(c=0;c<a.length;++c)if(d=a[c],1==d.nodeType)if(e=d.childNodes,1==e.length){if(e=e[0],3==e.nodeType||4==e.nodeType)d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,e=e.nodeValue.replace(this.regExes.trimSpace,
-""),b[d]=e}else b[d.nodeName.split(":").pop()]=null;break}a=a.nextSibling}return b},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=this.createElementNS("http://www.opengis.net/wfs","wfs:"+this.collectionName),c=0;c<a.length;c++)b.appendChild(this.createFeatureXML(a[c]));return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.featureNS,this.featurePrefix+":"+this.geometryName);c.appendChild(b);
-var b=this.createElementNS(this.gmlns,"gml:"+this.featureName),d=this.createElementNS(this.featureNS,this.featurePrefix+":"+this.layerName);d.setAttribute("fid",a.fid||a.id);d.appendChild(c);for(var e in a.attributes){var c=this.createTextNode(a.attributes[e]),f=e.substring(e.lastIndexOf(":")+1),f=this.createElementNS(this.featureNS,this.featurePrefix+":"+f);f.appendChild(c);d.appendChild(f)}b.appendChild(d);return b},buildGeometryNode:function(a){this.externalProjection&&this.internalProjection&&
-(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b=a.CLASS_NAME,b=b.substring(b.lastIndexOf(".")+1);return this.buildGeometry[b.toLowerCase()].apply(this,[a])},buildGeometry:{point:function(a){var b=this.createElementNS(this.gmlns,"gml:Point");b.appendChild(this.buildCoordinatesNode(a));return b},multipoint:function(a){var b=this.createElementNS(this.gmlns,"gml:MultiPoint");a=a.components;for(var c,d,e=0;e<a.length;e++)c=this.createElementNS(this.gmlns,"gml:pointMember"),
-d=this.buildGeometry.point.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},linestring:function(a){var b=this.createElementNS(this.gmlns,"gml:LineString");b.appendChild(this.buildCoordinatesNode(a));return b},multilinestring:function(a){var b=this.createElementNS(this.gmlns,"gml:MultiLineString");a=a.components;for(var c,d,e=0;e<a.length;++e)c=this.createElementNS(this.gmlns,"gml:lineStringMember"),d=this.buildGeometry.linestring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);
-return b},linearring:function(a){var b=this.createElementNS(this.gmlns,"gml:LinearRing");b.appendChild(this.buildCoordinatesNode(a));return b},polygon:function(a){var b=this.createElementNS(this.gmlns,"gml:Polygon");a=a.components;for(var c,d,e=0;e<a.length;++e)c=0==e?"outerBoundaryIs":"innerBoundaryIs",c=this.createElementNS(this.gmlns,"gml:"+c),d=this.buildGeometry.linearring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},multipolygon:function(a){var b=this.createElementNS(this.gmlns,
-"gml:MultiPolygon");a=a.components;for(var c,d,e=0;e<a.length;++e)c=this.createElementNS(this.gmlns,"gml:polygonMember"),d=this.buildGeometry.polygon.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},bounds:function(a){var b=this.createElementNS(this.gmlns,"gml:Box");b.appendChild(this.buildCoordinatesNode(a));return b}},buildCoordinatesNode:function(a){var b=this.createElementNS(this.gmlns,"gml:coordinates");b.setAttribute("decimal",".");b.setAttribute("cs",",");b.setAttribute("ts",
-" ");var c=[];if(a instanceof OpenLayers.Bounds)c.push(a.left+","+a.bottom),c.push(a.right+","+a.top);else{a=a.components?a.components:[a];for(var d=0;d<a.length;d++)c.push(a[d].x+","+a[d].y)}c=this.createTextNode(c.join(" "));b.appendChild(c);return b},CLASS_NAME:"OpenLayers.Format.GML"});OpenLayers.Format.GML||(OpenLayers.Format.GML={});
-OpenLayers.Format.GML.Base=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs"},defaultPrefix:"gml",schemaLocation:null,featureType:null,featureNS:null,geometryName:"geometry",extractAttributes:!0,srsName:null,xy:!0,geometryTypes:null,singleFeatureType:null,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,featureMember:/^(.*:)?featureMembers?$/},
-initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.setGeometryTypes();a&&a.featureNS&&this.setNamespace("feature",a.featureNS);this.singleFeatureType=!a||"string"===typeof a.featureType},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b=[];this.readNode(a,{features:b},!0);if(0==b.length){var c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMember");if(c.length){a=
-0;for(var d=c.length;a<d;++a)this.readNode(c[a],{features:b},!0)}else c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMembers"),c.length&&this.readNode(c[0],{features:b},!0)}return b},readNode:function(a,b,c){!0===c&&!0===this.autoConfig&&(this.featureType=null,delete this.namespaceAlias[this.featureNS],delete this.namespaces.feature,this.featureNS=null);this.featureNS||(a.prefix in this.namespaces||a.parentNode.namespaceURI!=this.namespaces.gml||!this.regExes.featureMember.test(a.parentNode.nodeName))||
-(this.featureType=a.nodeName.split(":").pop(),this.setNamespace("feature",a.namespaceURI),this.featureNS=a.namespaceURI,this.autoConfig=!0);return OpenLayers.Format.XML.prototype.readNode.apply(this,[a,b])},readers:{gml:{_inherit:function(a,b,c){},featureMember:function(a,b){this.readChildNodes(a,b)},featureMembers:function(a,b){this.readChildNodes(a,b)},name:function(a,b){b.name=this.getChildValue(a)},boundedBy:function(a,b){var c={};this.readChildNodes(a,c);c.components&&0<c.components.length&&
-(b.bounds=c.components[0])},Point:function(a,b){var c={points:[]};this.readChildNodes(a,c);b.components||(b.components=[]);b.components.push(c.points[0])},coordinates:function(a,b){for(var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace),d,e=c.length,f=Array(e),g=0;g<e;++g)d=c[g].split(","),f[g]=this.xy?new OpenLayers.Geometry.Point(d[0],d[1],d[2]):new OpenLayers.Geometry.Point(d[1],d[0],d[2]);b.points=f},coord:function(a,
-b){var c={};this.readChildNodes(a,c);b.points||(b.points=[]);b.points.push(new OpenLayers.Geometry.Point(c.x,c.y,c.z))},X:function(a,b){b.x=this.getChildValue(a)},Y:function(a,b){b.y=this.getChildValue(a)},Z:function(a,b){b.z=this.getChildValue(a)},MultiPoint:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiPoint(c.components)]},pointMember:function(a,b){this.readChildNodes(a,b)},LineString:function(a,
-b){var c={};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components||(b.components=[]);b.components.push(new OpenLayers.Geometry.LineString(c.points))},MultiLineString:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiLineString(c.components)]},lineStringMember:function(a,b){this.readChildNodes(a,b)},Polygon:function(a,b){var c={outer:null,inner:[]};this.readers.gml._inherit.apply(this,
-[a,c,b]);this.readChildNodes(a,c);c.inner.unshift(c.outer);b.components||(b.components=[]);b.components.push(new OpenLayers.Geometry.Polygon(c.inner))},LinearRing:function(a,b){var c={};this.readers.gml._inherit.apply(this,[a,c]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.LinearRing(c.points)]},MultiPolygon:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)]},
-polygonMember:function(a,b){this.readChildNodes(a,b)},GeometryCollection:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.Collection(c.components)]},geometryMember:function(a,b){this.readChildNodes(a,b)}},feature:{"*":function(a,b){var c,d=a.localName||a.nodeName.split(":").pop();b.features?this.singleFeatureType||-1===OpenLayers.Util.indexOf(this.featureType,d)?d===this.featureType&&(c="_typeName"):c=
-"_typeName":0==a.childNodes.length||1==a.childNodes.length&&3==a.firstChild.nodeType?this.extractAttributes&&(c="_attribute"):c="_geometry";c&&this.readers.feature[c].apply(this,[a,b])},_typeName:function(a,b){var c={components:[],attributes:{}};this.readChildNodes(a,c);c.name&&(c.attributes.name=c.name);var d=new OpenLayers.Feature.Vector(c.components[0],c.attributes);this.singleFeatureType||(d.type=a.nodeName.split(":").pop(),d.namespace=a.namespaceURI);var e=a.getAttribute("fid")||this.getAttributeNS(a,
-this.namespaces.gml,"id");e&&(d.fid=e);this.internalProjection&&(this.externalProjection&&d.geometry)&&d.geometry.transform(this.externalProjection,this.internalProjection);c.bounds&&(d.bounds=c.bounds);b.features.push(d)},_geometry:function(a,b){this.geometryName||(this.geometryName=a.nodeName.split(":").pop());this.readChildNodes(a,b)},_attribute:function(a,b){var c=a.localName||a.nodeName.split(":").pop(),d=this.getChildValue(a);b.attributes[c]=d}},wfs:{FeatureCollection:function(a,b){this.readChildNodes(a,
-b)}}},write:function(a){var b;b=OpenLayers.Util.isArray(a)?"featureMembers":"featureMember";a=this.writeNode("gml:"+b,a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:{featureMember:function(a){var b=this.createElementNSPlus("gml:featureMember");this.writeNode("feature:_typeName",a,b);return b},MultiPoint:function(a){var b=this.createElementNSPlus("gml:MultiPoint");a=a.components||[a];
-for(var c=0,d=a.length;c<d;++c)this.writeNode("pointMember",a[c],b);return b},pointMember:function(a){var b=this.createElementNSPlus("gml:pointMember");this.writeNode("Point",a,b);return b},MultiLineString:function(a){var b=this.createElementNSPlus("gml:MultiLineString");a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("lineStringMember",a[c],b);return b},lineStringMember:function(a){var b=this.createElementNSPlus("gml:lineStringMember");this.writeNode("LineString",a,b);return b},
-MultiPolygon:function(a){var b=this.createElementNSPlus("gml:MultiPolygon");a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("polygonMember",a[c],b);return b},polygonMember:function(a){var b=this.createElementNSPlus("gml:polygonMember");this.writeNode("Polygon",a,b);return b},GeometryCollection:function(a){for(var b=this.createElementNSPlus("gml:GeometryCollection"),c=0,d=a.components.length;c<d;++c)this.writeNode("geometryMember",a.components[c],b);return b},geometryMember:function(a){var b=
-this.createElementNSPlus("gml:geometryMember");a=this.writeNode("feature:_geometry",a);b.appendChild(a.firstChild);return b}},feature:{_typeName:function(a){var b=this.createElementNSPlus("feature:"+this.featureType,{attributes:{fid:a.fid}});a.geometry&&this.writeNode("feature:_geometry",a.geometry,b);for(var c in a.attributes){var d=a.attributes[c];null!=d&&this.writeNode("feature:_attribute",{name:c,value:d},b)}return b},_geometry:function(a){this.externalProjection&&this.internalProjection&&(a=
-a.clone().transform(this.internalProjection,this.externalProjection));var b=this.createElementNSPlus("feature:"+this.geometryName);a=this.writeNode("gml:"+this.geometryTypes[a.CLASS_NAME],a,b);this.srsName&&a.setAttribute("srsName",this.srsName);return b},_attribute:function(a){return this.createElementNSPlus("feature:"+a.name,{value:a.value})}},wfs:{FeatureCollection:function(a){for(var b=this.createElementNSPlus("wfs:FeatureCollection"),c=0,d=a.length;c<d;++c)this.writeNode("gml:featureMember",
-a[c],b);return b}}},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":"LineString","OpenLayers.Geometry.MultiLineString":"MultiLineString","OpenLayers.Geometry.Polygon":"Polygon","OpenLayers.Geometry.MultiPolygon":"MultiPolygon","OpenLayers.Geometry.Collection":"GeometryCollection"}},CLASS_NAME:"OpenLayers.Format.GML.Base"});OpenLayers.Format.GML.v3=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",curve:!1,multiCurve:!0,surface:!1,multiSurface:!0,initialize:function(a){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[a])},readers:{gml:OpenLayers.Util.applyDefaults({_inherit:function(a,b,c){if(a=parseInt(a.getAttribute("srsDimension"),10)||c&&c.srsDimension)b.srsDimension=a},featureMembers:function(a,
-b){this.readChildNodes(a,b)},Curve:function(a,b){var c={points:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);b.components||(b.components=[]);b.components.push(new OpenLayers.Geometry.LineString(c.points))},segments:function(a,b){this.readChildNodes(a,b)},LineStringSegment:function(a,b){var c={};this.readChildNodes(a,c);c.points&&Array.prototype.push.apply(b.points,c.points)},pos:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(this.regExes.splitSpace),
-c=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2]);b.points=[c]},posList:function(a,b){for(var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(this.regExes.splitSpace),d=b.srsDimension||parseInt(a.getAttribute("srsDimension")||a.getAttribute("dimension"),10)||2,e,f,g,h=Array(c.length/d),k=0,l=c.length;k<l;k+=d)e=c[k],f=c[k+1],g=2==d?void 0:c[k+2],h[k/d]=this.xy?new OpenLayers.Geometry.Point(e,f,g):new OpenLayers.Geometry.Point(f,
-e,g);b.points=h},Surface:function(a,b){this.readChildNodes(a,b)},patches:function(a,b){this.readChildNodes(a,b)},PolygonPatch:function(a,b){this.readers.gml.Polygon.apply(this,[a,b])},exterior:function(a,b){var c={};this.readChildNodes(a,c);b.outer=c.components[0]},interior:function(a,b){var c={};this.readChildNodes(a,c);b.inner.push(c.components[0])},MultiCurve:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);0<c.components.length&&(b.components=
-[new OpenLayers.Geometry.MultiLineString(c.components)])},curveMember:function(a,b){this.readChildNodes(a,b)},MultiSurface:function(a,b){var c={components:[]};this.readers.gml._inherit.apply(this,[a,c,b]);this.readChildNodes(a,c);0<c.components.length&&(b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)])},surfaceMember:function(a,b){this.readChildNodes(a,b)},surfaceMembers:function(a,b){this.readChildNodes(a,b)},pointMembers:function(a,b){this.readChildNodes(a,b)},lineStringMembers:function(a,
-b){this.readChildNodes(a,b)},polygonMembers:function(a,b){this.readChildNodes(a,b)},geometryMembers:function(a,b){this.readChildNodes(a,b)},Envelope:function(a,b){var c={points:Array(2)};this.readChildNodes(a,c);b.components||(b.components=[]);var d=c.points[0],c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))},lowerCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,[a,c]);b.points[0]=c.points[0]},upperCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,
-[a,c]);b.points[1]=c.points[0]}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){var b;b=OpenLayers.Util.isArray(a)?"featureMembers":"featureMember";a=this.writeNode("gml:"+b,a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({featureMembers:function(a){for(var b=
-this.createElementNSPlus("gml:featureMembers"),c=0,d=a.length;c<d;++c)this.writeNode("feature:_typeName",a[c],b);return b},Point:function(a){var b=this.createElementNSPlus("gml:Point");this.writeNode("pos",a,b);return b},pos:function(a){return this.createElementNSPlus("gml:pos",{value:this.xy?a.x+" "+a.y:a.y+" "+a.x})},LineString:function(a){var b=this.createElementNSPlus("gml:LineString");this.writeNode("posList",a.components,b);return b},Curve:function(a){var b=this.createElementNSPlus("gml:Curve");
-this.writeNode("segments",a,b);return b},segments:function(a){var b=this.createElementNSPlus("gml:segments");this.writeNode("LineStringSegment",a,b);return b},LineStringSegment:function(a){var b=this.createElementNSPlus("gml:LineStringSegment");this.writeNode("posList",a.components,b);return b},posList:function(a){for(var b=a.length,c=Array(b),d,e=0;e<b;++e)d=a[e],c[e]=this.xy?d.x+" "+d.y:d.y+" "+d.x;return this.createElementNSPlus("gml:posList",{value:c.join(" ")})},Surface:function(a){var b=this.createElementNSPlus("gml:Surface");
-this.writeNode("patches",a,b);return b},patches:function(a){var b=this.createElementNSPlus("gml:patches");this.writeNode("PolygonPatch",a,b);return b},PolygonPatch:function(a){var b=this.createElementNSPlus("gml:PolygonPatch",{attributes:{interpolation:"planar"}});this.writeNode("exterior",a.components[0],b);for(var c=1,d=a.components.length;c<d;++c)this.writeNode("interior",a.components[c],b);return b},Polygon:function(a){var b=this.createElementNSPlus("gml:Polygon");this.writeNode("exterior",a.components[0],
-b);for(var c=1,d=a.components.length;c<d;++c)this.writeNode("interior",a.components[c],b);return b},exterior:function(a){var b=this.createElementNSPlus("gml:exterior");this.writeNode("LinearRing",a,b);return b},interior:function(a){var b=this.createElementNSPlus("gml:interior");this.writeNode("LinearRing",a,b);return b},LinearRing:function(a){var b=this.createElementNSPlus("gml:LinearRing");this.writeNode("posList",a.components,b);return b},MultiCurve:function(a){var b=this.createElementNSPlus("gml:MultiCurve");
-a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("curveMember",a[c],b);return b},curveMember:function(a){var b=this.createElementNSPlus("gml:curveMember");this.curve?this.writeNode("Curve",a,b):this.writeNode("LineString",a,b);return b},MultiSurface:function(a){var b=this.createElementNSPlus("gml:MultiSurface");a=a.components||[a];for(var c=0,d=a.length;c<d;++c)this.writeNode("surfaceMember",a[c],b);return b},surfaceMember:function(a){var b=this.createElementNSPlus("gml:surfaceMember");
-this.surface?this.writeNode("Surface",a,b):this.writeNode("Polygon",a,b);return b},Envelope:function(a){var b=this.createElementNSPlus("gml:Envelope");this.writeNode("lowerCorner",a,b);this.writeNode("upperCorner",a,b);this.srsName&&b.setAttribute("srsName",this.srsName);return b},lowerCorner:function(a){return this.createElementNSPlus("gml:lowerCorner",{value:this.xy?a.left+" "+a.bottom:a.bottom+" "+a.left})},upperCorner:function(a){return this.createElementNSPlus("gml:upperCorner",{value:this.xy?
-a.right+" "+a.top:a.top+" "+a.right})}},OpenLayers.Format.GML.Base.prototype.writers.gml),feature:OpenLayers.Format.GML.Base.prototype.writers.feature,wfs:OpenLayers.Format.GML.Base.prototype.writers.wfs},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":!0===this.curve?"Curve":"LineString","OpenLayers.Geometry.MultiLineString":!1===this.multiCurve?"MultiLineString":"MultiCurve","OpenLayers.Geometry.Polygon":!0===
-this.surface?"Surface":"Polygon","OpenLayers.Geometry.MultiPolygon":!1===this.multiSurface?"MultiPolygon":"MultiSurface","OpenLayers.Geometry.Collection":"GeometryCollection"}},CLASS_NAME:"OpenLayers.Format.GML.v3"});OpenLayers.Format.Filter.v1_1_0=OpenLayers.Class(OpenLayers.Format.GML.v3,OpenLayers.Format.Filter.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.1.0/filter.xsd",initialize:function(a){OpenLayers.Format.GML.v3.prototype.initialize.apply(this,[a])},readers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a,b){var c=a.getAttribute("matchCase"),c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,matchCase:!("false"===c||"0"===c)});this.readChildNodes(a,
-c);b.filters.push(c)},PropertyIsNotEqualTo:function(a,b){var c=a.getAttribute("matchCase"),c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO,matchCase:!("false"===c||"0"===c)});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLike:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(a,c);var d=a.getAttribute("wildCard"),e=a.getAttribute("singleChar"),f=a.getAttribute("escapeChar");c.value2regex(d,e,
-f);b.filters.push(c)}},OpenLayers.Format.Filter.v1.prototype.readers.ogc),gml:OpenLayers.Format.GML.v3.prototype.readers.gml,feature:OpenLayers.Format.GML.v3.prototype.readers.feature},writers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsEqualTo",{attributes:{matchCase:a.matchCase}});this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsNotEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNotEqualTo",
-{attributes:{matchCase:a.matchCase}});this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLike:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{matchCase:a.matchCase,wildCard:"*",singleChar:".",escapeChar:"!"}});this.writeNode("PropertyName",a,b);this.writeNode("Literal",a.regex2value(),b);return b},BBOX:function(a){var b=this.createElementNSPlus("ogc:BBOX");a.property&&this.writeNode("PropertyName",a,b);var c=this.writeNode("gml:Envelope",
-a.value);a.projection&&c.setAttribute("srsName",a.projection);b.appendChild(c);return b},SortBy:function(a){for(var b=this.createElementNSPlus("ogc:SortBy"),c=0,d=a.length;c<d;c++)this.writeNode("ogc:SortProperty",a[c],b);return b},SortProperty:function(a){var b=this.createElementNSPlus("ogc:SortProperty");this.writeNode("ogc:PropertyName",a,b);this.writeNode("ogc:SortOrder","DESC"==a.order?"DESC":"ASC",b);return b},SortOrder:function(a){return this.createElementNSPlus("ogc:SortOrder",{value:a})}},
-OpenLayers.Format.Filter.v1.prototype.writers.ogc),gml:OpenLayers.Format.GML.v3.prototype.writers.gml,feature:OpenLayers.Format.GML.v3.prototype.writers.feature},writeSpatial:function(a,b){var c=this.createElementNSPlus("ogc:"+b);this.writeNode("PropertyName",a,c);if(a.value instanceof OpenLayers.Filter.Function)this.writeNode("Function",a.value,c);else{var d;d=a.value instanceof OpenLayers.Geometry?this.writeNode("feature:_geometry",a.value).firstChild:this.writeNode("gml:Envelope",a.value);a.projection&&
-d.setAttribute("srsName",a.projection);c.appendChild(d)}return c},CLASS_NAME:"OpenLayers.Format.Filter.v1_1_0"});OpenLayers.Format.OWSCommon=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",getVersion:function(a,b){var c=this.version;if(!c){var d=a.getAttribute("xmlns:ows");d&&"1.1"===d.substring(d.lastIndexOf("/")+1)&&(c="1.1.0");c||(c=this.defaultVersion)}return c},CLASS_NAME:"OpenLayers.Format.OWSCommon"});OpenLayers.Format.OWSCommon.v1=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a,b){OpenLayers.Util.applyDefaults(b,this.options);var c={};this.readChildNodes(a,c);return c},readers:{ows:{Exception:function(a,b){var c={code:a.getAttribute("exceptionCode"),locator:a.getAttribute("locator"),texts:[]};b.exceptions.push(c);this.readChildNodes(a,c)},ExceptionText:function(a,b){var c=this.getChildValue(a);b.texts.push(c)},
-ServiceIdentification:function(a,b){b.serviceIdentification={};this.readChildNodes(a,b.serviceIdentification)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},Keywords:function(a,b){b.keywords={};this.readChildNodes(a,b.keywords)},Keyword:function(a,b){b[this.getChildValue(a)]=!0},ServiceType:function(a,b){b.serviceType={codeSpace:a.getAttribute("codeSpace"),value:this.getChildValue(a)}},ServiceTypeVersion:function(a,b){b.serviceTypeVersion=
-this.getChildValue(a)},Fees:function(a,b){b.fees=this.getChildValue(a)},AccessConstraints:function(a,b){b.accessConstraints=this.getChildValue(a)},ServiceProvider:function(a,b){b.serviceProvider={};this.readChildNodes(a,b.serviceProvider)},ProviderName:function(a,b){b.providerName=this.getChildValue(a)},ProviderSite:function(a,b){b.providerSite=this.getAttributeNS(a,this.namespaces.xlink,"href")},ServiceContact:function(a,b){b.serviceContact={};this.readChildNodes(a,b.serviceContact)},IndividualName:function(a,
-b){b.individualName=this.getChildValue(a)},PositionName:function(a,b){b.positionName=this.getChildValue(a)},ContactInfo:function(a,b){b.contactInfo={};this.readChildNodes(a,b.contactInfo)},Phone:function(a,b){b.phone={};this.readChildNodes(a,b.phone)},Voice:function(a,b){b.voice=this.getChildValue(a)},Address:function(a,b){b.address={};this.readChildNodes(a,b.address)},DeliveryPoint:function(a,b){b.deliveryPoint=this.getChildValue(a)},City:function(a,b){b.city=this.getChildValue(a)},AdministrativeArea:function(a,
-b){b.administrativeArea=this.getChildValue(a)},PostalCode:function(a,b){b.postalCode=this.getChildValue(a)},Country:function(a,b){b.country=this.getChildValue(a)},ElectronicMailAddress:function(a,b){b.electronicMailAddress=this.getChildValue(a)},Role:function(a,b){b.role=this.getChildValue(a)},OperationsMetadata:function(a,b){b.operationsMetadata={};this.readChildNodes(a,b.operationsMetadata)},Operation:function(a,b){var c=a.getAttribute("name");b[c]={};this.readChildNodes(a,b[c])},DCP:function(a,
-b){b.dcp={};this.readChildNodes(a,b.dcp)},HTTP:function(a,b){b.http={};this.readChildNodes(a,b.http)},Get:function(a,b){b.get||(b.get=[]);var c={url:this.getAttributeNS(a,this.namespaces.xlink,"href")};this.readChildNodes(a,c);b.get.push(c)},Post:function(a,b){b.post||(b.post=[]);var c={url:this.getAttributeNS(a,this.namespaces.xlink,"href")};this.readChildNodes(a,c);b.post.push(c)},Parameter:function(a,b){b.parameters||(b.parameters={});var c=a.getAttribute("name");b.parameters[c]={};this.readChildNodes(a,
-b.parameters[c])},Constraint:function(a,b){b.constraints||(b.constraints={});var c=a.getAttribute("name");b.constraints[c]={};this.readChildNodes(a,b.constraints[c])},Value:function(a,b){b[this.getChildValue(a)]=!0},OutputFormat:function(a,b){b.formats.push({value:this.getChildValue(a)});this.readChildNodes(a,b)},WGS84BoundingBox:function(a,b){var c={};c.crs=a.getAttribute("crs");b.BoundingBox?b.BoundingBox.push(c):(b.projection=c.crs,c=b);this.readChildNodes(a,c)},BoundingBox:function(a,b){this.readers.ows.WGS84BoundingBox.apply(this,
-[a,b])},LowerCorner:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace);b.left=c[0];b.bottom=c[1]},UpperCorner:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace);b.right=c[0];b.top=c[1];b.bounds=new OpenLayers.Bounds(b.left,b.bottom,b.right,b.top);delete b.left;delete b.bottom;delete b.right;delete b.top},
-Language:function(a,b){b.language=this.getChildValue(a)}}},writers:{ows:{BoundingBox:function(a,b){var c=this.createElementNSPlus(b||"ows:BoundingBox",{attributes:{crs:a.projection}});this.writeNode("ows:LowerCorner",a,c);this.writeNode("ows:UpperCorner",a,c);return c},LowerCorner:function(a){return this.createElementNSPlus("ows:LowerCorner",{value:a.bounds.left+" "+a.bounds.bottom})},UpperCorner:function(a){return this.createElementNSPlus("ows:UpperCorner",{value:a.bounds.right+" "+a.bounds.top})},
-Identifier:function(a){return this.createElementNSPlus("ows:Identifier",{value:a})},Title:function(a){return this.createElementNSPlus("ows:Title",{value:a})},Abstract:function(a){return this.createElementNSPlus("ows:Abstract",{value:a})},OutputFormat:function(a){return this.createElementNSPlus("ows:OutputFormat",{value:a})}}},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1"});OpenLayers.Format.OWSCommon.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows",xlink:"http://www.w3.org/1999/xlink"},readers:{ows:OpenLayers.Util.applyDefaults({ExceptionReport:function(a,b){b.success=!1;b.exceptionReport={version:a.getAttribute("version"),language:a.getAttribute("language"),exceptions:[]};this.readChildNodes(a,b.exceptionReport)}},OpenLayers.Format.OWSCommon.v1.prototype.readers.ows)},writers:{ows:OpenLayers.Format.OWSCommon.v1.prototype.writers.ows},
-CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_0_0"});OpenLayers.Format.WFST.v1_1_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_1_0,OpenLayers.Format.WFST.v1,{version:"1.1.0",schemaLocations:{wfs:"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"},initialize:function(a){OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this,[a]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[a])},readNode:function(a,b,c){return OpenLayers.Format.GML.v3.prototype.readNode.apply(this,arguments)},readers:{wfs:OpenLayers.Util.applyDefaults({FeatureCollection:function(a,
-b){b.numberOfFeatures=parseInt(a.getAttribute("numberOfFeatures"));OpenLayers.Format.WFST.v1.prototype.readers.wfs.FeatureCollection.apply(this,arguments)},TransactionResponse:function(a,b){b.insertIds=[];b.success=!1;this.readChildNodes(a,b)},TransactionSummary:function(a,b){b.success=!0},InsertResults:function(a,b){this.readChildNodes(a,b)},Feature:function(a,b){var c={fids:[]};this.readChildNodes(a,c);b.insertIds.push(c.fids[0])}},OpenLayers.Format.WFST.v1.prototype.readers.wfs),gml:OpenLayers.Format.GML.v3.prototype.readers.gml,
-feature:OpenLayers.Format.GML.v3.prototype.readers.feature,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.readers.ogc,ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows},writers:{wfs:OpenLayers.Util.applyDefaults({GetFeature:function(a){var b=OpenLayers.Format.WFST.v1.prototype.writers.wfs.GetFeature.apply(this,arguments);a&&this.setAttributes(b,{resultType:a.resultType,startIndex:a.startIndex,count:a.count});return b},Query:function(a){a=OpenLayers.Util.extend({featureNS:this.featureNS,
-featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName},a);var b=a.featurePrefix,c=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(b?b+":":"")+a.featureType,srsName:a.srsName}});a.featureNS&&c.setAttribute("xmlns:"+b,a.featureNS);if(a.propertyNames)for(var b=0,d=a.propertyNames.length;b<d;b++)this.writeNode("wfs:PropertyName",{property:a.propertyNames[b]},c);a.filter&&(OpenLayers.Format.WFST.v1_1_0.prototype.setFilterProperty.call(this,a.filter),this.writeNode("ogc:Filter",
-a.filter,c));return c},PropertyName:function(a){return this.createElementNSPlus("wfs:PropertyName",{value:a.property})}},OpenLayers.Format.WFST.v1.prototype.writers.wfs),gml:OpenLayers.Format.GML.v3.prototype.writers.gml,feature:OpenLayers.Format.GML.v3.prototype.writers.feature,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc},CLASS_NAME:"OpenLayers.Format.WFST.v1_1_0"});OpenLayers.Protocol=OpenLayers.Class({format:null,options:null,autoDestroy:!0,defaultFilter:null,initialize:function(a){a=a||{};OpenLayers.Util.extend(this,a);this.options=a},mergeWithDefaultFilter:function(a){return a&&this.defaultFilter?new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.defaultFilter,a]}):a||this.defaultFilter||void 0},destroy:function(){this.format=this.options=null},read:function(a){a=a||{};a.filter=this.mergeWithDefaultFilter(a.filter)},create:function(){},
-update:function(){},"delete":function(){},commit:function(){},abort:function(a){},createCallback:function(a,b,c){return OpenLayers.Function.bind(function(){a.apply(this,[b,c])},this)},CLASS_NAME:"OpenLayers.Protocol"});OpenLayers.Protocol.Response=OpenLayers.Class({code:null,requestType:null,last:!0,features:null,data:null,reqFeatures:null,priv:null,error:null,initialize:function(a){OpenLayers.Util.extend(this,a)},success:function(){return 0<this.code},CLASS_NAME:"OpenLayers.Protocol.Response"});
-OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:" ",space:" ",newline:"\n",level:0,pretty:!1,nativeJSON:function(){return!(!window.JSON||"function"!=typeof JSON.parse||"function"!=typeof JSON.stringify)}(),read:function(a,b){var c;if(this.nativeJSON)c=JSON.parse(a,b);else try{if(/^[\],:{}\s]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))&&(c=eval("("+a+")"),"function"===
-typeof b)){var d=function(a,c){if(c&&"object"===typeof c)for(var e in c)c.hasOwnProperty(e)&&(c[e]=d(e,c[e]));return b(a,c)};c=d("",c)}}catch(e){}this.keepData&&(this.data=c);return c},write:function(a,b){this.pretty=!!b;var c=null,d=typeof a;if(this.serialize[d])try{c=!this.pretty&&this.nativeJSON?JSON.stringify(a):this.serialize[d].apply(this,[a])}catch(e){OpenLayers.Console.error("Trouble serializing: "+e)}return c},writeIndent:function(){var a=[];if(this.pretty)for(var b=0;b<this.level;++b)a.push(this.indent);
-return a.join("")},writeNewline:function(){return this.pretty?this.newline:""},writeSpace:function(){return this.pretty?this.space:""},serialize:{object:function(a){if(null==a)return"null";if(a.constructor==Date)return this.serialize.date.apply(this,[a]);if(a.constructor==Array)return this.serialize.array.apply(this,[a]);var b=["{"];this.level+=1;var c,d,e,f=!1;for(c in a)a.hasOwnProperty(c)&&(d=OpenLayers.Format.JSON.prototype.write.apply(this,[c,this.pretty]),e=OpenLayers.Format.JSON.prototype.write.apply(this,
-[a[c],this.pretty]),null!=d&&null!=e&&(f&&b.push(","),b.push(this.writeNewline(),this.writeIndent(),d,":",this.writeSpace(),e),f=!0));this.level-=1;b.push(this.writeNewline(),this.writeIndent(),"}");return b.join("")},array:function(a){var b,c=["["];this.level+=1;for(var d=0,e=a.length;d<e;++d)b=OpenLayers.Format.JSON.prototype.write.apply(this,[a[d],this.pretty]),null!=b&&(0<d&&c.push(","),c.push(this.writeNewline(),this.writeIndent(),b));this.level-=1;c.push(this.writeNewline(),this.writeIndent(),
-"]");return c.join("")},string:function(a){var b={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return/["\\\x00-\x1f]/.test(a)?'"'+a.replace(/([\x00-\x1f\\"])/g,function(a,d){var e=b[d];if(e)return e;e=d.charCodeAt();return"\\u00"+Math.floor(e/16).toString(16)+(e%16).toString(16)})+'"':'"'+a+'"'},number:function(a){return isFinite(a)?String(a):"null"},"boolean":function(a){return String(a)},date:function(a){function b(a){return 10>a?"0"+a:a}return'"'+a.getFullYear()+
-"-"+b(a.getMonth()+1)+"-"+b(a.getDate())+"T"+b(a.getHours())+":"+b(a.getMinutes())+":"+b(a.getSeconds())+'"'}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:!1,read:function(a,b,c){b=b?b:"FeatureCollection";var d=null,e=null,e="string"==typeof a?OpenLayers.Format.JSON.prototype.read.apply(this,[a,c]):a;if(!e)OpenLayers.Console.error("Bad JSON: "+a);else if("string"!=typeof e.type)OpenLayers.Console.error("Bad GeoJSON - no type: "+a);else if(this.isValidType(e,b))switch(b){case "Geometry":try{d=this.parseGeometry(e)}catch(f){OpenLayers.Console.error(f)}break;case "Feature":try{d=
-this.parseFeature(e),d.type="Feature"}catch(g){OpenLayers.Console.error(g)}break;case "FeatureCollection":switch(d=[],e.type){case "Feature":try{d.push(this.parseFeature(e))}catch(h){d=null,OpenLayers.Console.error(h)}break;case "FeatureCollection":a=0;for(b=e.features.length;a<b;++a)try{d.push(this.parseFeature(e.features[a]))}catch(k){d=null,OpenLayers.Console.error(k)}break;default:try{var l=this.parseGeometry(e);d.push(new OpenLayers.Feature.Vector(l))}catch(m){d=null,OpenLayers.Console.error(m)}}}return d},
-isValidType:function(a,b){var c=!1;switch(b){case "Geometry":-1==OpenLayers.Util.indexOf("Point MultiPoint LineString MultiLineString Polygon MultiPolygon Box GeometryCollection".split(" "),a.type)?OpenLayers.Console.error("Unsupported geometry type: "+a.type):c=!0;break;case "FeatureCollection":c=!0;break;default:a.type==b?c=!0:OpenLayers.Console.error("Cannot convert types from "+a.type+" to "+b)}return c},parseFeature:function(a){var b,c,d;c=a.properties?a.properties:{};d=a.geometry&&a.geometry.bbox||
-a.bbox;try{b=this.parseGeometry(a.geometry)}catch(e){throw e;}b=new OpenLayers.Feature.Vector(b,c);d&&(b.bounds=OpenLayers.Bounds.fromArray(d));a.id&&(b.fid=a.id);return b},parseGeometry:function(a){if(null==a)return null;var b,c=!1;if("GeometryCollection"==a.type){if(!OpenLayers.Util.isArray(a.geometries))throw"GeometryCollection must have geometries array: "+a;b=a.geometries.length;for(var c=Array(b),d=0;d<b;++d)c[d]=this.parseGeometry.apply(this,[a.geometries[d]]);b=new OpenLayers.Geometry.Collection(c);
-c=!0}else{if(!OpenLayers.Util.isArray(a.coordinates))throw"Geometry must have coordinates array: "+a;if(!this.parseCoords[a.type.toLowerCase()])throw"Unsupported geometry type: "+a.type;try{b=this.parseCoords[a.type.toLowerCase()].apply(this,[a.coordinates])}catch(e){throw e;}}this.internalProjection&&(this.externalProjection&&!c)&&b.transform(this.externalProjection,this.internalProjection);return b},parseCoords:{point:function(a){if(!1==this.ignoreExtraDims&&2!=a.length)throw"Only 2D points are supported: "+
-a;return new OpenLayers.Geometry.Point(a[0],a[1])},multipoint:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.point.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiPoint(b)},linestring:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.point.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.LineString(b)},multilinestring:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=
-this.parseCoords.linestring.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiLineString(b)},polygon:function(a){for(var b=[],c,d,e=0,f=a.length;e<f;++e){try{d=this.parseCoords.linestring.apply(this,[a[e]])}catch(g){throw g;}c=new OpenLayers.Geometry.LinearRing(d.components);b.push(c)}return new OpenLayers.Geometry.Polygon(b)},multipolygon:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.polygon.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiPolygon(b)},
-box:function(a){if(2!=a.length)throw"GeoJSON box coordinates must have 2 elements";return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(a[0][0],a[0][1]),new OpenLayers.Geometry.Point(a[1][0],a[0][1]),new OpenLayers.Geometry.Point(a[1][0],a[1][1]),new OpenLayers.Geometry.Point(a[0][0],a[1][1]),new OpenLayers.Geometry.Point(a[0][0],a[0][1])])])}},write:function(a,b){var c={type:null};if(OpenLayers.Util.isArray(a)){c.type="FeatureCollection";var d=
-a.length;c.features=Array(d);for(var e=0;e<d;++e){var f=a[e];if(!f instanceof OpenLayers.Feature.Vector)throw"FeatureCollection only supports collections of features: "+f;c.features[e]=this.extract.feature.apply(this,[f])}}else 0==a.CLASS_NAME.indexOf("OpenLayers.Geometry")?c=this.extract.geometry.apply(this,[a]):a instanceof OpenLayers.Feature.Vector&&(c=this.extract.feature.apply(this,[a]),a.layer&&a.layer.projection&&(c.crs=this.createCRSObject(a)));return OpenLayers.Format.JSON.prototype.write.apply(this,
-[c,b])},createCRSObject:function(a){a=a.layer.projection.toString();var b={};a.match(/epsg:/i)&&(a=parseInt(a.substring(a.indexOf(":")+1)),b=4326==a?{type:"name",properties:{name:"urn:ogc:def:crs:OGC:1.3:CRS84"}}:{type:"name",properties:{name:"EPSG:"+a}});return b},extract:{feature:function(a){var b=this.extract.geometry.apply(this,[a.geometry]),b={type:"Feature",properties:a.attributes,geometry:b};null!=a.fid&&(b.id=a.fid);return b},geometry:function(a){if(null==a)return null;this.internalProjection&&
-this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b=a.CLASS_NAME.split(".")[2];a=this.extract[b.toLowerCase()].apply(this,[a]);return"Collection"==b?{type:"GeometryCollection",geometries:a}:{type:b,coordinates:a}},point:function(a){return[a.x,a.y]},multipoint:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b},linestring:function(a){for(var b=[],c=0,d=a.components.length;c<
-d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b},multilinestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.linestring.apply(this,[a.components[c]]));return b},polygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.linestring.apply(this,[a.components[c]]));return b},multipolygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.polygon.apply(this,[a.components[c]]));return b},collection:function(a){for(var b=
-a.components.length,c=Array(b),d=0;d<b;++d)c[d]=this.extract.geometry.apply(this,[a.components[d]]);return c}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Protocol.Script=OpenLayers.Class(OpenLayers.Protocol,{url:null,params:null,callback:null,callbackTemplate:"OpenLayers.Protocol.Script.registry.${id}",callbackKey:"callback",callbackPrefix:"",scope:null,format:null,pendingRequests:null,srsInBBOX:!1,initialize:function(a){a=a||{};this.params={};this.pendingRequests={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);this.format||(this.format=new OpenLayers.Format.GeoJSON);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var b=
-new OpenLayers.Format.QueryStringFilter({srsInBBOX:this.srsInBBOX});this.filterToParams=function(a,d){return b.write(a,d)}}},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.applyDefaults(a,this.options);a.params=OpenLayers.Util.applyDefaults(a.params,this.options.params);a.filter&&this.filterToParams&&(a.params=this.filterToParams(a.filter,a.params));var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.createRequest(a.url,a.params,OpenLayers.Function.bind(function(c){b.data=
-c;this.handleRead(b,a)},this));b.priv=c;return b},createRequest:function(a,b,c){c=OpenLayers.Protocol.Script.register(c);var d=OpenLayers.String.format(this.callbackTemplate,{id:c});b=OpenLayers.Util.extend({},b);b[this.callbackKey]=this.callbackPrefix+d;a=OpenLayers.Util.urlAppend(a,OpenLayers.Util.getParameterString(b));b=document.createElement("script");b.type="text/javascript";b.src=a;b.id="OpenLayers_Protocol_Script_"+c;this.pendingRequests[b.id]=b;document.getElementsByTagName("head")[0].appendChild(b);
-return b},destroyRequest:function(a){OpenLayers.Protocol.Script.unregister(a.id.split("_").pop());delete this.pendingRequests[a.id];a.parentNode&&a.parentNode.removeChild(a)},handleRead:function(a,b){this.handleResponse(a,b)},handleResponse:function(a,b){b.callback&&(a.data?(a.features=this.parseFeatures(a.data),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE,this.destroyRequest(a.priv),b.callback.call(b.scope,a))},parseFeatures:function(a){return this.format.read(a)},
-abort:function(a){if(a)this.destroyRequest(a.priv);else for(var b in this.pendingRequests)this.destroyRequest(this.pendingRequests[b])},destroy:function(){this.abort();delete this.params;delete this.format;OpenLayers.Protocol.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Protocol.Script"});(function(){var a=OpenLayers.Protocol.Script,b=0;a.registry={};a.register=function(c){var d="c"+ ++b;a.registry[d]=function(){c.apply(this,arguments)};return d};a.unregister=function(b){delete a.registry[b]}})();OpenLayers.Format.EncodedPolyline=OpenLayers.Class(OpenLayers.Format,{geometryType:"linestring",initialize:function(a){OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){var b;if("linestring"==this.geometryType)b=OpenLayers.Geometry.LineString;else if("linearring"==this.geometryType)b=OpenLayers.Geometry.LinearRing;else if("multipoint"==this.geometryType)b=OpenLayers.Geometry.MultiPoint;else if("point"!=this.geometryType&&"polygon"!=this.geometryType)return null;a=this.decodeDeltas(a,
-2);for(var c=a.length,d=[],e=0;e+1<c;){var f=a[e++],g=a[e++];d.push(new OpenLayers.Geometry.Point(g,f))}return"point"==this.geometryType?new OpenLayers.Feature.Vector(d[0]):"polygon"==this.geometryType?new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)])):new OpenLayers.Feature.Vector(new b(d))},decode:function(a,b,c){a=this.decodeDeltas(a,b,c||1E5);c=a.length;for(var d=[],e=0;e+(b-1)<c;){for(var f=[],g=0;g<b;++g)f.push(a[e++]);d.push(f)}return d},
-write:function(a){a=(a.constructor==Array?a[0]:a).geometry;var b=a.CLASS_NAME.split(".")[2].toLowerCase();if("point"==b)a=Array(a);else if("linestring"==b||"linearring"==b||"multipoint"==b)a=a.components;else if("polygon"==b)a=a.components[0].components;else return null;for(var b=[],c=a.length,d=0;d<c;++d){var e=a[d];b.push(e.y);b.push(e.x)}return this.encodeDeltas(b,2)},encode:function(a,b,c){c=c||1E5;for(var d=[],e=a.length,f=0;f<e;++f)for(var g=a[f],h=0;h<b;++h)d.push(g[h]);return this.encodeDeltas(d,
-b,c)},encodeDeltas:function(a,b,c){var d,e=Array(b);for(d=0;d<b;++d)e[d]=0;for(var f=a.length,g=0;g<f;)for(d=0;d<b;++d,++g){var h=a[g],k=h-e[d];e[d]=h;a[g]=k}return this.encodeFloats(a,c||1E5)},decodeDeltas:function(a,b,c){var d,e=Array(b);for(d=0;d<b;++d)e[d]=0;a=this.decodeFloats(a,c||1E5);c=a.length;for(var f=0;f<c;)for(d=0;d<b;++d,++f)e[d]+=a[f],a[f]=e[d];return a},encodeFloats:function(a,b){for(var c=b||1E5,d=a.length,e=0;e<d;++e)a[e]=Math.round(a[e]*c);return this.encodeSignedIntegers(a)},decodeFloats:function(a,
-b){for(var c=b||1E5,d=this.decodeSignedIntegers(a),e=d.length,f=0;f<e;++f)d[f]/=c;return d},encodeSignedIntegers:function(a){for(var b=a.length,c=0;c<b;++c){var d=a[c],e=d<<1;0>d&&(e=~e);a[c]=e}return this.encodeUnsignedIntegers(a)},decodeSignedIntegers:function(a){a=this.decodeUnsignedIntegers(a);for(var b=a.length,c=0;c<b;++c){var d=a[c];a[c]=d&1?~(d>>1):d>>1}return a},encodeUnsignedIntegers:function(a){for(var b="",c=a.length,d=0;d<c;++d)b+=this.encodeUnsignedInteger(a[d]);return b},decodeUnsignedIntegers:function(a){for(var b=
-[],c=0,d=0,e=a.length,f=0;f<e;++f){var g=a.charCodeAt(f)-63,c=c|(g&31)<<d;32>g?(b.push(c),d=c=0):d+=5}return b},encodeFloat:function(a,b){a=Math.round(a*(b||1E5));return this.encodeSignedInteger(a)},decodeFloat:function(a,b){return this.decodeSignedInteger(a)/(b||1E5)},encodeSignedInteger:function(a){var b=a<<1;0>a&&(b=~b);return this.encodeUnsignedInteger(b)},decodeSignedInteger:function(a){a=this.decodeUnsignedInteger(a);return a&1?~(a>>1):a>>1},encodeUnsignedInteger:function(a){for(var b,c="";32<=
-a;)b=(32|a&31)+63,c+=String.fromCharCode(b),a>>=5;return c+=String.fromCharCode(a+63)},decodeUnsignedInteger:function(a){for(var b=0,c=0,d=a.length,e=0;e<d;++e){var f=a.charCodeAt(e)-63,b=b|(f&31)<<c;if(32>f)break;c+=5}return b},CLASS_NAME:"OpenLayers.Format.EncodedPolyline"});OpenLayers.Control.Panel=OpenLayers.Class(OpenLayers.Control,{controls:null,autoActivate:!0,defaultControl:null,saveState:!1,allowDepress:!1,activeState:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.controls=[];this.activeState={}},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments);for(var a,b=this.controls.length-1;0<=b;b--)a=this.controls[b],a.events&&
-a.events.un({activate:this.iconOn,deactivate:this.iconOff}),a.panel_div=null;this.activeState=null},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){for(var a,b=0,c=this.controls.length;b<c;b++)a=this.controls[b],(a===this.defaultControl||this.saveState&&this.activeState[a.id])&&a.activate();!0===this.saveState&&(this.defaultControl=null);this.redraw();return!0}return!1},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){for(var a,
-b=0,c=this.controls.length;b<c;b++)a=this.controls[b],this.activeState[a.id]=a.deactivate();this.redraw();return!0}return!1},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.outsideViewport?(this.events.attachToElement(this.div),this.events.register("buttonclick",this,this.onButtonClick)):this.map.events.register("buttonclick",this,this.onButtonClick);this.addControlsToMap(this.controls);return this.div},redraw:function(){for(var a=this.div.childNodes.length-1;0<=a;a--)this.div.removeChild(this.div.childNodes[a]);
-this.div.innerHTML="";if(this.active)for(var a=0,b=this.controls.length;a<b;a++)this.div.appendChild(this.controls[a].panel_div)},activateControl:function(a){if(!this.active)return!1;if(a.type==OpenLayers.Control.TYPE_BUTTON)a.trigger();else if(a.type==OpenLayers.Control.TYPE_TOGGLE)a.active?a.deactivate():a.activate();else if(this.allowDepress&&a.active)a.deactivate();else{for(var b,c=0,d=this.controls.length;c<d;c++)b=this.controls[c],b==a||b.type!==OpenLayers.Control.TYPE_TOOL&&null!=b.type||b.deactivate();
-a.activate()}},addControls:function(a){OpenLayers.Util.isArray(a)||(a=[a]);this.controls=this.controls.concat(a);for(var b=0,c=a.length;b<c;b++){var d=a[b],e=this.createControlMarkup(d);OpenLayers.Element.addClass(e,d.displayClass+"ItemInactive");OpenLayers.Element.addClass(e,"olButton");""==d.title||e.title||(e.title=d.title);d.panel_div=e}this.map&&(this.addControlsToMap(a),this.redraw())},createControlMarkup:function(a){return document.createElement("div")},addControlsToMap:function(a){for(var b,
-c=0,d=a.length;c<d;c++)b=a[c],!0===b.autoActivate?(b.autoActivate=!1,this.map.addControl(b),b.autoActivate=!0):(this.map.addControl(b),b.deactivate()),b.events.on({activate:this.iconOn,deactivate:this.iconOff})},iconOn:function(){var a=this.panel_div;a.className=a.className.replace(RegExp("\\b("+this.displayClass+"Item)Inactive\\b"),"$1Active")},iconOff:function(){var a=this.panel_div;a.className=a.className.replace(RegExp("\\b("+this.displayClass+"Item)Active\\b"),"$1Inactive")},onButtonClick:function(a){var b=
-this.controls;a=a.buttonElement;for(var c=b.length-1;0<=c;--c)if(b[c].panel_div===a){this.activateControl(b[c]);break}},getControlsBy:function(a,b){var c="function"==typeof b.test;return OpenLayers.Array.filter(this.controls,function(d){return d[a]==b||c&&b.test(d[a])})},getControlsByName:function(a){return this.getControlsBy("name",a)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},CLASS_NAME:"OpenLayers.Control.Panel"});OpenLayers.Control.Button=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){},CLASS_NAME:"OpenLayers.Control.Button"});OpenLayers.Control.ZoomIn=OpenLayers.Class(OpenLayers.Control.Button,{trigger:function(){this.map&&this.map.zoomIn()},CLASS_NAME:"OpenLayers.Control.ZoomIn"});OpenLayers.Control.ZoomOut=OpenLayers.Class(OpenLayers.Control.Button,{trigger:function(){this.map&&this.map.zoomOut()},CLASS_NAME:"OpenLayers.Control.ZoomOut"});OpenLayers.Control.ZoomToMaxExtent=OpenLayers.Class(OpenLayers.Control.Button,{trigger:function(){this.map&&this.map.zoomToMaxExtent()},CLASS_NAME:"OpenLayers.Control.ZoomToMaxExtent"});OpenLayers.Control.ZoomPanel=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);this.addControls([new OpenLayers.Control.ZoomIn,new OpenLayers.Control.ZoomToMaxExtent,new OpenLayers.Control.ZoomOut])},CLASS_NAME:"OpenLayers.Control.ZoomPanel"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:!1,initialize:function(a,b,c,d){OpenLayers.Layer.prototype.initialize.apply(this,[a,d]);this.url=b;this.params||(this.params=OpenLayers.Util.extend({},c))},destroy:function(){this.params=this.url=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.getOptions()));
-return a=OpenLayers.Layer.prototype.clone.apply(this,[a])},setUrl:function(a){this.url=a},mergeNewParams:function(a){this.params=OpenLayers.Util.extend(this.params,a);a=this.redraw();null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"params"});return a},redraw:function(a){return a?this.mergeNewParams({_olSalt:Math.random()}):OpenLayers.Layer.prototype.redraw.apply(this,[])},selectUrl:function(a,b){for(var c=1,d=0,e=a.length;d<e;d++)c*=a.charCodeAt(d)*this.URL_HASH_FACTOR,
-c-=Math.floor(c);return b[Math.floor(c*b.length)]},getFullRequestString:function(a,b){var c=b||this.url,d=OpenLayers.Util.extend({},this.params),d=OpenLayers.Util.extend(d,a),e=OpenLayers.Util.getParameterString(d);OpenLayers.Util.isArray(c)&&(c=this.selectUrl(e,c));var e=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),f;for(f in d)f.toUpperCase()in e&&delete d[f];e=OpenLayers.Util.getParameterString(d);return OpenLayers.Util.urlAppend(c,e)},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Tile=OpenLayers.Class({events:null,eventListeners:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:!1,initialize:function(a,b,c,d,e,f){this.layer=a;this.position=b.clone();this.setBounds(c);this.url=d;e&&(this.size=e.clone());this.id=OpenLayers.Util.createUniqueID("Tile_");OpenLayers.Util.extend(this,f);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object)this.events.on(this.eventListeners)},unload:function(){this.isLoading&&(this.isLoading=
-!1,this.events.triggerEvent("unload"))},destroy:function(){this.position=this.size=this.bounds=this.layer=null;this.eventListeners&&this.events.un(this.eventListeners);this.events.destroy();this.events=this.eventListeners=null},draw:function(a){a||this.clear();var b=this.shouldDraw();b&&(!a&&!1===this.events.triggerEvent("beforedraw"))&&(b=null);return b},shouldDraw:function(){var a=!1,b=this.layer.maxExtent;if(b){var c=this.layer.map,c=c.baseLayer.wrapDateLine&&c.getMaxExtent();this.bounds.intersectsBounds(b,
-{inclusive:!1,worldBounds:c})&&(a=!0)}return a||this.layer.displayOutsideMaxExtent},setBounds:function(a){a=a.clone();if(this.layer.map.baseLayer.wrapDateLine){var b=this.layer.map.getMaxExtent(),c=this.layer.map.getResolution();a=a.wrapDateLine(b,{leftTolerance:c,rightTolerance:c})}this.bounds=a},moveTo:function(a,b,c){null==c&&(c=!0);this.setBounds(a);this.position=b.clone();c&&this.draw()},clear:function(a){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,maxGetUrlLength:null,canvasContext:null,crossOriginKeyword:null,initialize:function(a,b,c,d,e,f){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=d;this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();if(null!=this.maxGetUrlLength||this.layer.gutter||this.layerAlphaHack)this.frame=document.createElement("div"),this.frame.style.position=
-"absolute",this.frame.style.overflow="hidden";null!=this.maxGetUrlLength&&OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame)},destroy:function(){this.imgDiv&&(this.clear(),this.frame=this.imgDiv=null);this.asyncRequestId=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.prototype.draw.apply(this,arguments);a?(this.layer!=this.layer.map.baseLayer&&this.layer.reproject&&(this.bounds=this.getBoundsFromBaseLayer(this.position)),this.isLoading?this._loadEvent=
-"reload":(this.isLoading=!0,this._loadEvent="loadstart"),this.renderTile(),this.positionTile()):!1===a&&this.unload();return a},renderTile:function(){if(this.layer.async){var a=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,function(b){a==this.asyncRequestId&&(this.url=b,this.initImage())},this)}else this.url=this.layer.getURL(this.bounds),this.initImage()},positionTile:function(){var a=this.getTile().style,b=this.frame?this.size:this.layer.getImageSize(this.bounds),
-c=1;this.layer instanceof OpenLayers.Layer.Grid&&(c=this.layer.getServerResolution()/this.layer.map.getResolution());a.left=this.position.x+"px";a.top=this.position.y+"px";a.width=Math.round(c*b.w)+"px";a.height=Math.round(c*b.h)+"px"},clear:function(){OpenLayers.Tile.prototype.clear.apply(this,arguments);var a=this.imgDiv;if(a){var b=this.getTile();b.parentNode===this.layer.div&&this.layer.div.removeChild(b);this.setImgSrc();!0===this.layerAlphaHack&&(a.style.filter="");OpenLayers.Element.removeClass(a,
-"olImageLoadError")}this.canvasContext=null},getImage:function(){if(!this.imgDiv){this.imgDiv=OpenLayers.Tile.Image.IMAGE.cloneNode(!1);var a=this.imgDiv.style;if(this.frame){var b=0,c=0;this.layer.gutter&&(b=100*(this.layer.gutter/this.layer.tileSize.w),c=100*(this.layer.gutter/this.layer.tileSize.h));a.left=-b+"%";a.top=-c+"%";a.width=2*b+100+"%";a.height=2*c+100+"%"}a.visibility="hidden";a.opacity=0;1>this.layer.opacity&&(a.filter="alpha(opacity="+100*this.layer.opacity+")");a.position="absolute";
-this.layerAlphaHack&&(a.paddingTop=a.height,a.height="0",a.width="100%");this.frame&&this.frame.appendChild(this.imgDiv)}return this.imgDiv},setImage:function(a){this.imgDiv=a},initImage:function(){if(this.url||this.imgDiv){this.events.triggerEvent("beforeload");this.layer.div.appendChild(this.getTile());this.events.triggerEvent(this._loadEvent);var a=this.getImage(),b=a.getAttribute("src")||"";this.url&&OpenLayers.Util.isEquivalentUrl(b,this.url)?this._loadTimeout=window.setTimeout(OpenLayers.Function.bind(this.onImageLoad,
-this),0):(this.stopLoading(),this.crossOriginKeyword&&a.removeAttribute("crossorigin"),OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,this)),OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError,this)),this.imageReloadAttempts=0,this.setImgSrc(this.url))}else this.isLoading=!1},setImgSrc:function(a){var b=this.imgDiv;a?(b.style.visibility="hidden",b.style.opacity=0,this.crossOriginKeyword&&("data:"!==a.substr(0,5)?b.setAttribute("crossorigin",this.crossOriginKeyword):
-b.removeAttribute("crossorigin")),b.src=a):(this.stopLoading(),this.imgDiv=null,b.parentNode&&b.parentNode.removeChild(b))},getTile:function(){return this.frame?this.frame:this.getImage()},createBackBuffer:function(){if(this.imgDiv&&!this.isLoading){var a;this.frame?(a=this.frame.cloneNode(!1),a.appendChild(this.imgDiv)):a=this.imgDiv;this.imgDiv=null;return a}},onImageLoad:function(){var a=this.imgDiv;this.stopLoading();a.style.visibility="inherit";a.style.opacity=this.layer.opacity;this.isLoading=
-!1;this.canvasContext=null;this.events.triggerEvent("loadend");!0===this.layerAlphaHack&&(a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a.src+"', sizingMethod='scale')")},onImageError:function(){var a=this.imgDiv;null!=a.src&&(this.imageReloadAttempts++,this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)):(OpenLayers.Element.addClass(a,"olImageLoadError"),this.events.triggerEvent("loaderror"),this.onImageLoad()))},stopLoading:function(){OpenLayers.Event.stopObservingElement(this.imgDiv);
-window.clearTimeout(this._loadTimeout);delete this._loadTimeout},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var a=document.createElement("canvas");a.width=this.size.w;a.height=this.size.h;this.canvasContext=a.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0)}return this.canvasContext}},CLASS_NAME:"OpenLayers.Tile.Image"});
-OpenLayers.Tile.Image.IMAGE=function(){var a=new Image;a.className="olTileImage";a.galleryImg="no";return a}();OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:!1,ratio:1.5,buffer:0,transitionEffect:"resize",numLoadingTiles:0,serverResolutions:null,loading:!1,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null,className:null,gridLayout:null,rowSign:null,transitionendEvents:["transitionend",
-"webkitTransitionEnd","otransitionend","oTransitionEnd"],initialize:function(a,b,c,d){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this._removeBackBuffer=OpenLayers.Function.bind(this.removeBackBuffer,this);this.initProperties();this.rowSign="t"===this.tileOriginCorner.substr(0,1)?1:-1},initProperties:function(){void 0===this.options.removeBackBufferDelay&&(this.removeBackBufferDelay=this.singleTile?0:2500);void 0===this.options.className&&(this.className=this.singleTile?
-"olLayerGridSingleTile":"olLayerGrid")},setMap:function(a){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this,a);OpenLayers.Element.addClass(this.div,this.className)},removeMap:function(a){this.removeBackBuffer()},destroy:function(){this.removeBackBuffer();this.clearGrid();this.tileSize=this.grid=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments)},clearGrid:function(){if(this.grid){for(var a=0,b=this.grid.length;a<b;a++)for(var c=this.grid[a],d=0,e=c.length;d<e;d++)this.destroyTile(c[d]);
-this.grid=[];this.gridLayout=this.gridResolution=null}},addOptions:function(a,b){var c=void 0!==a.singleTile&&a.singleTile!==this.singleTile;OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this,arguments);this.map&&c&&(this.initProperties(),this.clearGrid(),this.tileSize=this.options.tileSize,this.setTileSize(),this.moveTo(null,!0))},clone:function(a){null==a&&(a=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.getOptions()));a=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,
-[a]);null!=this.tileSize&&(a.tileSize=this.tileSize.clone());a.grid=[];a.gridResolution=null;a.backBuffer=null;a.backBufferTimerId=null;a.loading=!1;a.numLoadingTiles=0;return a},moveTo:function(a,b,c){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);a=a||this.map.getExtent();if(null!=a){var d=!this.grid.length||b,e=this.getTilesBounds(),f=this.map.getResolution();this.getServerResolution(f);if(this.singleTile){if(d||!c&&!e.containsBounds(a))b&&"resize"!==this.transitionEffect&&
-this.removeBackBuffer(),b&&"resize"!==this.transitionEffect||this.applyBackBuffer(f),this.initSingleTile(a)}else(d=d||!e.intersectsBounds(a,{worldBounds:this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent()}))?(!b||"resize"!==this.transitionEffect&&this.gridResolution!==f||this.applyBackBuffer(f),this.initGriddedTiles(a)):this.moveGriddedTiles()}},getTileData:function(a){var b=null,c=a.lon,d=a.lat,e=this.grid.length;if(this.map&&e){var f=this.map.getResolution();a=this.tileSize.w;var g=this.tileSize.h,
-h=this.grid[0][0].bounds,k=h.left,h=h.top;if(c<k&&this.map.baseLayer.wrapDateLine)var l=this.map.getMaxExtent().getWidth(),m=Math.ceil((k-c)/l),c=c+l*m;c=(c-k)/(f*a);d=(h-d)/(f*g);f=Math.floor(c);k=Math.floor(d);0<=k&&k<e&&(e=this.grid[k][f])&&(b={tile:e,i:Math.floor((c-f)*a),j:Math.floor((d-k)*g)})}return b},destroyTile:function(a){this.removeTileMonitoringHooks(a);a.destroy()},getServerResolution:function(a){var b=Number.POSITIVE_INFINITY;a=a||this.map.getResolution();if(this.serverResolutions&&
--1===OpenLayers.Util.indexOf(this.serverResolutions,a)){var c,d,e,f;for(c=this.serverResolutions.length-1;0<=c;c--){e=this.serverResolutions[c];d=Math.abs(e-a);if(d>b)break;b=d;f=e}a=f}return a},getServerZoom:function(){var a=this.getServerResolution();return this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,a):this.map.getZoomForResolution(a)+(this.zoomOffset||0)},applyBackBuffer:function(a){null!==this.backBufferTimerId&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=
-this.createBackBuffer();if(!b)return;a===this.gridResolution?this.div.insertBefore(b,this.div.firstChild):this.map.baseLayer.div.parentNode.insertBefore(b,this.map.baseLayer.div);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}for(var c=this.backBufferResolution/a,d=b.childNodes,e,f=d.length-1;0<=f;--f)e=d[f],e.style.top=(c*e._i*e._h|0)+"px",e.style.left=(c*e._j*e._w|0)+"px",e.style.width=Math.round(c*e._w)+
-"px",e.style.height=Math.round(c*e._h)+"px";a=this.getViewPortPxFromLonLat(this.backBufferLonLat,a);c=this.map.layerContainerOriginPx.y;b.style.left=Math.round(a.x-this.map.layerContainerOriginPx.x)+"px";b.style.top=Math.round(a.y-c)+"px"},createBackBuffer:function(){var a;if(0<this.grid.length){a=document.createElement("div");a.id=this.div.id+"_bb";a.className="olBackBuffer";a.style.position="absolute";var b=this.map;a.style.zIndex="resize"===this.transitionEffect?this.getZIndex()-1:b.Z_INDEX_BASE.BaseLayer-
-(b.getNumLayers()-b.getLayerIndex(this));for(var b=0,c=this.grid.length;b<c;b++)for(var d=0,e=this.grid[b].length;d<e;d++){var f=this.grid[b][d],g=this.grid[b][d].createBackBuffer();g&&(g._i=b,g._j=d,g._w=f.size.w,g._h=f.size.h,g.id=f.id+"_bb",a.appendChild(g))}}return a},removeBackBuffer:function(){if(this._transitionElement){for(var a=this.transitionendEvents.length-1;0<=a;--a)OpenLayers.Event.stopObserving(this._transitionElement,this.transitionendEvents[a],this._removeBackBuffer);delete this._transitionElement}this.backBuffer&&
-(this.backBuffer.parentNode&&this.backBuffer.parentNode.removeChild(this.backBuffer),this.backBufferResolution=this.backBuffer=null,null!==this.backBufferTimerId&&(window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null))},moveByPx:function(a,b){this.singleTile||this.moveGriddedTiles()},setTileSize:function(a){this.singleTile&&(a=this.map.getSize(),a.h=parseInt(a.h*this.ratio,10),a.w=parseInt(a.w*this.ratio,10));OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[a])},getTilesBounds:function(){var a=
-null,b=this.grid.length;if(b)var a=this.grid[b-1][0].bounds,b=this.grid[0].length*a.getWidth(),c=this.grid.length*a.getHeight(),a=new OpenLayers.Bounds(a.left,a.bottom,a.left+b,a.bottom+c);return a},initSingleTile:function(a){this.events.triggerEvent("retile");var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio;a=a.getHeight()*this.ratio;b=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2);c=this.map.getLayerPxFromLonLat({lon:b.left,lat:b.top});this.grid.length||(this.grid[0]=[]);(a=this.grid[0][0])?
-a.moveTo(b,c):(a=this.addTile(b,c),this.addTileMonitoringHooks(a),a.draw(),this.grid[0][0]=a);this.removeExcessTiles(1,1);this.gridResolution=this.getServerResolution()},calculateGridLayout:function(a,b,c){var d=c*this.tileSize.w;c*=this.tileSize.h;var e=Math.floor((a.left-b.lon)/d)-this.buffer,f=this.rowSign;a=Math[~f?"floor":"ceil"](f*(b.lat-a.top+c)/c)-this.buffer*f;return{tilelon:d,tilelat:c,startcol:e,startrow:a}},getTileOrigin:function(){var a=this.tileOrigin;if(!a)var a=this.getMaxExtent(),
-b={tl:["left","top"],tr:["right","top"],bl:["left","bottom"],br:["right","bottom"]}[this.tileOriginCorner],a=new OpenLayers.LonLat(a[b[0]],a[b[1]]);return a},getTileBoundsForGridIndex:function(a,b){var c=this.getTileOrigin(),d=this.gridLayout,e=d.tilelon,f=d.tilelat,g=d.startcol,d=d.startrow,h=this.rowSign;return new OpenLayers.Bounds(c.lon+(g+b)*e,c.lat-(d+a*h)*f*h,c.lon+(g+b+1)*e,c.lat-(d+(a-1)*h)*f*h)},initGriddedTiles:function(a){this.events.triggerEvent("retile");var b=this.map.getSize(),c=this.getTileOrigin(),
-d=this.map.getResolution(),e=this.getServerResolution(),f=d/e,d=this.tileSize.w/f,f=this.tileSize.h/f,g=Math.ceil(b.h/f)+2*this.buffer+1,b=Math.ceil(b.w/d)+2*this.buffer+1;this.gridLayout=e=this.calculateGridLayout(a,c,e);var c=e.tilelon,h=e.tilelat,e=this.map.layerContainerOriginPx.x,k=this.map.layerContainerOriginPx.y,l=this.getTileBoundsForGridIndex(0,0),m=this.map.getViewPortPxFromLonLat(new OpenLayers.LonLat(l.left,l.top));m.x=Math.round(m.x)-e;m.y=Math.round(m.y)-k;var e=[],k=this.map.getCenter(),
-n=0;do{var p=this.grid[n];p||(p=[],this.grid.push(p));var q=0;do{var l=this.getTileBoundsForGridIndex(n,q),r=m.clone();r.x+=q*Math.round(d);r.y+=n*Math.round(f);var s=p[q];s?s.moveTo(l,r,!1):(s=this.addTile(l,r),this.addTileMonitoringHooks(s),p.push(s));r=l.getCenterLonLat();e.push({tile:s,distance:Math.pow(r.lon-k.lon,2)+Math.pow(r.lat-k.lat,2)});q+=1}while(l.right<=a.right+c*this.buffer||q<b);n+=1}while(l.bottom>=a.bottom-h*this.buffer||n<g);this.removeExcessTiles(n,q);this.gridResolution=d=this.getServerResolution();
-e.sort(function(a,b){return a.distance-b.distance});a=0;for(d=e.length;a<d;++a)e[a].tile.draw()},getMaxExtent:function(){return this.maxExtent},addTile:function(a,b){var c=new this.tileClass(this,b,a,null,this.tileSize,this.tileOptions);this.events.triggerEvent("addtile",{tile:c});return c},addTileMonitoringHooks:function(a){a.onLoadStart=function(){!1===this.loading&&(this.loading=!0,this.events.triggerEvent("loadstart"));this.events.triggerEvent("tileloadstart",{tile:a});this.numLoadingTiles++;
-!this.singleTile&&(this.backBuffer&&this.gridResolution===this.backBufferResolution)&&OpenLayers.Element.addClass(a.getTile(),"olTileReplacing")};a.onLoadEnd=function(b){this.numLoadingTiles--;b="unload"===b.type;this.events.triggerEvent("tileloaded",{tile:a,aborted:b});if(!this.singleTile&&!b&&this.backBuffer&&this.gridResolution===this.backBufferResolution){var c=a.getTile();if("none"===OpenLayers.Element.getStyle(c,"display")){var d=document.getElementById(a.id+"_bb");d&&d.parentNode.removeChild(d)}OpenLayers.Element.removeClass(c,
-"olTileReplacing")}if(0===this.numLoadingTiles){if(this.backBuffer)if(0===this.backBuffer.childNodes.length)this.removeBackBuffer();else{this._transitionElement=b?this.div.lastChild:a.imgDiv;b=this.transitionendEvents;for(c=b.length-1;0<=c;--c)OpenLayers.Event.observe(this._transitionElement,b[c],this._removeBackBuffer);this.backBufferTimerId=window.setTimeout(this._removeBackBuffer,this.removeBackBufferDelay)}this.loading=!1;this.events.triggerEvent("loadend")}};a.onLoadError=function(){this.events.triggerEvent("tileerror",
-{tile:a})};a.events.on({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,loaderror:a.onLoadError,scope:this})},removeTileMonitoringHooks:function(a){a.unload();a.events.un({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,loaderror:a.onLoadError,scope:this})},moveGriddedTiles:function(){for(var a=this.buffer+1;;){var b=this.grid[0][0],c=b.position.x+this.map.layerContainerOriginPx.x,b=b.position.y+this.map.layerContainerOriginPx.y,d=this.getServerResolution()/this.map.getResolution(),
-d={w:Math.round(this.tileSize.w*d),h:Math.round(this.tileSize.h*d)};if(c>-d.w*(a-1))this.shiftColumn(!0,d);else if(c<-d.w*a)this.shiftColumn(!1,d);else if(b>-d.h*(a-1))this.shiftRow(!0,d);else if(b<-d.h*a)this.shiftRow(!1,d);else break}},shiftRow:function(a,b){var c=this.grid,d=a?0:c.length-1,e=a?-1:1;this.gridLayout.startrow+=e*this.rowSign;for(var f=c[d],g=c[a?"pop":"shift"](),h=0,k=g.length;h<k;h++){var l=g[h],m=f[h].position.clone();m.y+=b.h*e;l.moveTo(this.getTileBoundsForGridIndex(d,h),m)}c[a?
-"unshift":"push"](g)},shiftColumn:function(a,b){var c=this.grid,d=a?0:c[0].length-1,e=a?-1:1;this.gridLayout.startcol+=e;for(var f=0,g=c.length;f<g;f++){var h=c[f],k=h[d].position.clone(),l=h[a?"pop":"shift"]();k.x+=b.w*e;l.moveTo(this.getTileBoundsForGridIndex(f,d),k);h[a?"unshift":"push"](l)}},removeExcessTiles:function(a,b){for(var c,d;this.grid.length>a;){var e=this.grid.pop();c=0;for(d=e.length;c<d;c++){var f=e[c];this.destroyTile(f)}}c=0;for(d=this.grid.length;c<d;c++)for(;this.grid[c].length>
-b;)e=this.grid[c],f=e.pop(),this.destroyTile(f)},onMapResize:function(){this.singleTile&&(this.clearGrid(),this.setTileSize())},getTileBounds:function(a){var b=this.maxExtent,c=this.getResolution(),d=c*this.tileSize.w,c=c*this.tileSize.h,e=this.getLonLatFromViewPortPx(a);a=b.left+d*Math.floor((e.lon-b.left)/d);b=b.bottom+c*Math.floor((e.lat-b.bottom)/c);return new OpenLayers.Bounds(a,b,a+d,b+c)},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Format.ArcXML=OpenLayers.Class(OpenLayers.Format.XML,{fontStyleKeys:"antialiasing blockout font fontcolor fontsize fontstyle glowing interval outline printmode shadow transparency".split(" "),request:null,response:null,initialize:function(a){this.request=new OpenLayers.Format.ArcXML.Request;this.response=new OpenLayers.Format.ArcXML.Response;if(a)if("feature"==a.requesttype){this.request.get_image=null;var b=this.request.get_feature.query;this.addCoordSys(b.featurecoordsys,a.featureCoordSys);
-this.addCoordSys(b.filtercoordsys,a.filterCoordSys);a.polygon?(b.isspatial=!0,b.spatialfilter.polygon=a.polygon):a.envelope&&(b.isspatial=!0,b.spatialfilter.envelope={minx:0,miny:0,maxx:0,maxy:0},this.parseEnvelope(b.spatialfilter.envelope,a.envelope))}else"image"==a.requesttype?(this.request.get_feature=null,b=this.request.get_image.properties,this.parseEnvelope(b.envelope,a.envelope),this.addLayers(b.layerlist,a.layers),this.addImageSize(b.imagesize,a.tileSize),this.addCoordSys(b.featurecoordsys,
-a.featureCoordSys),this.addCoordSys(b.filtercoordsys,a.filterCoordSys)):this.request=null;OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},parseEnvelope:function(a,b){b&&4==b.length&&(a.minx=b[0],a.miny=b[1],a.maxx=b[2],a.maxy=b[3])},addLayers:function(a,b){for(var c=0,d=b.length;c<d;c++)a.push(b[c])},addImageSize:function(a,b){null!==b&&(a.width=b.w,a.height=b.h,a.printwidth=b.w,a.printheight=b.h)},addCoordSys:function(a,b){"string"==typeof b?(a.id=parseInt(b),a.string=b):"object"==typeof b&&
-null!==b.proj&&(a.id=b.proj.srsProjNumber,a.string=b.proj.srsCode)},iserror:function(a){var b=null;a?(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]),a=a.documentElement.getElementsByTagName("ERROR"),b=null!==a&&0<a.length):b=""!==this.response.error;return b},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=null;a&&a.documentElement&&(b="ARCXML"==a.documentElement.nodeName?a.documentElement:a.documentElement.getElementsByTagName("ARCXML")[0]);
-if(!b||"parsererror"===b.firstChild.nodeName){var c,d;try{c=a.firstChild.nodeValue,d=a.firstChild.childNodes[1].firstChild.nodeValue}catch(e){}throw{message:"Error parsing the ArcXML request",error:c,source:d};}return this.parseResponse(b)},write:function(a){a||(a=this.request);var b=this.createElementNS("","ARCXML");b.setAttribute("version","1.1");var c=this.createElementNS("","REQUEST");if(null!=a.get_image){var d=this.createElementNS("","GET_IMAGE");c.appendChild(d);var e=this.createElementNS("",
-"PROPERTIES");d.appendChild(e);a=a.get_image.properties;null!=a.featurecoordsys&&(d=this.createElementNS("","FEATURECOORDSYS"),e.appendChild(d),0===a.featurecoordsys.id?d.setAttribute("string",a.featurecoordsys.string):d.setAttribute("id",a.featurecoordsys.id));null!=a.filtercoordsys&&(d=this.createElementNS("","FILTERCOORDSYS"),e.appendChild(d),0===a.filtercoordsys.id?d.setAttribute("string",a.filtercoordsys.string):d.setAttribute("id",a.filtercoordsys.id));null!=a.envelope&&(d=this.createElementNS("",
-"ENVELOPE"),e.appendChild(d),d.setAttribute("minx",a.envelope.minx),d.setAttribute("miny",a.envelope.miny),d.setAttribute("maxx",a.envelope.maxx),d.setAttribute("maxy",a.envelope.maxy));d=this.createElementNS("","IMAGESIZE");e.appendChild(d);d.setAttribute("height",a.imagesize.height);d.setAttribute("width",a.imagesize.width);if(a.imagesize.height!=a.imagesize.printheight||a.imagesize.width!=a.imagesize.printwidth)d.setAttribute("printheight",a.imagesize.printheight),d.setArrtibute("printwidth",a.imagesize.printwidth);
-null!=a.background&&(d=this.createElementNS("","BACKGROUND"),e.appendChild(d),d.setAttribute("color",a.background.color.r+","+a.background.color.g+","+a.background.color.b),null!==a.background.transcolor&&d.setAttribute("transcolor",a.background.transcolor.r+","+a.background.transcolor.g+","+a.background.transcolor.b));if(null!=a.layerlist&&0<a.layerlist.length)for(d=this.createElementNS("","LAYERLIST"),e.appendChild(d),e=0;e<a.layerlist.length;e++){var f=this.createElementNS("","LAYERDEF");d.appendChild(f);
-f.setAttribute("id",a.layerlist[e].id);f.setAttribute("visible",a.layerlist[e].visible);if("object"==typeof a.layerlist[e].query){var g=a.layerlist[e].query;if(0>g.where.length)continue;var h=null,h="boolean"==typeof g.spatialfilter&&g.spatialfilter?this.createElementNS("","SPATIALQUERY"):this.createElementNS("","QUERY");h.setAttribute("where",g.where);"number"==typeof g.accuracy&&0<g.accuracy&&h.setAttribute("accuracy",g.accuracy);"number"==typeof g.featurelimit&&2E3>g.featurelimit&&h.setAttribute("featurelimit",
-g.featurelimit);"string"==typeof g.subfields&&"#ALL#"!=g.subfields&&h.setAttribute("subfields",g.subfields);"string"==typeof g.joinexpression&&0<g.joinexpression.length&&h.setAttribute("joinexpression",g.joinexpression);"string"==typeof g.jointables&&0<g.jointables.length&&h.setAttribute("jointables",g.jointables);f.appendChild(h)}"object"==typeof a.layerlist[e].renderer&&this.addRenderer(f,a.layerlist[e].renderer)}}else null!=a.get_feature&&(d=this.createElementNS("","GET_FEATURES"),d.setAttribute("outputmode",
-"newxml"),d.setAttribute("checkesc","true"),a.get_feature.geometry?d.setAttribute("geometry",a.get_feature.geometry):d.setAttribute("geometry","false"),a.get_feature.compact&&d.setAttribute("compact",a.get_feature.compact),"number"==a.get_feature.featurelimit&&d.setAttribute("featurelimit",a.get_feature.featurelimit),d.setAttribute("globalenvelope","true"),c.appendChild(d),null!=a.get_feature.layer&&0<a.get_feature.layer.length&&(e=this.createElementNS("","LAYER"),e.setAttribute("id",a.get_feature.layer),
-d.appendChild(e)),a=a.get_feature.query,null!=a&&(e=null,e=a.isspatial?this.createElementNS("","SPATIALQUERY"):this.createElementNS("","QUERY"),d.appendChild(e),"number"==typeof a.accuracy&&e.setAttribute("accuracy",a.accuracy),null!=a.featurecoordsys&&(d=this.createElementNS("","FEATURECOORDSYS"),0==a.featurecoordsys.id?d.setAttribute("string",a.featurecoordsys.string):d.setAttribute("id",a.featurecoordsys.id),e.appendChild(d)),null!=a.filtercoordsys&&(d=this.createElementNS("","FILTERCOORDSYS"),
-0===a.filtercoordsys.id?d.setAttribute("string",a.filtercoordsys.string):d.setAttribute("id",a.filtercoordsys.id),e.appendChild(d)),0<a.buffer&&(d=this.createElementNS("","BUFFER"),d.setAttribute("distance",a.buffer),e.appendChild(d)),a.isspatial&&(d=this.createElementNS("","SPATIALFILTER"),d.setAttribute("relation",a.spatialfilter.relation),e.appendChild(d),a.spatialfilter.envelope?(f=this.createElementNS("","ENVELOPE"),f.setAttribute("minx",a.spatialfilter.envelope.minx),f.setAttribute("miny",a.spatialfilter.envelope.miny),
-f.setAttribute("maxx",a.spatialfilter.envelope.maxx),f.setAttribute("maxy",a.spatialfilter.envelope.maxy),d.appendChild(f)):"object"==typeof a.spatialfilter.polygon&&d.appendChild(this.writePolygonGeometry(a.spatialfilter.polygon))),null!=a.where&&0<a.where.length&&e.setAttribute("where",a.where)));b.appendChild(c);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},addGroupRenderer:function(a,b){var c=this.createElementNS("","GROUPRENDERER");a.appendChild(c);for(var d=0;d<b.length;d++)this.addRenderer(c,
-b[d])},addRenderer:function(a,b){if(OpenLayers.Util.isArray(b))this.addGroupRenderer(a,b);else{var c=this.createElementNS("",b.type.toUpperCase()+"RENDERER");a.appendChild(c);"VALUEMAPRENDERER"==c.tagName?this.addValueMapRenderer(c,b):"VALUEMAPLABELRENDERER"==c.tagName?this.addValueMapLabelRenderer(c,b):"SIMPLELABELRENDERER"==c.tagName?this.addSimpleLabelRenderer(c,b):"SCALEDEPENDENTRENDERER"==c.tagName&&this.addScaleDependentRenderer(c,b)}},addScaleDependentRenderer:function(a,b){"string"!=typeof b.lower&&
-"number"!=typeof b.lower||a.setAttribute("lower",b.lower);"string"!=typeof b.upper&&"number"!=typeof b.upper||a.setAttribute("upper",b.upper);this.addRenderer(a,b.renderer)},addValueMapLabelRenderer:function(a,b){a.setAttribute("lookupfield",b.lookupfield);a.setAttribute("labelfield",b.labelfield);if("object"==typeof b.exacts)for(var c=0,d=b.exacts.length;c<d;c++){var e=b.exacts[c],f=this.createElementNS("","EXACT");"string"==typeof e.value&&f.setAttribute("value",e.value);"string"==typeof e.label&&
-f.setAttribute("label",e.label);"string"==typeof e.method&&f.setAttribute("method",e.method);a.appendChild(f);if("object"==typeof e.symbol){var g=null;"text"==e.symbol.type&&(g=this.createElementNS("","TEXTSYMBOL"));if(null!=g){for(var h=this.fontStyleKeys,k=0,l=h.length;k<l;k++){var m=h[k];e.symbol[m]&&g.setAttribute(m,e.symbol[m])}f.appendChild(g)}}}},addValueMapRenderer:function(a,b){a.setAttribute("lookupfield",b.lookupfield);if("object"==typeof b.ranges)for(var c=0,d=b.ranges.length;c<d;c++){var e=
-b.ranges[c],f=this.createElementNS("","RANGE");f.setAttribute("lower",e.lower);f.setAttribute("upper",e.upper);a.appendChild(f);if("object"==typeof e.symbol){var g=null;"simplepolygon"==e.symbol.type&&(g=this.createElementNS("","SIMPLEPOLYGONSYMBOL"));null!=g&&("string"==typeof e.symbol.boundarycolor&&g.setAttribute("boundarycolor",e.symbol.boundarycolor),"string"==typeof e.symbol.fillcolor&&g.setAttribute("fillcolor",e.symbol.fillcolor),"number"==typeof e.symbol.filltransparency&&g.setAttribute("filltransparency",
-e.symbol.filltransparency),f.appendChild(g))}}else if("object"==typeof b.exacts)for(c=0,d=b.exacts.length;c<d;c++)e=b.exacts[c],f=this.createElementNS("","EXACT"),"string"==typeof e.value&&f.setAttribute("value",e.value),"string"==typeof e.label&&f.setAttribute("label",e.label),"string"==typeof e.method&&f.setAttribute("method",e.method),a.appendChild(f),"object"==typeof e.symbol&&(g=null,"simplemarker"==e.symbol.type&&(g=this.createElementNS("","SIMPLEMARKERSYMBOL")),null!=g&&("string"==typeof e.symbol.antialiasing&&
-g.setAttribute("antialiasing",e.symbol.antialiasing),"string"==typeof e.symbol.color&&g.setAttribute("color",e.symbol.color),"string"==typeof e.symbol.outline&&g.setAttribute("outline",e.symbol.outline),"string"==typeof e.symbol.overlap&&g.setAttribute("overlap",e.symbol.overlap),"string"==typeof e.symbol.shadow&&g.setAttribute("shadow",e.symbol.shadow),"number"==typeof e.symbol.transparency&&g.setAttribute("transparency",e.symbol.transparency),"string"==typeof e.symbol.usecentroid&&g.setAttribute("usecentroid",
-e.symbol.usecentroid),"number"==typeof e.symbol.width&&g.setAttribute("width",e.symbol.width),f.appendChild(g)))},addSimpleLabelRenderer:function(a,b){a.setAttribute("field",b.field);for(var c="featureweight howmanylabels labelbufferratio labelpriorities labelweight linelabelposition rotationalangles".split(" "),d=0,e=c.length;d<e;d++){var f=c[d];b[f]&&a.setAttribute(f,b[f])}if("text"==b.symbol.type){var g=b.symbol,h=this.createElementNS("","TEXTSYMBOL");a.appendChild(h);c=this.fontStyleKeys;d=0;
-for(e=c.length;d<e;d++)f=c[d],g[f]&&h.setAttribute(f,b[f])}},writePolygonGeometry:function(a){if(!(a instanceof OpenLayers.Geometry.Polygon))throw{message:"Cannot write polygon geometry to ArcXML with an "+a.CLASS_NAME+" object.",geometry:a};for(var b=this.createElementNS("","POLYGON"),c=0,d=a.components.length;c<d;c++){for(var e=a.components[c],f=this.createElementNS("","RING"),g=0,h=e.components.length;g<h;g++){var k=e.components[g],l=this.createElementNS("","POINT");l.setAttribute("x",k.x);l.setAttribute("y",
-k.y);f.appendChild(l)}b.appendChild(f)}return b},parseResponse:function(a){"string"==typeof a&&(a=(new OpenLayers.Format.XML).read(a));var b=new OpenLayers.Format.ArcXML.Response,c=a.getElementsByTagName("ERROR");if(null!=c&&0<c.length)b.error=this.getChildValue(c,"Unknown error.");else{c=a.getElementsByTagName("RESPONSE");if(null==c||0==c.length)return b.error="No RESPONSE tag found in ArcXML response.",b;var d=c[0].firstChild.nodeName;"#text"==d&&(d=c[0].firstChild.nextSibling.nodeName);if("IMAGE"==
-d)c=a.getElementsByTagName("ENVELOPE"),a=a.getElementsByTagName("OUTPUT"),null==c||0==c.length?b.error="No ENVELOPE tag found in ArcXML response.":null==a||0==a.length?b.error="No OUTPUT tag found in ArcXML response.":(c=this.parseAttributes(c[0]),d=this.parseAttributes(a[0]),b.image="string"==typeof d.type?{envelope:c,output:{type:d.type,data:this.getChildValue(a[0])}}:{envelope:c,output:d});else if("FEATURES"==d){if(a=c[0].getElementsByTagName("FEATURES"),c=a[0].getElementsByTagName("FEATURECOUNT"),
-b.features.featurecount=c[0].getAttribute("count"),0<b.features.featurecount)for(c=a[0].getElementsByTagName("ENVELOPE"),b.features.envelope=this.parseAttributes(c[0],"number"),a=a[0].getElementsByTagName("FEATURE"),c=0;c<a.length;c++){for(var d=new OpenLayers.Feature.Vector,e=a[c].getElementsByTagName("FIELD"),f=0;f<e.length;f++){var g=e[f].getAttribute("name"),h=e[f].getAttribute("value");d.attributes[g]=h}e=a[c].getElementsByTagName("POLYGON");if(0<e.length){e=e[0].getElementsByTagName("RING");
-f=[];for(g=0;g<e.length;g++){h=[];h.push(this.parsePointGeometry(e[g]));for(var k=e[g].getElementsByTagName("HOLE"),l=0;l<k.length;l++)h.push(this.parsePointGeometry(k[l]));f.push(new OpenLayers.Geometry.Polygon(h))}d.geometry=1==f.length?f[0]:new OpenLayers.Geometry.MultiPolygon(f)}b.features.feature.push(d)}}else b.error="Unidentified response type."}return b},parseAttributes:function(a,b){for(var c={},d=0;d<a.attributes.length;d++)c[a.attributes[d].nodeName]="number"==b?parseFloat(a.attributes[d].nodeValue):
-a.attributes[d].nodeValue;return c},parsePointGeometry:function(a){var b=[],c=a.getElementsByTagName("COORDS");if(0<c.length)for(a=this.getChildValue(c[0]),a=a.split(/;/),c=0;c<a.length;c++){var d=a[c].split(/ /);b.push(new OpenLayers.Geometry.Point(d[0],d[1]))}else if(a=a.getElementsByTagName("POINT"),0<a.length)for(c=0;c<a.length;c++)b.push(new OpenLayers.Geometry.Point(parseFloat(a[c].getAttribute("x")),parseFloat(a[c].getAttribute("y"))));return new OpenLayers.Geometry.LinearRing(b)},CLASS_NAME:"OpenLayers.Format.ArcXML"});
-OpenLayers.Format.ArcXML.Request=OpenLayers.Class({initialize:function(a){return OpenLayers.Util.extend(this,{get_image:{properties:{background:null,draw:!0,envelope:{minx:0,miny:0,maxx:0,maxy:0},featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},imagesize:{height:0,width:0,dpi:96,printheight:0,printwidth:0,scalesymbols:!1},layerlist:[],output:{baseurl:"",legendbaseurl:"",legendname:"",legendpath:"",
-legendurl:"",name:"",path:"",type:"jpg",url:""}}},get_feature:{layer:"",query:{isspatial:!1,featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},buffer:0,where:"",spatialfilter:{relation:"envelope_intersection",envelope:null}}},environment:{separators:{cs:" ",ts:";"}},layer:[],workspaces:[]})},CLASS_NAME:"OpenLayers.Format.ArcXML.Request"});
-OpenLayers.Format.ArcXML.Response=OpenLayers.Class({initialize:function(a){return OpenLayers.Util.extend(this,{image:{envelope:null,output:""},features:{featurecount:0,envelope:null,feature:[]},error:""})},CLASS_NAME:"OpenLayers.Format.ArcXML.Response"});(function(){function a(){this._object=f&&!k?new f:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function b(){return new a}function c(a){b.onreadystatechange&&b.onreadystatechange.apply(a);a.dispatchEvent({type:"readystatechange",bubbles:!1,cancelable:!1,timeStamp:new Date+0})}function d(a){try{a.responseText=a._object.responseText}catch(b){}try{var c;var d=a._object,e=d.responseXML,f=d.responseText;h&&(f&&e&&!e.documentElement&&d.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/))&&
-(e=new window.ActiveXObject("Microsoft.XMLDOM"),e.async=!1,e.validateOnParse=!1,e.loadXML(f));c=e&&(h&&0!=e.parseError||!e.documentElement||e.documentElement&&"parsererror"==e.documentElement.tagName)?null:e;a.responseXML=c}catch(g){}try{a.status=a._object.status}catch(k){}try{a.statusText=a._object.statusText}catch(u){}}function e(a){a._object.onreadystatechange=new window.Function}var f=window.XMLHttpRequest,g=!!window.controllers,h=window.document.all&&!window.opera,k=h&&window.navigator.userAgent.match(/MSIE 7.0/);
-b.prototype=a.prototype;g&&f.wrapped&&(b.wrapped=f.wrapped);b.UNSENT=0;b.OPENED=1;b.HEADERS_RECEIVED=2;b.LOADING=3;b.DONE=4;b.prototype.readyState=b.UNSENT;b.prototype.responseText="";b.prototype.responseXML=null;b.prototype.status=0;b.prototype.statusText="";b.prototype.priority="NORMAL";b.prototype.onreadystatechange=null;b.onreadystatechange=null;b.onopen=null;b.onsend=null;b.onabort=null;b.prototype.open=function(a,f,k,p,q){delete this._headers;3>arguments.length&&(k=!0);this._async=k;var r=this,
-s=this.readyState,t;h&&k&&(t=function(){s!=b.DONE&&(e(r),r.abort())},window.attachEvent("onunload",t));b.onopen&&b.onopen.apply(this,arguments);4<arguments.length?this._object.open(a,f,k,p,q):3<arguments.length?this._object.open(a,f,k,p):this._object.open(a,f,k);this.readyState=b.OPENED;c(this);this._object.onreadystatechange=function(){if(!g||k)r.readyState=r._object.readyState,d(r),r._aborted?r.readyState=b.UNSENT:(r.readyState==b.DONE&&(delete r._data,e(r),h&&k&&window.detachEvent("onunload",t)),
-s!=r.readyState&&c(r),s=r.readyState)}};b.prototype.send=function(a){b.onsend&&b.onsend.apply(this,arguments);arguments.length||(a=null);a&&a.nodeType&&(a=window.XMLSerializer?(new window.XMLSerializer).serializeToString(a):a.xml,this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml"));this._data=a;a:if(this._object.send(this._data),g&&!this._async)for(this.readyState=b.OPENED,d(this);this.readyState<b.DONE;)if(this.readyState++,c(this),this._aborted)break a};
-b.prototype.abort=function(){b.onabort&&b.onabort.apply(this,arguments);this.readyState>b.UNSENT&&(this._aborted=!0);this._object.abort();e(this);this.readyState=b.UNSENT;delete this._data};b.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};b.prototype.getResponseHeader=function(a){return this._object.getResponseHeader(a)};b.prototype.setRequestHeader=function(a,b){this._headers||(this._headers={});this._headers[a]=b;return this._object.setRequestHeader(a,b)};
-b.prototype.addEventListener=function(a,b,c){for(var d=0,e;e=this._listeners[d];d++)if(e[0]==a&&e[1]==b&&e[2]==c)return;this._listeners.push([a,b,c])};b.prototype.removeEventListener=function(a,b,c){for(var d=0,e;(e=this._listeners[d])&&(e[0]!=a||e[1]!=b||e[2]!=c);d++);e&&this._listeners.splice(d,1)};b.prototype.dispatchEvent=function(a){a={type:a.type,target:this,currentTarget:this,eventPhase:2,bubbles:a.bubbles,cancelable:a.cancelable,timeStamp:a.timeStamp,stopPropagation:function(){},preventDefault:function(){},
-initEvent:function(){}};"readystatechange"==a.type&&this.onreadystatechange&&(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[a]);for(var b=0,c;c=this._listeners[b];b++)c[0]!=a.type||c[2]||(c[1].handleEvent||c[1]).apply(this,[a])};b.prototype.toString=function(){return"[object XMLHttpRequest]"};b.toString=function(){return"[XMLHttpRequest]"};window.Function.prototype.apply||(window.Function.prototype.apply=function(a,b){b||(b=[]);a.__func=this;a.__func(b[0],b[1],b[2],b[3],
-b[4]);delete a.__func});OpenLayers.Request||(OpenLayers.Request={});OpenLayers.Request.XMLHttpRequest=b})();OpenLayers.ProxyHost="";OpenLayers.Request||(OpenLayers.Request={});
-OpenLayers.Util.extend(OpenLayers.Request,{DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:!0,user:void 0,password:void 0,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(a,b){var c=0!==a.indexOf("http"),d=!c&&a.match(this.URL_SPLIT_REGEX);if(d){var e=window.location,c=d[1]==e.protocol&&d[3]==
-e.hostname,d=d[4],e=e.port;if(80!=d&&""!=d||"80"!=e&&""!=e)c=c&&d==e}c||b&&(a="function"==typeof b?b(a):b+encodeURIComponent(a));return a},issue:function(a){var b=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});a=a||{};a.headers=a.headers||{};a=OpenLayers.Util.applyDefaults(a,b);a.headers=OpenLayers.Util.applyDefaults(a.headers,b.headers);var b=!1,c;for(c in a.headers)a.headers.hasOwnProperty(c)&&"x-requested-with"===c.toLowerCase()&&(b=!0);!1===b&&(a.headers["X-Requested-With"]=
-"XMLHttpRequest");var d=new OpenLayers.Request.XMLHttpRequest,e=OpenLayers.Util.urlAppend(a.url,OpenLayers.Util.getParameterString(a.params||{})),e=OpenLayers.Request.makeSameOrigin(e,a.proxy);d.open(a.method,e,a.async,a.user,a.password);for(var f in a.headers)d.setRequestHeader(f,a.headers[f]);var g=this.events,h=this;d.onreadystatechange=function(){d.readyState==OpenLayers.Request.XMLHttpRequest.DONE&&!1!==g.triggerEvent("complete",{request:d,config:a,requestUrl:e})&&h.runCallbacks({request:d,config:a,
-requestUrl:e})};!1===a.async?d.send(a.data):window.setTimeout(function(){0!==d.readyState&&d.send(a.data)},0);return d},runCallbacks:function(a){var b=a.request,c=a.config,d=c.scope?OpenLayers.Function.bind(c.callback,c.scope):c.callback,e;c.success&&(e=c.scope?OpenLayers.Function.bind(c.success,c.scope):c.success);var f;c.failure&&(f=c.scope?OpenLayers.Function.bind(c.failure,c.scope):c.failure);"file:"==OpenLayers.Util.createUrlObject(c.url).protocol&&b.responseText&&(b.status=200);d(b);if(!b.status||
-200<=b.status&&300>b.status)this.events.triggerEvent("success",a),e&&e(b);b.status&&(200>b.status||300<=b.status)&&(this.events.triggerEvent("failure",a),f&&f(b))},GET:function(a){a=OpenLayers.Util.extend(a,{method:"GET"});return OpenLayers.Request.issue(a)},POST:function(a){a=OpenLayers.Util.extend(a,{method:"POST"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},PUT:function(a){a=
-OpenLayers.Util.extend(a,{method:"PUT"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},DELETE:function(a){a=OpenLayers.Util.extend(a,{method:"DELETE"});return OpenLayers.Request.issue(a)},HEAD:function(a){a=OpenLayers.Util.extend(a,{method:"HEAD"});return OpenLayers.Request.issue(a)},OPTIONS:function(a){a=OpenLayers.Util.extend(a,{method:"OPTIONS"});return OpenLayers.Request.issue(a)}});OpenLayers.Layer.ArcIMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{ClientVersion:"9.2",ServiceName:""},featureCoordSys:"4326",filterCoordSys:"4326",layers:null,async:!0,name:"ArcIMS",isBaseLayer:!0,DEFAULT_OPTIONS:{tileSize:new OpenLayers.Size(512,512),featureCoordSys:"4326",filterCoordSys:"4326",layers:null,isBaseLayer:!0,async:!0,name:"ArcIMS"},initialize:function(a,b,c){this.tileSize=new OpenLayers.Size(512,512);this.params=OpenLayers.Util.applyDefaults({ServiceName:c.serviceName},
-this.DEFAULT_PARAMS);this.options=OpenLayers.Util.applyDefaults(c,this.DEFAULT_OPTIONS);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,this.params,c]);this.transparent&&(this.isBaseLayer||(this.isBaseLayer=!1),"image/jpeg"==this.format&&(this.format=OpenLayers.Util.alphaHack()?"image/gif":"image/png"));null===this.options.layers&&(this.options.layers=[])},getURL:function(a){var b="";a=this.adjustBounds(a);a=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",
-envelope:a.toArray(),tileSize:this.tileSize}));a=new OpenLayers.Request.POST({url:this.getFullRequestString(),data:a.write(),async:!1});null!=a&&(b=a.responseXML,b&&b.documentElement||(b=a.responseText),b=(new OpenLayers.Format.ArcXML).read(b),b=this.getUrlOrImage(b.image.output));return b},getURLasync:function(a,b,c){a=this.adjustBounds(a);a=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",envelope:a.toArray(),tileSize:this.tileSize}));OpenLayers.Request.POST({url:this.getFullRequestString(),
-async:!0,data:a.write(),callback:function(a){var e=a.responseXML;e&&e.documentElement||(e=a.responseText);a=(new OpenLayers.Format.ArcXML).read(e);b.call(c,this.getUrlOrImage(a.image.output))},scope:this})},getUrlOrImage:function(a){var b="";a.url?b=a.url:a.data&&(b="data:image/"+a.type+";base64,"+a.data);return b},setLayerQuery:function(a,b){for(var c=0;c<this.options.layers.length;c++)if(a==this.options.layers[c].id){this.options.layers[c].query=b;return}this.options.layers.push({id:a,visible:!0,
-query:b})},getFeatureInfo:function(a,b,c){var d=c.buffer||1,e=c.callback||function(){},f=c.scope||window,g={};OpenLayers.Util.extend(g,this.options);g.requesttype="feature";a instanceof OpenLayers.LonLat?(g.polygon=null,g.envelope=[a.lon-d,a.lat-d,a.lon+d,a.lat+d]):a instanceof OpenLayers.Geometry.Polygon&&(g.envelope=null,g.polygon=a);var h=new OpenLayers.Format.ArcXML(g);OpenLayers.Util.extend(h.request.get_feature,c);h.request.get_feature.layer=b.id;"number"==typeof b.query.accuracy?h.request.get_feature.query.accuracy=
-b.query.accuracy:(a=this.map.getCenter(),c=this.map.getViewPortPxFromLonLat(a),c.x++,c=this.map.getLonLatFromPixel(c),h.request.get_feature.query.accuracy=c.lon-a.lon);h.request.get_feature.query.where=b.query.where;h.request.get_feature.query.spatialfilter.relation="area_intersection";OpenLayers.Request.POST({url:this.getFullRequestString({CustomService:"Query"}),data:h.write(),callback:function(a){a=h.parseResponse(a.responseText);h.iserror()?e.call(f,null):e.call(f,a.features)}})},clone:function(a){null==
-a&&(a=new OpenLayers.Layer.ArcIMS(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.ArcIMS"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,slideRatio:null,buttons:null,position:null,initialize:function(a){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onButtonClick);this.removeButtons();this.position=this.buttons=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},
-setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.register("buttonclick",this,this.onButtonClick)},draw:function(a){OpenLayers.Control.prototype.draw.apply(this,arguments);a=this.position;this.buttons=[];var b={w:18,h:18},c=new OpenLayers.Pixel(a.x+b.w/2,a.y);this._addButton("panup","north-mini.png",c,b);a.y=c.y+b.h;this._addButton("panleft","west-mini.png",a,b);this._addButton("panright","east-mini.png",a.add(b.w,0),b);this._addButton("pandown","south-mini.png",
-c.add(0,2*b.h),b);this._addButton("zoomin","zoom-plus-mini.png",c.add(0,3*b.h+5),b);this._addButton("zoomworld","zoom-world-mini.png",c.add(0,4*b.h+5),b);this._addButton("zoomout","zoom-minus-mini.png",c.add(0,5*b.h+5),b);return this.div},_addButton:function(a,b,c,d){b=OpenLayers.Util.getImageLocation(b);c=OpenLayers.Util.createAlphaImageDiv(this.id+"_"+a,c,d,b,"absolute");c.style.cursor="pointer";this.div.appendChild(c);c.action=a;c.className="olButton";this.buttons.push(c);return c},_removeButton:function(a){this.div.removeChild(a);
-OpenLayers.Util.removeItem(this.buttons,a)},removeButtons:function(){for(var a=this.buttons.length-1;0<=a;--a)this._removeButton(this.buttons[a])},onButtonClick:function(a){switch(a.buttonElement.action){case "panup":this.map.pan(0,-this.getSlideFactor("h"));break;case "pandown":this.map.pan(0,this.getSlideFactor("h"));break;case "panleft":this.map.pan(-this.getSlideFactor("w"),0);break;case "panright":this.map.pan(this.getSlideFactor("w"),0);break;case "zoomin":this.map.zoomIn();break;case "zoomout":this.map.zoomOut();
-break;case "zoomworld":this.map.zoomToMaxExtent()}},getSlideFactor:function(a){return this.slideRatio?this.map.getSize()[a]*this.slideRatio:this.slideFactor},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Control.PanZoomBar=OpenLayers.Class(OpenLayers.Control.PanZoom,{zoomStopWidth:18,zoomStopHeight:11,slider:null,sliderEvents:null,zoombarDiv:null,zoomWorldIcon:!1,panIcons:!0,forceFixedZoomLevel:!1,mouseDragStart:null,deltaY:null,zoomStart:null,destroy:function(){this._removeZoomBar();this.map.events.un({changebaselayer:this.redraw,updatesize:this.redraw,scope:this});OpenLayers.Control.PanZoom.prototype.destroy.apply(this,arguments);delete this.mouseDragStart;delete this.zoomStart},setMap:function(a){OpenLayers.Control.PanZoom.prototype.setMap.apply(this,
-arguments);this.map.events.on({changebaselayer:this.redraw,updatesize:this.redraw,scope:this})},redraw:function(){null!=this.div&&(this.removeButtons(),this._removeZoomBar());this.draw()},draw:function(a){OpenLayers.Control.prototype.draw.apply(this,arguments);a=this.position.clone();this.buttons=[];var b={w:18,h:18};if(this.panIcons){var c=new OpenLayers.Pixel(a.x+b.w/2,a.y),d=b.w;this.zoomWorldIcon&&(c=new OpenLayers.Pixel(a.x+b.w,a.y));this._addButton("panup","north-mini.png",c,b);a.y=c.y+b.h;
-this._addButton("panleft","west-mini.png",a,b);this.zoomWorldIcon&&(this._addButton("zoomworld","zoom-world-mini.png",a.add(b.w,0),b),d*=2);this._addButton("panright","east-mini.png",a.add(d,0),b);this._addButton("pandown","south-mini.png",c.add(0,2*b.h),b);this._addButton("zoomin","zoom-plus-mini.png",c.add(0,3*b.h+5),b);c=this._addZoomBar(c.add(0,4*b.h+5));this._addButton("zoomout","zoom-minus-mini.png",c,b)}else this._addButton("zoomin","zoom-plus-mini.png",a,b),c=this._addZoomBar(a.add(0,b.h)),
-this._addButton("zoomout","zoom-minus-mini.png",c,b),this.zoomWorldIcon&&(c=c.add(0,b.h+3),this._addButton("zoomworld","zoom-world-mini.png",c,b));return this.div},_addZoomBar:function(a){var b=OpenLayers.Util.getImageLocation("slider.png"),c=this.id+"_"+this.map.id,d=this.map.getMinZoom(),e=this.map.getNumZoomLevels()-1-this.map.getZoom(),e=OpenLayers.Util.createAlphaImageDiv(c,a.add(-1,e*this.zoomStopHeight),{w:20,h:9},b,"absolute");e.style.cursor="move";this.slider=e;this.sliderEvents=new OpenLayers.Events(this,
-e,null,!0,{includeXY:!0});this.sliderEvents.on({touchstart:this.zoomBarDown,touchmove:this.zoomBarDrag,touchend:this.zoomBarUp,mousedown:this.zoomBarDown,mousemove:this.zoomBarDrag,mouseup:this.zoomBarUp});var f={w:this.zoomStopWidth,h:this.zoomStopHeight*(this.map.getNumZoomLevels()-d)},b=OpenLayers.Util.getImageLocation("zoombar.png"),c=null;OpenLayers.Util.alphaHack()?(c=this.id+"_"+this.map.id,c=OpenLayers.Util.createAlphaImageDiv(c,a,{w:f.w,h:this.zoomStopHeight},b,"absolute",null,"crop"),c.style.height=
-f.h+"px"):c=OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar"+this.map.id,a,f,b);c.style.cursor="pointer";c.className="olButton";this.zoombarDiv=c;this.div.appendChild(c);this.startTop=parseInt(c.style.top);this.div.appendChild(e);this.map.events.register("zoomend",this,this.moveZoomBar);return a=a.add(0,this.zoomStopHeight*(this.map.getNumZoomLevels()-d))},_removeZoomBar:function(){this.sliderEvents.un({touchstart:this.zoomBarDown,touchmove:this.zoomBarDrag,touchend:this.zoomBarUp,
-mousedown:this.zoomBarDown,mousemove:this.zoomBarDrag,mouseup:this.zoomBarUp});this.sliderEvents.destroy();this.div.removeChild(this.zoombarDiv);this.zoombarDiv=null;this.div.removeChild(this.slider);this.slider=null;this.map.events.unregister("zoomend",this,this.moveZoomBar)},onButtonClick:function(a){OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this,arguments);if(a.buttonElement===this.zoombarDiv){var b=a.buttonXY.y/this.zoomStopHeight;if(this.forceFixedZoomLevel||!this.map.fractionalZoom)b=
-Math.floor(b);b=this.map.getNumZoomLevels()-1-b;b=Math.min(Math.max(b,0),this.map.getNumZoomLevels()-1);this.map.zoomTo(b)}},passEventToSlider:function(a){this.sliderEvents.handleBrowserEvent(a)},zoomBarDown:function(a){if(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))this.map.events.on({touchmove:this.passEventToSlider,mousemove:this.passEventToSlider,mouseup:this.passEventToSlider,scope:this}),this.mouseDragStart=a.xy.clone(),this.zoomStart=a.xy.clone(),this.div.style.cursor=
-"move",this.zoombarDiv.offsets=null,OpenLayers.Event.stop(a)},zoomBarDrag:function(a){if(null!=this.mouseDragStart){var b=this.mouseDragStart.y-a.xy.y,c=OpenLayers.Util.pagePosition(this.zoombarDiv);0<a.clientY-c[1]&&a.clientY-c[1]<parseInt(this.zoombarDiv.style.height)-2&&(b=parseInt(this.slider.style.top)-b,this.slider.style.top=b+"px",this.mouseDragStart=a.xy.clone());this.deltaY=this.zoomStart.y-a.xy.y;OpenLayers.Event.stop(a)}},zoomBarUp:function(a){if((OpenLayers.Event.isLeftClick(a)||"touchend"===
-a.type)&&this.mouseDragStart){this.div.style.cursor="";this.map.events.un({touchmove:this.passEventToSlider,mouseup:this.passEventToSlider,mousemove:this.passEventToSlider,scope:this});var b=this.map.zoom;!this.forceFixedZoomLevel&&this.map.fractionalZoom?(b+=this.deltaY/this.zoomStopHeight,b=Math.min(Math.max(b,0),this.map.getNumZoomLevels()-1)):(b+=this.deltaY/this.zoomStopHeight,b=Math.max(Math.round(b),0));this.map.zoomTo(b);this.zoomStart=this.mouseDragStart=null;this.deltaY=0;OpenLayers.Event.stop(a)}},
-moveZoomBar:function(){var a=(this.map.getNumZoomLevels()-1-this.map.getZoom())*this.zoomStopHeight+this.startTop+1;this.slider.style.top=a+"px"},CLASS_NAME:"OpenLayers.Control.PanZoomBar"});OpenLayers.Format.WFSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",CLASS_NAME:"OpenLayers.Format.WFSCapabilities"});OpenLayers.Format.WFSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wfs:"http://www.opengis.net/wfs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows"},errorProperty:"featureTypeList",defaultPrefix:"wfs",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{wfs:{WFS_Capabilities:function(a,
-b){this.readChildNodes(a,b)},FeatureTypeList:function(a,b){b.featureTypeList={featureTypes:[]};this.readChildNodes(a,b.featureTypeList)},FeatureType:function(a,b){var c={};this.readChildNodes(a,c);b.featureTypes.push(c)},Name:function(a,b){var c=this.getChildValue(a);c&&(c=c.split(":"),b.name=c.pop(),0<c.length&&(b.featureNS=this.lookupNamespaceURI(a,c[0])))},Title:function(a,b){var c=this.getChildValue(a);c&&(b.title=c)},Abstract:function(a,b){var c=this.getChildValue(a);c&&(b["abstract"]=c)}}},
-CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1"});OpenLayers.Format.WFSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},readers:{wfs:OpenLayers.Util.applyDefaults({DefaultSRS:function(a,b){var c=this.getChildValue(a);c&&(b.srs=c)}},OpenLayers.Format.WFSCapabilities.v1.prototype.readers.wfs),ows:OpenLayers.Format.OWSCommon.v1.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_1_0"});OpenLayers.Layer.Image=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!0,url:null,extent:null,size:null,tile:null,aspectRatio:null,initialize:function(a,b,c,d,e){this.url=b;this.maxExtent=this.extent=c;this.size=d;OpenLayers.Layer.prototype.initialize.apply(this,[a,e]);this.aspectRatio=this.extent.getHeight()/this.size.h/(this.extent.getWidth()/this.size.w)},destroy:function(){this.tile&&(this.removeTileMonitoringHooks(this.tile),this.tile.destroy(),this.tile=null);OpenLayers.Layer.prototype.destroy.apply(this,
-arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Image(this.name,this.url,this.extent,this.size,this.getOptions()));return a=OpenLayers.Layer.prototype.clone.apply(this,[a])},setMap:function(a){null==this.options.maxResolution&&(this.options.maxResolution=this.aspectRatio*this.extent.getWidth()/this.size.w);OpenLayers.Layer.prototype.setMap.apply(this,arguments)},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var d=null==this.tile;if(b||d){this.setTileSize();
-var e=this.map.getLayerPxFromLonLat({lon:this.extent.left,lat:this.extent.top});d?(this.tile=new OpenLayers.Tile.Image(this,e,this.extent,null,this.tileSize),this.addTileMonitoringHooks(this.tile)):(this.tile.size=this.tileSize.clone(),this.tile.position=e.clone());this.tile.draw()}},setTileSize:function(){var a=this.extent.getWidth()/this.map.getResolution(),b=this.extent.getHeight()/this.map.getResolution();this.tileSize=new OpenLayers.Size(a,b)},addTileMonitoringHooks:function(a){a.onLoadStart=
-function(){this.events.triggerEvent("loadstart")};a.events.register("loadstart",this,a.onLoadStart);a.onLoadEnd=function(){this.events.triggerEvent("loadend")};a.events.register("loadend",this,a.onLoadEnd);a.events.register("unload",this,a.onLoadEnd)},removeTileMonitoringHooks:function(a){a.unload();a.events.un({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,scope:this})},setUrl:function(a){this.url=a;this.tile.draw()},getURL:function(a){return this.url},CLASS_NAME:"OpenLayers.Layer.Image"});OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:!0,autoDestroy:!0,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a;this.active=!1},destroy:function(){this.deactivate();this.options=this.layer=null},setLayer:function(a){this.layer=a},activate:function(){return this.active?!1:this.active=!0},deactivate:function(){return this.active?(this.active=!1,!0):!1},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.Save=OpenLayers.Class(OpenLayers.Strategy,{events:null,auto:!1,timer:null,initialize:function(a){OpenLayers.Strategy.prototype.initialize.apply(this,[a]);this.events=new OpenLayers.Events(this)},activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a&&this.auto)if("number"===typeof this.auto)this.timer=window.setInterval(OpenLayers.Function.bind(this.save,this),1E3*this.auto);else this.layer.events.on({featureadded:this.triggerSave,afterfeaturemodified:this.triggerSave,
-scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.auto&&("number"===typeof this.auto?window.clearInterval(this.timer):this.layer.events.un({featureadded:this.triggerSave,afterfeaturemodified:this.triggerSave,scope:this}));return a},triggerSave:function(a){var b=a.feature;b.state!==OpenLayers.State.INSERT&&b.state!==OpenLayers.State.UPDATE&&b.state!==OpenLayers.State.DELETE||this.save([a.feature])},save:function(a){a||(a=this.layer.features);
-this.events.triggerEvent("start",{features:a});var b=this.layer.projection,c=this.layer.map.getProjectionObject();if(!c.equals(b)){for(var d=a.length,e=Array(d),f,g,h=0;h<d;++h)f=a[h],g=f.clone(),g.fid=f.fid,g.state=f.state,f.url&&(g.url=f.url),g._original=f,g.geometry.transform(c,b),e[h]=g;a=e}this.layer.protocol.commit(a,{callback:this.onCommit,scope:this})},onCommit:function(a){var b={response:a};if(a.success()){for(var c=a.reqFeatures,d,e=[],f=a.insertIds||[],g=0,h=0,k=c.length;h<k;++h)if(d=c[h],
-d=d._original||d,a=d.state)a==OpenLayers.State.DELETE?e.push(d):a==OpenLayers.State.INSERT&&(d.fid=f[g],++g),d.state=null;0<e.length&&this.layer.destroyFeatures(e);this.events.triggerEvent("success",b)}else this.events.triggerEvent("fail",b)},CLASS_NAME:"OpenLayers.Strategy.Save"});OpenLayers.Events.featureclick=OpenLayers.Class({cache:null,map:null,provides:["featureclick","nofeatureclick","featureover","featureout"],initialize:function(a){this.target=a;if(a.object instanceof OpenLayers.Map)this.setMap(a.object);else if(a.object instanceof OpenLayers.Layer.Vector)a.object.map?this.setMap(a.object.map):a.object.events.register("added",this,function(b){this.setMap(a.object.map)});else throw"Listeners for '"+this.provides.join("', '")+"' events can only be registered for OpenLayers.Layer.Vector or OpenLayers.Map instances";
-for(var b=this.provides.length-1;0<=b;--b)a.extensions[this.provides[b]]=!0},setMap:function(a){this.map=a;this.cache={};a.events.register("mousedown",this,this.start,{extension:!0});a.events.register("mouseup",this,this.onClick,{extension:!0});a.events.register("touchstart",this,this.start,{extension:!0});a.events.register("touchmove",this,this.cancel,{extension:!0});a.events.register("touchend",this,this.onClick,{extension:!0});a.events.register("mousemove",this,this.onMousemove,{extension:!0})},
-start:function(a){this.startEvt=a},cancel:function(a){delete this.startEvt},onClick:function(a){if(this.startEvt&&("touchend"===a.type||OpenLayers.Event.isLeftClick(a))){a=this.getFeatures(this.startEvt);delete this.startEvt;for(var b,c,d={},e=0,f=a.length;e<f&&(b=a[e],c=b.layer,d[c.id]=!0,b=this.triggerEvent("featureclick",{feature:b}),!1!==b);++e);e=0;for(f=this.map.layers.length;e<f;++e)c=this.map.layers[e],c instanceof OpenLayers.Layer.Vector&&!d[c.id]&&this.triggerEvent("nofeatureclick",{layer:c})}},
-onMousemove:function(a){delete this.startEvt;var b=this.getFeatures(a),c={};a=[];for(var d,e=0,f=b.length;e<f;++e)d=b[e],c[d.id]=d,this.cache[d.id]||a.push(d);var b=[],g;for(g in this.cache)d=this.cache[g],d.layer&&d.layer.map?c[d.id]||b.push(d):delete this.cache[g];e=0;for(f=a.length;e<f&&(d=a[e],this.cache[d.id]=d,g=this.triggerEvent("featureover",{feature:d}),!1!==g);++e);e=0;for(f=b.length;e<f&&(d=b[e],delete this.cache[d.id],g=this.triggerEvent("featureout",{feature:d}),!1!==g);++e);},triggerEvent:function(a,
-b){var c=b.feature?b.feature.layer:b.layer,d=this.target.object;if(d instanceof OpenLayers.Map||d===c)return this.target.triggerEvent(a,b)},getFeatures:function(a){var b=a.clientX,c=a.clientY,d=[],e=[],f=[],g,h,k,l;for(l=this.map.layers.length-1;0<=l;--l)if(g=this.map.layers[l],"none"!==g.div.style.display)if(g.renderer instanceof OpenLayers.Renderer.Elements){if(g instanceof OpenLayers.Layer.Vector)for(h=document.elementFromPoint(b,c);h&&h._featureId;)(k=g.getFeatureById(h._featureId))?(d.push(k),
-h.style.display="none",e.push(h),h=document.elementFromPoint(b,c)):h=!1;f.push(g);g.div.style.display="none"}else g.renderer instanceof OpenLayers.Renderer.Canvas&&(k=g.renderer.getFeatureIdFromEvent(a))&&(d.push(k),f.push(g));l=0;for(a=e.length;l<a;++l)e[l].style.display="";for(l=f.length-1;0<=l;--l)f[l].div.style.display="block";return d},destroy:function(){for(var a=this.provides.length-1;0<=a;--a)delete this.target.extensions[this.provides[a]];this.map.events.un({mousemove:this.onMousemove,mousedown:this.start,
-mouseup:this.onClick,touchstart:this.start,touchmove:this.cancel,touchend:this.onClick,scope:this});delete this.cache;delete this.map;delete this.target}});OpenLayers.Events.nofeatureclick=OpenLayers.Events.featureclick;OpenLayers.Events.featureover=OpenLayers.Events.featureclick;OpenLayers.Events.featureout=OpenLayers.Events.featureclick;OpenLayers.Format.GPX=OpenLayers.Class(OpenLayers.Format.XML,{defaultDesc:"No description available",extractWaypoints:!0,extractTracks:!0,extractRoutes:!0,extractAttributes:!0,namespaces:{gpx:"http://www.topografix.com/GPX/1/1",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd",creator:"OpenLayers",initialize:function(a){this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,
-[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=[];if(this.extractTracks)for(var c=a.getElementsByTagName("trk"),d=0,e=c.length;d<e;d++){var f={};this.extractAttributes&&(f=this.parseAttributes(c[d]));for(var g=this.getElementsByTagNameNS(c[d],c[d].namespaceURI,"trkseg"),h=0,k=g.length;h<k;h++){var l=this.extractSegment(g[h],"trkpt");b.push(new OpenLayers.Feature.Vector(l,f))}}if(this.extractRoutes)for(e=a.getElementsByTagName("rte"),c=0,d=
-e.length;c<d;c++)f={},this.extractAttributes&&(f=this.parseAttributes(e[c])),g=this.extractSegment(e[c],"rtept"),b.push(new OpenLayers.Feature.Vector(g,f));if(this.extractWaypoints)for(a=a.getElementsByTagName("wpt"),c=0,e=a.length;c<e;c++)f={},this.extractAttributes&&(f=this.parseAttributes(a[c])),d=new OpenLayers.Geometry.Point(a[c].getAttribute("lon"),a[c].getAttribute("lat")),b.push(new OpenLayers.Feature.Vector(d,f));if(this.internalProjection&&this.externalProjection)for(f=0,a=b.length;f<a;f++)b[f].geometry.transform(this.externalProjection,
-this.internalProjection);return b},extractSegment:function(a,b){for(var c=this.getElementsByTagNameNS(a,a.namespaceURI,b),d=[],e=0,f=c.length;e<f;e++)d.push(new OpenLayers.Geometry.Point(c[e].getAttribute("lon"),c[e].getAttribute("lat")));return new OpenLayers.Geometry.LineString(d)},parseAttributes:function(a){var b={};a=a.firstChild;for(var c,d;a;)1==a.nodeType&&a.firstChild&&(c=a.firstChild,3==c.nodeType||4==c.nodeType)&&(d=a.prefix?a.nodeName.split(":")[1]:a.nodeName,"trkseg"!=d&&"rtept"!=d&&
-(b[d]=c.nodeValue)),a=a.nextSibling;return b},write:function(a,b){a=OpenLayers.Util.isArray(a)?a:[a];var c=this.createElementNS(this.namespaces.gpx,"gpx");c.setAttribute("version","1.1");c.setAttribute("creator",this.creator);this.setAttributes(c,{"xsi:schemaLocation":this.schemaLocation});b&&"object"==typeof b&&c.appendChild(this.buildMetadataNode(b));for(var d=0,e=a.length;d<e;d++)c.appendChild(this.buildFeatureNode(a[d]));return OpenLayers.Format.XML.prototype.write.apply(this,[c])},buildMetadataNode:function(a){for(var b=
-["name","desc","author"],c=this.createElementNS(this.namespaces.gpx,"metadata"),d=0;d<b.length;d++){var e=b[d];if(a[e]){var f=this.createElementNS(this.namespaces.gpx,e);f.appendChild(this.createTextNode(a[e]));c.appendChild(f)}}return c},buildFeatureNode:function(a){var b=a.geometry,b=b.clone();this.internalProjection&&this.externalProjection&&b.transform(this.internalProjection,this.externalProjection);if("OpenLayers.Geometry.Point"==b.CLASS_NAME){var c=this.buildWptNode(b);this.appendAttributesNode(c,
-a);return c}c=this.createElementNS(this.namespaces.gpx,"trk");this.appendAttributesNode(c,a);a=this.buildTrkSegNode(b);a=OpenLayers.Util.isArray(a)?a:[a];for(var b=0,d=a.length;b<d;b++)c.appendChild(a[b]);return c},buildTrkSegNode:function(a){var b,c,d,e;if("OpenLayers.Geometry.LineString"==a.CLASS_NAME||"OpenLayers.Geometry.LinearRing"==a.CLASS_NAME){b=this.createElementNS(this.namespaces.gpx,"trkseg");c=0;for(d=a.components.length;c<d;c++)e=a.components[c],b.appendChild(this.buildTrkPtNode(e));
-return b}b=[];c=0;for(d=a.components.length;c<d;c++)b.push(this.buildTrkSegNode(a.components[c]));return b},buildTrkPtNode:function(a){var b=this.createElementNS(this.namespaces.gpx,"trkpt");b.setAttribute("lon",a.x);b.setAttribute("lat",a.y);return b},buildWptNode:function(a){var b=this.createElementNS(this.namespaces.gpx,"wpt");b.setAttribute("lon",a.x);b.setAttribute("lat",a.y);return b},appendAttributesNode:function(a,b){var c=this.createElementNS(this.namespaces.gpx,"name");c.appendChild(this.createTextNode(b.attributes.name||
-b.id));a.appendChild(c);c=this.createElementNS(this.namespaces.gpx,"desc");c.appendChild(this.createTextNode(b.attributes.description||this.defaultDesc));a.appendChild(c)},CLASS_NAME:"OpenLayers.Format.GPX"});OpenLayers.Format.WMSDescribeLayer=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.1",CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer"});OpenLayers.Format.WMSDescribeLayer.v1_1_1=OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer,{initialize:function(a){OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var b=a.documentElement.childNodes,c={layerDescriptions:[]},d,e,f=0;f<b.length;++f)if(d=b[f],e=d.nodeName,"LayerDescription"==e){e=d.getAttribute("name");var g="",h="",k="";d.getAttribute("owsType")?(g=d.getAttribute("owsType"),
-h=d.getAttribute("owsURL")):""!=d.getAttribute("wfs")?(g="WFS",h=d.getAttribute("wfs")):""!=d.getAttribute("wcs")&&(g="WCS",h=d.getAttribute("wcs"));d=d.getElementsByTagName("Query");0<d.length&&((k=d[0].getAttribute("typeName"))||(k=d[0].getAttribute("typename")));d={layerName:e,owsType:g,owsURL:h,typeName:k};c.layerDescriptions.push(d);c.length=c.layerDescriptions.length;c[c.length-1]=d}else if("ServiceException"==e)return{error:(new OpenLayers.Format.OGCExceptionReport).read(a)};return c},CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer.v1_1_1"});
-OpenLayers.Format.WMSDescribeLayer.v1_1_0=OpenLayers.Format.WMSDescribeLayer.v1_1_1;OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){null==a&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
-[a])},getURL:function(a){a=this.getXYZ(a);var b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w));a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h));b=this.getServerZoom();if(this.wrapDateLine)var d=Math.pow(2,b),c=(c%d+d)%d;return{x:c,y:a,z:b}},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,
-arguments);this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.bottom))},CLASS_NAME:"OpenLayers.Layer.XYZ"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",sphericalMercator:!0,wrapDateLine:!0,tileOptions:null,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=
-OpenLayers.Util.extend({crossOriginKeyword:"anonymous"},this.options&&this.options.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:!1,size:null,resolution:null,map:null,featureDx:0,initialize:function(a,b){this.container=OpenLayers.Util.getElement(a);OpenLayers.Util.extend(this,b)},destroy:function(){this.map=this.resolution=this.size=this.extent=this.container=null},supported:function(){return!1},setExtent:function(a,b){this.extent=a.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var c=a.getWidth()/this.map.getExtent().getWidth();
-a=a.scale(1/c);this.extent=a.wrapDateLine(this.map.getMaxExtent()).scale(c)}b&&(this.resolution=null);return!0},setSize:function(a){this.size=a.clone();this.resolution=null},getResolution:function(){return this.resolution=this.resolution||this.map.getResolution()},drawFeature:function(a,b){null==b&&(b=a.style);if(a.geometry){var c=a.geometry.getBounds();if(c){var d;this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&(d=this.map.getMaxExtent());c.intersectsBounds(this.extent,{worldBounds:d})?this.calculateFeatureDx(c,
-d):b={display:"none"};c=this.drawGeometry(a.geometry,b,a.id);if("none"!=b.display&&b.label&&!1!==c){d=a.geometry.getCentroid();if(b.labelXOffset||b.labelYOffset){var e=isNaN(b.labelXOffset)?0:b.labelXOffset,f=isNaN(b.labelYOffset)?0:b.labelYOffset,g=this.getResolution();d.move(e*g,f*g)}this.drawText(a.id,b,d)}else this.removeText(a.id);return c}}},calculateFeatureDx:function(a,b){this.featureDx=0;if(b){var c=b.getWidth();this.featureDx=Math.round(((a.left+a.right)/2-(this.extent.left+this.extent.right)/
-2)/c)*c}},drawGeometry:function(a,b,c){},drawText:function(a,b,c){},removeText:function(a){},clear:function(){},getFeatureIdFromEvent:function(a){},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b<c;++b){var d=a[b];this.eraseGeometry(d.geometry,d.id);this.removeText(d.id)}},eraseGeometry:function(a,b){},moveRoot:function(a){},getRenderLayerId:function(){return this.container.id},applyDefaultSymbolizer:function(a){var b=OpenLayers.Util.extend({},OpenLayers.Renderer.defaultSymbolizer);
-!1===a.stroke&&(delete b.strokeWidth,delete b.strokeColor);!1===a.fill&&delete b.fillColor;OpenLayers.Util.extend(b,a);return b},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Renderer.defaultSymbolizer={fillColor:"#000000",strokeColor:"#000000",strokeWidth:2,fillOpacity:1,strokeOpacity:1,pointRadius:0,labelAlign:"cm"};
-OpenLayers.Renderer.symbol={star:[350,75,379,161,469,161,397,215,423,301,350,250,277,301,303,215,231,161,321,161,350,75],cross:[4,0,6,0,6,4,10,4,10,6,6,6,6,10,4,10,4,6,0,6,0,4,4,4,4,0],x:[0,0,25,0,50,35,75,0,100,0,65,50,100,100,75,100,50,65,25,100,0,100,35,50,0,0],square:[0,0,0,1,1,1,1,0,0,0],triangle:[0,10,10,10,5,0,0,10]};OpenLayers.Renderer.Canvas=OpenLayers.Class(OpenLayers.Renderer,{hitDetection:!0,hitOverflow:0,canvas:null,features:null,pendingRedraw:!1,cachedSymbolBounds:{},initialize:function(a,b){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.root=document.createElement("canvas");this.container.appendChild(this.root);this.canvas=this.root.getContext("2d");this.features={};this.hitDetection&&(this.hitCanvas=document.createElement("canvas"),this.hitContext=this.hitCanvas.getContext("2d"))},
-setExtent:function(){OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);return!1},eraseGeometry:function(a,b){this.eraseFeatures(this.features[b][0])},supported:function(){return OpenLayers.CANVAS_SUPPORTED},setSize:function(a){this.size=a.clone();var b=this.root;b.style.width=a.w+"px";b.style.height=a.h+"px";b.width=a.w;b.height=a.h;this.resolution=null;this.hitDetection&&(b=this.hitCanvas,b.style.width=a.w+"px",b.style.height=a.h+"px",b.width=a.w,b.height=a.h)},drawFeature:function(a,
-b){var c;if(a.geometry){b=this.applyDefaultSymbolizer(b||a.style);c=a.geometry.getBounds();var d;this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&(d=this.map.getMaxExtent());d=c&&c.intersectsBounds(this.extent,{worldBounds:d});(c="none"!==b.display&&!!c&&d)?this.features[a.id]=[a,b]:delete this.features[a.id];this.pendingRedraw=!0}this.pendingRedraw&&!this.locked&&(this.redraw(),this.pendingRedraw=!1);return c},drawGeometry:function(a,b,c){var d=a.CLASS_NAME;if("OpenLayers.Geometry.Collection"==
-d||"OpenLayers.Geometry.MultiPoint"==d||"OpenLayers.Geometry.MultiLineString"==d||"OpenLayers.Geometry.MultiPolygon"==d)for(d=0;d<a.components.length;d++)this.drawGeometry(a.components[d],b,c);else switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":this.drawPoint(a,b,c);break;case "OpenLayers.Geometry.LineString":this.drawLineString(a,b,c);break;case "OpenLayers.Geometry.LinearRing":this.drawLinearRing(a,b,c);break;case "OpenLayers.Geometry.Polygon":this.drawPolygon(a,b,c)}},drawExternalGraphic:function(a,
-b,c){var d=new Image,e=b.title||b.graphicTitle;e&&(d.title=e);var f=b.graphicWidth||b.graphicHeight,g=b.graphicHeight||b.graphicWidth,f=f?f:2*b.pointRadius,g=g?g:2*b.pointRadius,h=void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*f),k=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*g),l=b.graphicOpacity||b.fillOpacity;d.onload=OpenLayers.Function.bind(function(){if(this.features[c]){var b=this.getLocalXY(a),e=b[0],b=b[1];if(!isNaN(e)&&!isNaN(b)){var e=e+h|0,b=b+k|0,p=this.canvas;p.globalAlpha=l;var q=
-OpenLayers.Renderer.Canvas.drawImageScaleFactor||(OpenLayers.Renderer.Canvas.drawImageScaleFactor=/android 2.1/.test(navigator.userAgent.toLowerCase())?320/window.screen.width:1);p.drawImage(d,e*q,b*q,f*q,g*q);this.hitDetection&&(this.setHitContextStyle("fill",c),this.hitContext.fillRect(e,b,f,g))}}},this);d.src=b.externalGraphic},drawNamedSymbol:function(a,b,c){var d,e,f,g;f=Math.PI/180;var h=OpenLayers.Renderer.symbol[b.graphicName];if(!h)throw Error(b.graphicName+" is not a valid symbol name");
-if(!(!h.length||2>h.length||(a=this.getLocalXY(a),e=a[0],g=a[1],isNaN(e)||isNaN(g)))){this.canvas.lineCap="round";this.canvas.lineJoin="round";this.hitDetection&&(this.hitContext.lineCap="round",this.hitContext.lineJoin="round");if(b.graphicName in this.cachedSymbolBounds)d=this.cachedSymbolBounds[b.graphicName];else{d=new OpenLayers.Bounds;for(a=0;a<h.length;a+=2)d.extend(new OpenLayers.LonLat(h[a],h[a+1]));this.cachedSymbolBounds[b.graphicName]=d}this.canvas.save();this.hitDetection&&this.hitContext.save();
-this.canvas.translate(e,g);this.hitDetection&&this.hitContext.translate(e,g);a=f*b.rotation;isNaN(a)||(this.canvas.rotate(a),this.hitDetection&&this.hitContext.rotate(a));f=2*b.pointRadius/Math.max(d.getWidth(),d.getHeight());this.canvas.scale(f,f);this.hitDetection&&this.hitContext.scale(f,f);a=d.getCenterLonLat().lon;d=d.getCenterLonLat().lat;this.canvas.translate(-a,-d);this.hitDetection&&this.hitContext.translate(-a,-d);g=b.strokeWidth;b.strokeWidth=g/f;if(!1!==b.fill){this.setCanvasStyle("fill",
-b);this.canvas.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.canvas.lineTo(d,e);this.canvas.closePath();this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",c,b);this.hitContext.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.hitContext.lineTo(d,e);this.hitContext.closePath();this.hitContext.fill()}}if(!1!==b.stroke){this.setCanvasStyle("stroke",b);this.canvas.beginPath();for(a=0;a<h.length;a+=2)d=h[a],
-e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.canvas.lineTo(d,e);this.canvas.closePath();this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",c,b,f);this.hitContext.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.hitContext.moveTo(d,e),this.hitContext.lineTo(d,e);this.hitContext.closePath();this.hitContext.stroke()}}b.strokeWidth=g;this.canvas.restore();this.hitDetection&&this.hitContext.restore();this.setCanvasStyle("reset")}},setCanvasStyle:function(a,b){"fill"===
-a?(this.canvas.globalAlpha=b.fillOpacity,this.canvas.fillStyle=b.fillColor):"stroke"===a?(this.canvas.globalAlpha=b.strokeOpacity,this.canvas.strokeStyle=b.strokeColor,this.canvas.lineWidth=b.strokeWidth):(this.canvas.globalAlpha=0,this.canvas.lineWidth=1)},featureIdToHex:function(a){a=Number(a.split("_").pop())+1;16777216<=a&&(this.hitOverflow=a-16777215,a=a%16777216+1);a="000000"+a.toString(16);var b=a.length;return a="#"+a.substring(b-6,b)},setHitContextStyle:function(a,b,c,d){b=this.featureIdToHex(b);
-"fill"==a?(this.hitContext.globalAlpha=1,this.hitContext.fillStyle=b):"stroke"==a?(this.hitContext.globalAlpha=1,this.hitContext.strokeStyle=b,"undefined"===typeof d?this.hitContext.lineWidth=c.strokeWidth+2:isNaN(d)||(this.hitContext.lineWidth=c.strokeWidth+2/d)):(this.hitContext.globalAlpha=0,this.hitContext.lineWidth=1)},drawPoint:function(a,b,c){if(!1!==b.graphic)if(b.externalGraphic)this.drawExternalGraphic(a,b,c);else if(b.graphicName&&"circle"!=b.graphicName)this.drawNamedSymbol(a,b,c);else{var d=
-this.getLocalXY(a);a=d[0];d=d[1];if(!isNaN(a)&&!isNaN(d)){var e=2*Math.PI,f=b.pointRadius;!1!==b.fill&&(this.setCanvasStyle("fill",b),this.canvas.beginPath(),this.canvas.arc(a,d,f,0,e,!0),this.canvas.fill(),this.hitDetection&&(this.setHitContextStyle("fill",c,b),this.hitContext.beginPath(),this.hitContext.arc(a,d,f,0,e,!0),this.hitContext.fill()));!1!==b.stroke&&(this.setCanvasStyle("stroke",b),this.canvas.beginPath(),this.canvas.arc(a,d,f,0,e,!0),this.canvas.stroke(),this.hitDetection&&(this.setHitContextStyle("stroke",
-c,b),this.hitContext.beginPath(),this.hitContext.arc(a,d,f,0,e,!0),this.hitContext.stroke()),this.setCanvasStyle("reset"))}}},drawLineString:function(a,b,c){b=OpenLayers.Util.applyDefaults({fill:!1},b);this.drawLinearRing(a,b,c)},drawLinearRing:function(a,b,c){!1!==b.fill&&(this.setCanvasStyle("fill",b),this.renderPath(this.canvas,a,b,c,"fill"),this.hitDetection&&(this.setHitContextStyle("fill",c,b),this.renderPath(this.hitContext,a,b,c,"fill")));!1!==b.stroke&&(this.setCanvasStyle("stroke",b),this.renderPath(this.canvas,
-a,b,c,"stroke"),this.hitDetection&&(this.setHitContextStyle("stroke",c,b),this.renderPath(this.hitContext,a,b,c,"stroke")));this.setCanvasStyle("reset")},renderPath:function(a,b,c,d,e){b=b.components;c=b.length;a.beginPath();d=this.getLocalXY(b[0]);var f=d[1];if(!isNaN(d[0])&&!isNaN(f)){a.moveTo(d[0],d[1]);for(d=1;d<c;++d)f=this.getLocalXY(b[d]),a.lineTo(f[0],f[1]);"fill"===e?a.fill():a.stroke()}},drawPolygon:function(a,b,c){a=a.components;var d=a.length;this.drawLinearRing(a[0],b,c);for(var e=1;e<
-d;++e)this.canvas.globalCompositeOperation="destination-out",this.hitDetection&&(this.hitContext.globalCompositeOperation="destination-out"),this.drawLinearRing(a[e],OpenLayers.Util.applyDefaults({stroke:!1,fillOpacity:1},b),c),this.canvas.globalCompositeOperation="source-over",this.hitDetection&&(this.hitContext.globalCompositeOperation="source-over"),this.drawLinearRing(a[e],OpenLayers.Util.applyDefaults({fill:!1},b),c)},drawText:function(a,b){var c=this.getLocalXY(a);this.setCanvasStyle("reset");
-this.canvas.fillStyle=b.fontColor;this.canvas.globalAlpha=b.fontOpacity||1;var d=[b.fontStyle?b.fontStyle:"normal","normal",b.fontWeight?b.fontWeight:"normal",b.fontSize?b.fontSize:"1em",b.fontFamily?b.fontFamily:"sans-serif"].join(" "),e=b.label.split("\n"),f=e.length;if(this.canvas.fillText){this.canvas.font=d;this.canvas.textAlign=OpenLayers.Renderer.Canvas.LABEL_ALIGN[b.labelAlign[0]]||"center";this.canvas.textBaseline=OpenLayers.Renderer.Canvas.LABEL_ALIGN[b.labelAlign[1]]||"middle";var g=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[1]];
-null==g&&(g=-0.5);d=this.canvas.measureText("Mg").height||this.canvas.measureText("xx").width;c[1]+=d*g*(f-1);for(g=0;g<f;g++)b.labelOutlineWidth&&(this.canvas.save(),this.canvas.globalAlpha=b.labelOutlineOpacity||b.fontOpacity||1,this.canvas.strokeStyle=b.labelOutlineColor,this.canvas.lineWidth=b.labelOutlineWidth,this.canvas.strokeText(e[g],c[0],c[1]+d*g+1),this.canvas.restore()),this.canvas.fillText(e[g],c[0],c[1]+d*g)}else if(this.canvas.mozDrawText){this.canvas.mozTextStyle=d;var h=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[0]];
-null==h&&(h=-0.5);g=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[1]];null==g&&(g=-0.5);d=this.canvas.mozMeasureText("xx");c[1]+=d*(1+g*f);for(g=0;g<f;g++){var k=c[0]+h*this.canvas.mozMeasureText(e[g]),l=c[1]+g*d;this.canvas.translate(k,l);this.canvas.mozDrawText(e[g]);this.canvas.translate(-k,-l)}}this.setCanvasStyle("reset")},getLocalXY:function(a){var b=this.getResolution(),c=this.extent;return[(a.x-this.featureDx)/b+-c.left/b,c.top/b-a.y/b]},clear:function(){var a=this.root.height,b=this.root.width;
-this.canvas.clearRect(0,0,b,a);this.features={};this.hitDetection&&this.hitContext.clearRect(0,0,b,a)},getFeatureIdFromEvent:function(a){var b;if(this.hitDetection&&"none"!==this.root.style.display&&!this.map.dragging&&(a=a.xy,a=this.hitContext.getImageData(a.x|0,a.y|0,1,1).data,255===a[3]&&(a=a[2]+256*(a[1]+256*a[0])))){a="OpenLayers_Feature_Vector_"+(a-1+this.hitOverflow);try{b=this.features[a][0]}catch(c){}}return b},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0;b<a.length;++b)delete this.features[a[b].id];
-this.redraw()},redraw:function(){if(!this.locked){var a=this.root.height,b=this.root.width;this.canvas.clearRect(0,0,b,a);this.hitDetection&&this.hitContext.clearRect(0,0,b,a);var a=[],c,d,e=this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent(),f;for(f in this.features)this.features.hasOwnProperty(f)&&(b=this.features[f][0],c=b.geometry,this.calculateFeatureDx(c.getBounds(),e),d=this.features[f][1],this.drawGeometry(c,d,b.id),d.label&&a.push([b,d]));b=0;for(c=a.length;b<c;++b)f=
-a[b],this.drawText(f[0].geometry.getCentroid(),f[1])}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={l:"left",r:"right",t:"top",b:"bottom"};OpenLayers.Renderer.Canvas.LABEL_FACTOR={l:0,r:-1,t:0,b:-1};OpenLayers.Renderer.Canvas.drawImageScaleFactor=null;OpenLayers.Format.OSM=OpenLayers.Class(OpenLayers.Format.XML,{checkTags:!1,interestingTagsExclude:null,areaTags:null,initialize:function(a){var b={interestingTagsExclude:"source source_ref source:ref history attribution created_by".split(" "),areaTags:"area building leisure tourism ruins historic landuse military natural sport".split(" ")},b=OpenLayers.Util.extend(b,a),c={};for(a=0;a<b.interestingTagsExclude.length;a++)c[b.interestingTagsExclude[a]]=!0;b.interestingTagsExclude=c;c={};for(a=0;a<b.areaTags.length;a++)c[b.areaTags[a]]=
-!0;b.areaTags=c;this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[b])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=this.getNodes(a),c=this.getWays(a);a=Array(c.length);for(var d=0;d<c.length;d++){for(var e=Array(c[d].nodes.length),f=this.isWayArea(c[d])?1:0,g=0;g<c[d].nodes.length;g++){var h=b[c[d].nodes[g]],k=new OpenLayers.Geometry.Point(h.lon,h.lat);k.osm_id=parseInt(c[d].nodes[g]);
-e[g]=k;h.used=!0}h=null;h=f?new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(e)):new OpenLayers.Geometry.LineString(e);this.internalProjection&&this.externalProjection&&h.transform(this.externalProjection,this.internalProjection);e=new OpenLayers.Feature.Vector(h,c[d].tags);e.osm_id=parseInt(c[d].id);e.fid="way."+e.osm_id;a[d]=e}for(var l in b){h=b[l];if(!h.used||this.checkTags){c=null;if(this.checkTags){c=this.getTags(h.node,!0);if(h.used&&!c[1])continue;c=c[0]}else c=this.getTags(h.node);
-e=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(h.lon,h.lat),c);this.internalProjection&&this.externalProjection&&e.geometry.transform(this.externalProjection,this.internalProjection);e.osm_id=parseInt(l);e.fid="node."+e.osm_id;a.push(e)}h.node=null}return a},getNodes:function(a){a=a.getElementsByTagName("node");for(var b={},c=0;c<a.length;c++){var d=a[c],e=d.getAttribute("id");b[e]={lat:d.getAttribute("lat"),lon:d.getAttribute("lon"),node:d}}return b},getWays:function(a){a=a.getElementsByTagName("way");
-for(var b=[],c=0;c<a.length;c++){var d=a[c],e={id:d.getAttribute("id")};e.tags=this.getTags(d);d=d.getElementsByTagName("nd");e.nodes=Array(d.length);for(var f=0;f<d.length;f++)e.nodes[f]=d[f].getAttribute("ref");b.push(e)}return b},getTags:function(a,b){for(var c=a.getElementsByTagName("tag"),d={},e=!1,f=0;f<c.length;f++){var g=c[f].getAttribute("k");d[g]=c[f].getAttribute("v");b&&(this.interestingTagsExclude[g]||(e=!0))}return b?[d,e]:d},isWayArea:function(a){var b=!1,c=!1;a.nodes[0]==a.nodes[a.nodes.length-
-1]&&(b=!0);if(this.checkTags)for(var d in a.tags)if(this.areaTags[d]){c=!0;break}return b&&(this.checkTags?c:!0)},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);this.osm_id=1;this.created_nodes={};var b=this.createElementNS(null,"osm");b.setAttribute("version","0.5");b.setAttribute("generator","OpenLayers "+OpenLayers.VERSION_NUMBER);for(var c=a.length-1;0<=c;c--)for(var d=this.createFeatureNodes(a[c]),e=0;e<d.length;e++)b.appendChild(d[e]);return OpenLayers.Format.XML.prototype.write.apply(this,
-[b])},createFeatureNodes:function(a){var b=[],c=a.geometry.CLASS_NAME,c=c.substring(c.lastIndexOf(".")+1),c=c.toLowerCase();(c=this.createXML[c])&&(b=c.apply(this,[a]));return b},createXML:{point:function(a){var b=null,c=a.geometry?a.geometry:a;this.internalProjection&&this.externalProjection&&(c=c.clone(),c.transform(this.internalProjection,this.externalProjection));var d=!1;a.osm_id?(b=a.osm_id,this.created_nodes[b]&&(d=!0)):(b=-this.osm_id,this.osm_id++);var e=d?this.created_nodes[b]:this.createElementNS(null,
-"node");this.created_nodes[b]=e;e.setAttribute("id",b);e.setAttribute("lon",c.x);e.setAttribute("lat",c.y);a.attributes&&this.serializeTags(a,e);this.setState(a,e);return d?[]:[e]},linestring:function(a){var b,c=[],d=a.geometry;a.osm_id?b=a.osm_id:(b=-this.osm_id,this.osm_id++);var e=this.createElementNS(null,"way");e.setAttribute("id",b);for(b=0;b<d.components.length;b++){var f=this.createXML.point.apply(this,[d.components[b]]);if(f.length){var f=f[0],g=f.getAttribute("id");c.push(f)}else g=d.components[b].osm_id,
-f=this.created_nodes[g];this.setState(a,f);f=this.createElementNS(null,"nd");f.setAttribute("ref",g);e.appendChild(f)}this.serializeTags(a,e);c.push(e);return c},polygon:function(a){var b=OpenLayers.Util.extend({area:"yes"},a.attributes),b=new OpenLayers.Feature.Vector(a.geometry.components[0],b);b.osm_id=a.osm_id;return this.createXML.linestring.apply(this,[b])}},serializeTags:function(a,b){for(var c in a.attributes){var d=this.createElementNS(null,"tag");d.setAttribute("k",c);d.setAttribute("v",
-a.attributes[c]);b.appendChild(d)}},setState:function(a,b){if(a.state){var c=null;switch(a.state){case OpenLayers.State.UPDATE:case OpenLayers.State.DELETE:c="delete"}c&&b.setAttribute("action",c)}},CLASS_NAME:"OpenLayers.Format.OSM"});OpenLayers.Handler.Keyboard=OpenLayers.Class(OpenLayers.Handler,{KEY_EVENTS:["keydown","keyup"],eventListener:null,observeElement:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.eventListener=OpenLayers.Function.bindAsEventListener(this.handleKeyEvent,this)},destroy:function(){this.deactivate();this.eventListener=null;OpenLayers.Handler.prototype.destroy.apply(this,arguments)},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,
-arguments)){this.observeElement=this.observeElement||document;for(var a=0,b=this.KEY_EVENTS.length;a<b;a++)OpenLayers.Event.observe(this.observeElement,this.KEY_EVENTS[a],this.eventListener);return!0}return!1},deactivate:function(){var a=!1;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){for(var a=0,b=this.KEY_EVENTS.length;a<b;a++)OpenLayers.Event.stopObserving(this.observeElement,this.KEY_EVENTS[a],this.eventListener);a=!0}return a},handleKeyEvent:function(a){this.checkModifiers(a)&&
-this.callback(a.type,[a])},CLASS_NAME:"OpenLayers.Handler.Keyboard"});OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{documentDrag:!1,geometryTypes:null,clickout:!0,toggle:!0,standalone:!1,layer:null,feature:null,vertex:null,vertices:null,virtualVertices:null,handlers:null,deleteCodes:null,virtualStyle:null,vertexRenderIntent:null,mode:null,createVertices:!0,modified:!1,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(a,b){b=b||{};this.layer=a;this.vertices=
-[];this.virtualVertices=[];this.virtualStyle=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer(null,b.vertexRenderIntent));this.virtualStyle.fillOpacity=0.3;this.virtualStyle.strokeOpacity=0.3;this.deleteCodes=[46,68];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[b]);OpenLayers.Util.isArray(this.deleteCodes)||(this.deleteCodes=[this.deleteCodes]);var c={documentDrag:this.documentDrag,stopDown:!1};this.handlers=
-{keyboard:new OpenLayers.Handler.Keyboard(this,{keydown:this.handleKeypress}),drag:new OpenLayers.Handler.Drag(this,{down:function(a){this.vertex=null;(a=this.layer.getFeatureFromEvent(this.handlers.drag.evt))?this.dragStart(a):this.clickout&&(this._unselect=this.feature)},move:function(a){delete this._unselect;this.vertex&&this.dragVertex(this.vertex,a)},up:function(){this.handlers.drag.stopDown=!1;this._unselect&&(this.unselectFeature(this._unselect),delete this._unselect)},done:function(a){this.vertex&&
-this.dragComplete(this.vertex)}},c)}},destroy:function(){this.map&&this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){this.moveLayerToTop();this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this});return this.handlers.keyboard.activate()&&this.handlers.drag.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments)},
-deactivate:function(){var a=!1;OpenLayers.Control.prototype.deactivate.apply(this,arguments)&&(this.moveLayerBack(),this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),this.layer.removeFeatures(this.vertices,{silent:!0}),this.layer.removeFeatures(this.virtualVertices,{silent:!0}),this.vertices=[],this.handlers.drag.deactivate(),this.handlers.keyboard.deactivate(),(a=this.feature)&&(a.geometry&&a.layer)&&this.unselectFeature(a),a=!0);return a},beforeSelectFeature:function(a){return this.layer.events.triggerEvent("beforefeaturemodified",
-{feature:a})},selectFeature:function(a){if(!(this.feature===a||this.geometryTypes&&-1==OpenLayers.Util.indexOf(this.geometryTypes,a.geometry.CLASS_NAME))){!1!==this.beforeSelectFeature(a)&&(this.feature&&this.unselectFeature(this.feature),this.feature=a,this.layer.selectedFeatures.push(a),this.layer.drawFeature(a,"select"),this.modified=!1,this.resetVertices(),this.onModificationStart(this.feature));var b=a.modified;!a.geometry||b&&b.geometry||(this._originalGeometry=a.geometry.clone())}},unselectFeature:function(a){this.layer.removeFeatures(this.vertices,
-{silent:!0});this.vertices=[];this.layer.destroyFeatures(this.virtualVertices,{silent:!0});this.virtualVertices=[];this.dragHandle&&(this.layer.destroyFeatures([this.dragHandle],{silent:!0}),delete this.dragHandle);this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),delete this.radiusHandle);this.layer.drawFeature(this.feature,"default");this.feature=null;OpenLayers.Util.removeItem(this.layer.selectedFeatures,a);this.onModificationEnd(a);this.layer.events.triggerEvent("afterfeaturemodified",
-{feature:a,modified:this.modified});this.modified=!1},dragStart:function(a){var b="OpenLayers.Geometry.Point"==a.geometry.CLASS_NAME;this.standalone||(a._sketch||!b)&&a._sketch||(this.toggle&&this.feature===a&&(this._unselect=a),this.selectFeature(a));if(a._sketch||b)this.vertex=a,this.handlers.drag.stopDown=!0},dragVertex:function(a,b){var c=this.map.getLonLatFromViewPortPx(b),d=a.geometry;d.move(c.lon-d.x,c.lat-d.y);this.modified=!0;"OpenLayers.Geometry.Point"==this.feature.geometry.CLASS_NAME?
-this.layer.events.triggerEvent("vertexmodified",{vertex:a.geometry,feature:this.feature,pixel:b}):(a._index?(a.geometry.parent.addComponent(a.geometry,a._index),delete a._index,OpenLayers.Util.removeItem(this.virtualVertices,a),this.vertices.push(a)):a==this.dragHandle?(this.layer.removeFeatures(this.vertices,{silent:!0}),this.vertices=[],this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),this.radiusHandle=null)):a!==this.radiusHandle&&this.layer.events.triggerEvent("vertexmodified",
-{vertex:a.geometry,feature:this.feature,pixel:b}),0<this.virtualVertices.length&&(this.layer.destroyFeatures(this.virtualVertices,{silent:!0}),this.virtualVertices=[]),this.layer.drawFeature(this.feature,this.standalone?void 0:"select"));this.layer.drawFeature(a)},dragComplete:function(a){this.resetVertices();this.setFeatureState();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature})},setFeatureState:function(){if(this.feature.state!=OpenLayers.State.INSERT&&
-this.feature.state!=OpenLayers.State.DELETE&&(this.feature.state=OpenLayers.State.UPDATE,this.modified&&this._originalGeometry)){var a=this.feature;a.modified=OpenLayers.Util.extend(a.modified,{geometry:this._originalGeometry});delete this._originalGeometry}},resetVertices:function(){0<this.vertices.length&&(this.layer.removeFeatures(this.vertices,{silent:!0}),this.vertices=[]);0<this.virtualVertices.length&&(this.layer.removeFeatures(this.virtualVertices,{silent:!0}),this.virtualVertices=[]);this.dragHandle&&
-(this.layer.destroyFeatures([this.dragHandle],{silent:!0}),this.dragHandle=null);this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),this.radiusHandle=null);this.feature&&"OpenLayers.Geometry.Point"!=this.feature.geometry.CLASS_NAME&&(this.mode&OpenLayers.Control.ModifyFeature.DRAG&&this.collectDragHandle(),this.mode&(OpenLayers.Control.ModifyFeature.ROTATE|OpenLayers.Control.ModifyFeature.RESIZE)&&this.collectRadiusHandle(),this.mode&OpenLayers.Control.ModifyFeature.RESHAPE&&
-(this.mode&OpenLayers.Control.ModifyFeature.RESIZE||this.collectVertices()))},handleKeypress:function(a){var b=a.keyCode;this.feature&&-1!=OpenLayers.Util.indexOf(this.deleteCodes,b)&&(b=this.layer.getFeatureFromEvent(this.handlers.drag.evt))&&(-1!=OpenLayers.Util.indexOf(this.vertices,b)&&!this.handlers.drag.dragging&&b.geometry.parent)&&(b.geometry.parent.removeComponent(b.geometry),this.layer.events.triggerEvent("vertexremoved",{vertex:b.geometry,feature:this.feature,pixel:a.xy}),this.layer.drawFeature(this.feature,
-this.standalone?void 0:"select"),this.modified=!0,this.resetVertices(),this.setFeatureState(),this.onModification(this.feature),this.layer.events.triggerEvent("featuremodified",{feature:this.feature}))},collectVertices:function(){function a(c){var d,e,f;if("OpenLayers.Geometry.Point"==c.CLASS_NAME)e=new OpenLayers.Feature.Vector(c),e._sketch=!0,e.renderIntent=b.vertexRenderIntent,b.vertices.push(e);else{f=c.components.length;"OpenLayers.Geometry.LinearRing"==c.CLASS_NAME&&(f-=1);for(d=0;d<f;++d)e=
-c.components[d],"OpenLayers.Geometry.Point"==e.CLASS_NAME?(e=new OpenLayers.Feature.Vector(e),e._sketch=!0,e.renderIntent=b.vertexRenderIntent,b.vertices.push(e)):a(e);if(b.createVertices&&"OpenLayers.Geometry.MultiPoint"!=c.CLASS_NAME)for(d=0,f=c.components.length;d<f-1;++d){e=c.components[d];var g=c.components[d+1];"OpenLayers.Geometry.Point"==e.CLASS_NAME&&"OpenLayers.Geometry.Point"==g.CLASS_NAME&&(e=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point((e.x+g.x)/2,(e.y+g.y)/2),null,b.virtualStyle),
-e.geometry.parent=c,e._index=d+1,e._sketch=!0,b.virtualVertices.push(e))}}}this.vertices=[];this.virtualVertices=[];var b=this;a.call(this,this.feature.geometry);this.layer.addFeatures(this.virtualVertices,{silent:!0});this.layer.addFeatures(this.vertices,{silent:!0})},collectDragHandle:function(){var a=this.feature.geometry,b=a.getBounds().getCenterLonLat(),b=new OpenLayers.Geometry.Point(b.lon,b.lat),c=new OpenLayers.Feature.Vector(b);b.move=function(b,c){OpenLayers.Geometry.Point.prototype.move.call(this,
-b,c);a.move(b,c)};c._sketch=!0;this.dragHandle=c;this.dragHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.dragHandle],{silent:!0})},collectRadiusHandle:function(){var a=this.feature.geometry,b=a.getBounds(),c=b.getCenterLonLat(),d=new OpenLayers.Geometry.Point(c.lon,c.lat),b=new OpenLayers.Geometry.Point(b.right,b.bottom),c=new OpenLayers.Feature.Vector(b),e=this.mode&OpenLayers.Control.ModifyFeature.RESIZE,f=this.mode&OpenLayers.Control.ModifyFeature.RESHAPE,g=this.mode&
-OpenLayers.Control.ModifyFeature.ROTATE;b.move=function(b,c){OpenLayers.Geometry.Point.prototype.move.call(this,b,c);var l=this.x-d.x,m=this.y-d.y,n=l-b,p=m-c;if(g){var q=Math.atan2(p,n),q=Math.atan2(m,l)-q,q=q*(180/Math.PI);a.rotate(q,d)}if(e){var r;f?(m/=p,r=l/n/m):(n=Math.sqrt(n*n+p*p),m=Math.sqrt(l*l+m*m)/n);a.resize(m,d,r)}};c._sketch=!0;this.radiusHandle=c;this.radiusHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.radiusHandle],{silent:!0})},setMap:function(a){this.handlers.drag.setMap(a);
-OpenLayers.Control.prototype.setMap.apply(this,arguments)},handleMapEvents:function(a){"removelayer"!=a.type&&"order"!=a.property||this.moveLayerToTop()},moveLayerToTop:function(){var a=Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1;this.layer.setZIndex(a)},moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});
-OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Layer.Bing=OpenLayers.Class(OpenLayers.Layer.XYZ,{key:null,serverResolutions:[156543.03390625,78271.516953125,39135.7584765625,19567.87923828125,9783.939619140625,4891.9698095703125,2445.9849047851562,1222.9924523925781,611.4962261962891,305.74811309814453,152.87405654907226,76.43702827453613,38.218514137268066,19.109257068634033,9.554628534317017,4.777314267158508,2.388657133579254,1.194328566789627,0.5971642833948135,0.29858214169740677,0.14929107084870338,0.07464553542435169],attributionTemplate:'<span class="olBingAttribution ${type}"><div><a target="_blank" href="http://www.bing.com/maps/"><img src="${logo}" /></a></div>${copyrights}<a style="white-space: nowrap" target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a></span>',
-metadata:null,protocolRegex:/^http:/i,type:"Road",culture:"en-US",metadataParams:null,tileOptions:null,protocol:~window.location.href.indexOf("http")?"":"http:",initialize:function(a){a=OpenLayers.Util.applyDefaults({sphericalMercator:!0},a);OpenLayers.Layer.XYZ.prototype.initialize.apply(this,[a.name||"Bing "+(a.type||this.type),null,a]);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"},this.options.tileOptions);this.loadMetadata()},loadMetadata:function(){this._callbackId=
-"_callback_"+this.id.replace(/\./g,"_");window[this._callbackId]=OpenLayers.Function.bind(OpenLayers.Layer.Bing.processMetadata,this);var a=OpenLayers.Util.applyDefaults({key:this.key,jsonp:this._callbackId,include:"ImageryProviders"},this.metadataParams),a=this.protocol+"//dev.virtualearth.net/REST/v1/Imagery/Metadata/"+this.type+"?"+OpenLayers.Util.getParameterString(a),b=document.createElement("script");b.type="text/javascript";b.src=a;b.id=this._callbackId;document.getElementsByTagName("head")[0].appendChild(b)},
-initLayer:function(){var a=this.metadata.resourceSets[0].resources[0],b=a.imageUrl.replace("{quadkey}","${quadkey}"),b=b.replace("{culture}",this.culture),b=b.replace(this.protocolRegex,this.protocol);this.url=[];for(var c=0;c<a.imageUrlSubdomains.length;++c)this.url.push(b.replace("{subdomain}",a.imageUrlSubdomains[c]));this.addOptions({maxResolution:Math.min(this.serverResolutions[a.zoomMin],this.maxResolution||Number.POSITIVE_INFINITY),numZoomLevels:Math.min(a.zoomMax+1-a.zoomMin,this.numZoomLevels)},
-!0);this.isBaseLayer||this.redraw();this.updateAttribution()},getURL:function(a){if(this.url){var b=this.getXYZ(a);a=b.x;for(var c=b.y,b=b.z,d=[],e=b;0<e;--e){var f="0",g=1<<e-1;0!=(a&g)&&f++;0!=(c&g)&&(f++,f++);d.push(f)}d=d.join("");a=this.selectUrl(""+a+c+b,this.url);return OpenLayers.String.format(a,{quadkey:d})}},updateAttribution:function(){var a=this.metadata;if(a.resourceSets&&this.map&&this.map.center){var b=a.resourceSets[0].resources[0],c=this.map.getExtent().transform(this.map.getProjectionObject(),
-new OpenLayers.Projection("EPSG:4326")),d=b.imageryProviders||[],e=OpenLayers.Util.indexOf(this.serverResolutions,this.getServerResolution()),b="",f,g,h,k,l,m,n;g=0;for(h=d.length;g<h;++g)for(f=d[g],k=0,l=f.coverageAreas.length;k<l;++k)n=f.coverageAreas[k],m=OpenLayers.Bounds.fromArray(n.bbox,!0),c.intersectsBounds(m)&&(e<=n.zoomMax&&e>=n.zoomMin)&&(b+=f.attribution+" ");a=a.brandLogoUri.replace(this.protocolRegex,this.protocol);this.attribution=OpenLayers.String.format(this.attributionTemplate,{type:this.type.toLowerCase(),
-logo:a,copyrights:b});this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"attribution"})}},setMap:function(){OpenLayers.Layer.XYZ.prototype.setMap.apply(this,arguments);this.map.events.register("moveend",this,this.updateAttribution)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Bing(this.options));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},destroy:function(){this.map&&this.map.events.unregister("moveend",this,this.updateAttribution);OpenLayers.Layer.XYZ.prototype.destroy.apply(this,
-arguments)},CLASS_NAME:"OpenLayers.Layer.Bing"});OpenLayers.Layer.Bing.processMetadata=function(a){this.metadata=a;this.initLayer();a=document.getElementById(this._callbackId);a.parentNode.removeChild(a);window[this._callbackId]=void 0;delete this._callbackId};OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:!0,initialize:function(a,b){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),select:new OpenLayers.Style(OpenLayers.Feature.Vector.style.select),temporary:new OpenLayers.Style(OpenLayers.Feature.Vector.style.temporary),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(a instanceof OpenLayers.Style)this.styles["default"]=a,this.styles.select=a,this.styles.temporary=a,this.styles["delete"]=
-a;else if("object"==typeof a)for(var c in a)if(a[c]instanceof OpenLayers.Style)this.styles[c]=a[c];else if("object"==typeof a[c])this.styles[c]=new OpenLayers.Style(a[c]);else{this.styles["default"]=new OpenLayers.Style(a);this.styles.select=new OpenLayers.Style(a);this.styles.temporary=new OpenLayers.Style(a);this.styles["delete"]=new OpenLayers.Style(a);break}OpenLayers.Util.extend(this,b)},destroy:function(){for(var a in this.styles)this.styles[a].destroy();this.styles=null},createSymbolizer:function(a,
-b){a||(a=new OpenLayers.Feature.Vector);this.styles[b]||(b="default");a.renderIntent=b;var c={};this.extendDefault&&"default"!=b&&(c=this.styles["default"].createSymbolizer(a));return OpenLayers.Util.extend(c,this.styles[b].createSymbolizer(a))},addUniqueValueRules:function(a,b,c,d){var e=[],f;for(f in c)e.push(new OpenLayers.Rule({symbolizer:c[f],context:d,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:b,value:f})}));this.styles[a].addRules(e)},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,isFixed:!1,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:!0,style:null,styleMap:null,strategies:null,protocol:null,renderers:["SVG","VML","Canvas"],renderer:null,rendererOptions:null,geometryType:null,drawn:!1,ratio:1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.renderer&&this.renderer.supported()||this.assignRenderer();this.renderer&&this.renderer.supported()||
-(this.renderer=null,this.displayError());this.styleMap||(this.styleMap=new OpenLayers.StyleMap);this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies)for(var c=0,d=this.strategies.length;c<d;c++)this.strategies[c].setLayer(this)},destroy:function(){if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoDestroy&&a.destroy();this.strategies=null}this.protocol&&(this.protocol.autoDestroy&&this.protocol.destroy(),this.protocol=
-null);this.destroyFeatures();this.unrenderedFeatures=this.selectedFeatures=this.features=null;this.renderer&&this.renderer.destroy();this.drawn=this.geometryType=this.renderer=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Vector(this.name,this.getOptions()));a=OpenLayers.Layer.prototype.clone.apply(this,[a]);for(var b=this.features,c=b.length,d=Array(c),e=0;e<c;++e)d[e]=b[e].clone();a.features=d;return a},refresh:function(a){this.calculateInRange()&&
-this.visibility&&this.events.triggerEvent("refresh",a)},assignRenderer:function(){for(var a=0,b=this.renderers.length;a<b;a++){var c=this.renderers[a];if((c="function"==typeof c?c:OpenLayers.Renderer[c])&&c.prototype.supported()){this.renderer=new c(this.div,this.rendererOptions);break}}},displayError:function(){this.reportError&&OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",{renderers:this.renderers.join("\n")}))},setMap:function(a){OpenLayers.Layer.prototype.setMap.apply(this,
-arguments);if(this.renderer){this.renderer.map=this.map;var b=this.map.getSize();b.w*=this.ratio;b.h*=this.ratio;this.renderer.setSize(b)}else this.map.removeLayer(this)},afterAdd:function(){if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoActivate&&a.activate()}},removeMap:function(a){this.drawn=!1;if(this.strategies){var b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoActivate&&a.deactivate()}},onMapResize:function(){OpenLayers.Layer.prototype.onMapResize.apply(this,
-arguments);var a=this.map.getSize();a.w*=this.ratio;a.h*=this.ratio;this.renderer.setSize(a)},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var d=!0;if(!c){this.renderer.root.style.visibility="hidden";var d=this.map.getSize(),e=d.w,d=d.h,e=e/2*this.ratio-e/2,d=d/2*this.ratio-d/2,e=e+this.map.layerContainerOriginPx.x,e=-Math.round(e),d=d+this.map.layerContainerOriginPx.y,d=-Math.round(d);this.div.style.left=e+"px";this.div.style.top=d+"px";e=this.map.getExtent().scale(this.ratio);
-d=this.renderer.setExtent(e,b);this.renderer.root.style.visibility="visible";!0===OpenLayers.IS_GECKO&&(this.div.scrollLeft=this.div.scrollLeft);if(!b&&d)for(var f in this.unrenderedFeatures)e=this.unrenderedFeatures[f],this.drawFeature(e)}if(!this.drawn||b||!d)for(this.drawn=!0,f=0,d=this.features.length;f<d;f++)this.renderer.locked=f!==d-1,e=this.features[f],this.drawFeature(e)},display:function(a){OpenLayers.Layer.prototype.display.apply(this,arguments);var b=this.div.style.display;b!=this.renderer.root.style.display&&
-(this.renderer.root.style.display=b)},addFeatures:function(a,b){OpenLayers.Util.isArray(a)||(a=[a]);var c=!b||!b.silent;if(c){var d={features:a};if(!1===this.events.triggerEvent("beforefeaturesadded",d))return;a=d.features}for(var d=[],e=0,f=a.length;e<f;e++){this.renderer.locked=e!=a.length-1?!0:!1;var g=a[e];if(this.geometryType&&!(g.geometry instanceof this.geometryType))throw new TypeError("addFeatures: component should be an "+this.geometryType.prototype.CLASS_NAME);g.layer=this;!g.style&&this.style&&
-(g.style=OpenLayers.Util.extend({},this.style));if(c){if(!1===this.events.triggerEvent("beforefeatureadded",{feature:g}))continue;this.preFeatureInsert(g)}d.push(g);this.features.push(g);this.drawFeature(g);c&&(this.events.triggerEvent("featureadded",{feature:g}),this.onFeatureInsert(g))}c&&this.events.triggerEvent("featuresadded",{features:d})},removeFeatures:function(a,b){if(a&&0!==a.length){if(a===this.features)return this.removeAllFeatures(b);OpenLayers.Util.isArray(a)||(a=[a]);a===this.selectedFeatures&&
-(a=a.slice());var c=!b||!b.silent;c&&this.events.triggerEvent("beforefeaturesremoved",{features:a});for(var d=a.length-1;0<=d;d--){this.renderer.locked=0!=d&&a[d-1].geometry?!0:!1;var e=a[d];delete this.unrenderedFeatures[e.id];c&&this.events.triggerEvent("beforefeatureremoved",{feature:e});this.features=OpenLayers.Util.removeItem(this.features,e);e.layer=null;e.geometry&&this.renderer.eraseFeatures(e);-1!=OpenLayers.Util.indexOf(this.selectedFeatures,e)&&OpenLayers.Util.removeItem(this.selectedFeatures,
-e);c&&this.events.triggerEvent("featureremoved",{feature:e})}c&&this.events.triggerEvent("featuresremoved",{features:a})}},removeAllFeatures:function(a){a=!a||!a.silent;var b=this.features;a&&this.events.triggerEvent("beforefeaturesremoved",{features:b});for(var c,d=b.length-1;0<=d;d--)c=b[d],a&&this.events.triggerEvent("beforefeatureremoved",{feature:c}),c.layer=null,a&&this.events.triggerEvent("featureremoved",{feature:c});this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures=
-[];a&&this.events.triggerEvent("featuresremoved",{features:b})},destroyFeatures:function(a,b){void 0==a&&(a=this.features);if(a){this.removeFeatures(a,b);for(var c=a.length-1;0<=c;c--)a[c].destroy()}},drawFeature:function(a,b){if(this.drawn){if("object"!=typeof b){b||a.state!==OpenLayers.State.DELETE||(b="delete");var c=b||a.renderIntent;(b=a.style||this.style)||(b=this.styleMap.createSymbolizer(a,c))}c=this.renderer.drawFeature(a,b);!1===c||null===c?this.unrenderedFeatures[a.id]=a:delete this.unrenderedFeatures[a.id]}},
-eraseFeatures:function(a){this.renderer.eraseFeatures(a)},getFeatureFromEvent:function(a){if(!this.renderer)throw Error("getFeatureFromEvent called on layer with no renderer. This usually means you destroyed a layer, but not some handler which is associated with it.");var b=null;(a=this.renderer.getFeatureIdFromEvent(a))&&(b="string"===typeof a?this.getFeatureById(a):a);return b},getFeatureBy:function(a,b){for(var c=null,d=0,e=this.features.length;d<e;++d)if(this.features[d][a]==b){c=this.features[d];
-break}return c},getFeatureById:function(a){return this.getFeatureBy("id",a)},getFeatureByFid:function(a){return this.getFeatureBy("fid",a)},getFeaturesByAttribute:function(a,b){var c,d,e=this.features.length,f=[];for(c=0;c<e;c++)(d=this.features[c])&&d.attributes&&d.attributes[a]===b&&f.push(d);return f},onFeatureInsert:function(a){},preFeatureInsert:function(a){},getDataExtent:function(){var a=null,b=this.features;if(b&&0<b.length)for(var c=null,d=0,e=b.length;d<e;d++)if(c=b[d].geometry)null===a&&
-(a=new OpenLayers.Bounds),a.extend(c.getBounds());return a},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.PointGrid=OpenLayers.Class(OpenLayers.Layer.Vector,{dx:null,dy:null,ratio:1.5,maxFeatures:250,rotation:0,origin:null,gridBounds:null,initialize:function(a){a=a||{};OpenLayers.Layer.Vector.prototype.initialize.apply(this,[a.name,a])},setMap:function(a){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);a.events.register("moveend",this,this.onMoveEnd)},removeMap:function(a){a.events.unregister("moveend",this,this.onMoveEnd);OpenLayers.Layer.Vector.prototype.removeMap.apply(this,
-arguments)},setRatio:function(a){this.ratio=a;this.updateGrid(!0)},setMaxFeatures:function(a){this.maxFeatures=a;this.updateGrid(!0)},setSpacing:function(a,b){this.dx=a;this.dy=b||a;this.updateGrid(!0)},setOrigin:function(a){this.origin=a;this.updateGrid(!0)},getOrigin:function(){this.origin||(this.origin=this.map.getExtent().getCenterLonLat());return this.origin},setRotation:function(a){this.rotation=a;this.updateGrid(!0)},onMoveEnd:function(){this.updateGrid()},getViewBounds:function(){var a=this.map.getExtent();
-if(this.rotation){var b=this.getOrigin(),b=new OpenLayers.Geometry.Point(b.lon,b.lat),a=a.toGeometry();a.rotate(-this.rotation,b);a=a.getBounds()}return a},updateGrid:function(a){if(a||this.invalidBounds()){var b=this.getViewBounds(),c=this.getOrigin();a=new OpenLayers.Geometry.Point(c.lon,c.lat);var d=b.getWidth(),e=b.getHeight(),f=d/e,g=Math.sqrt(this.dx*this.dy*this.maxFeatures/f),d=Math.min(d*this.ratio,g*f),e=Math.min(e*this.ratio,g),b=b.getCenterLonLat();this.gridBounds=new OpenLayers.Bounds(b.lon-
-d/2,b.lat-e/2,b.lon+d/2,b.lat+e/2);for(var b=Math.floor(e/this.dy),d=Math.floor(d/this.dx),e=c.lon+this.dx*Math.ceil((this.gridBounds.left-c.lon)/this.dx),c=c.lat+this.dy*Math.ceil((this.gridBounds.bottom-c.lat)/this.dy),g=Array(b*d),h,k=0;k<d;++k)for(var f=e+k*this.dx,l=0;l<b;++l)h=c+l*this.dy,h=new OpenLayers.Geometry.Point(f,h),this.rotation&&h.rotate(this.rotation,a),g[k*b+l]=new OpenLayers.Feature.Vector(h);this.destroyFeatures(this.features,{silent:!0});this.addFeatures(g,{silent:!0})}},invalidBounds:function(){return!this.gridBounds||
-!this.gridBounds.containsBounds(this.getViewBounds())},CLASS_NAME:"OpenLayers.Layer.PointGrid"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,interval:0,maxDelta:Number.POSITIVE_INFINITY,delta:0,cumulative:!0,initialize:function(a,b,c){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(a){if(this.map&&this.checkModifiers(a)){for(var b=
-!1,c=!1,d=!1,e=OpenLayers.Event.element(a);null!=e&&!d&&!b;){if(!b)try{var f,b=(f=e.currentStyle?e.currentStyle.overflow:document.defaultView.getComputedStyle(e,null).getPropertyValue("overflow"))&&"auto"==f||"scroll"==f}catch(g){}if(!c&&(c=OpenLayers.Element.hasClass(e,"olScrollable"),!c))for(var d=0,h=this.map.layers.length;d<h;d++){var k=this.map.layers[d];if(e==k.div||e==k.pane){c=!0;break}}d=e==this.map.div;e=e.parentNode}if(!b&&d){if(c)if(b=0,a.wheelDelta?(b=a.wheelDelta,0===b%160&&(b*=0.75),
-b/=120):a.detail&&(b=-(a.detail/Math.abs(a.detail))),this.delta+=b,window.clearTimeout(this._timeoutId),this.interval&&Math.abs(this.delta)<this.maxDelta){var l=OpenLayers.Util.extend({},a);this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(l)},this),this.interval)}else this.wheelZoom(a);OpenLayers.Event.stop(a)}}},wheelZoom:function(a){var b=this.delta;this.delta=0;b&&(a.xy=this.map.events.getMousePosition(a),0>b?this.callback("down",[a,this.cumulative?Math.max(-this.maxDelta,
-b):-1]):this.callback("up",[a,this.cumulative?Math.min(this.maxDelta,b):1]))},activate:function(a){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",b);OpenLayers.Event.observe(window,"mousewheel",b);OpenLayers.Event.observe(document,"mousewheel",b);return!0}return!1},deactivate:function(a){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.stopObserving(window,
-"DOMMouseScroll",b);OpenLayers.Event.stopObserving(window,"mousewheel",b);OpenLayers.Event.stopObserving(document,"mousewheel",b);return!0}return!1},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Symbolizer=OpenLayers.Class({zIndex:0,initialize:function(a){OpenLayers.Util.extend(this,a)},clone:function(){return new (eval(this.CLASS_NAME))(OpenLayers.Util.extend({},this))},CLASS_NAME:"OpenLayers.Symbolizer"});OpenLayers.Symbolizer.Raster=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Raster"});OpenLayers.Rule=OpenLayers.Class({id:null,name:null,title:null,description:null,context:null,filter:null,elseFilter:!1,symbolizer:null,symbolizers:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(a){this.symbolizer={};OpenLayers.Util.extend(this,a);this.symbolizers&&delete this.symbolizer;this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a in this.symbolizer)this.symbolizer[a]=null;this.symbolizer=null;delete this.symbolizers},evaluate:function(a){var b=
-this.getContext(a),c=!0;if(this.minScaleDenominator||this.maxScaleDenominator)var d=a.layer.map.getScale();this.minScaleDenominator&&(c=d>=OpenLayers.Style.createLiteral(this.minScaleDenominator,b));c&&this.maxScaleDenominator&&(c=d<OpenLayers.Style.createLiteral(this.maxScaleDenominator,b));c&&this.filter&&(c="OpenLayers.Filter.FeatureId"==this.filter.CLASS_NAME?this.filter.evaluate(a):this.filter.evaluate(b));return c},getContext:function(a){var b=this.context;b||(b=a.attributes||a.data);"function"==
-typeof this.context&&(b=this.context(a));return b},clone:function(){var a=OpenLayers.Util.extend({},this);if(this.symbolizers){var b=this.symbolizers.length;a.symbolizers=Array(b);for(var c=0;c<b;++c)a.symbolizers[c]=this.symbolizers[c].clone()}else{a.symbolizer={};for(var d in this.symbolizer)b=this.symbolizer[d],c=typeof b,"object"===c?a.symbolizer[d]=OpenLayers.Util.extend({},b):"string"===c&&(a.symbolizer[d]=b)}a.filter=this.filter&&this.filter.clone();a.context=this.context&&OpenLayers.Util.extend({},
-this.context);return new OpenLayers.Rule(a)},CLASS_NAME:"OpenLayers.Rule"});OpenLayers.Format.SLD=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{profile:null,defaultVersion:"1.0.0",stringifyOutput:!0,namedLayersAsArray:!1,CLASS_NAME:"OpenLayers.Format.SLD"});OpenLayers.Symbolizer.Polygon=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Polygon"});OpenLayers.Format.GML.v2=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",initialize:function(a){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[a])},readers:{gml:OpenLayers.Util.applyDefaults({outerBoundaryIs:function(a,b){var c={};this.readChildNodes(a,c);b.outer=c.components[0]},innerBoundaryIs:function(a,b){var c={};this.readChildNodes(a,c);b.inner.push(c.components[0])},Box:function(a,b){var c=
-{};this.readChildNodes(a,c);b.components||(b.components=[]);var d=c.points[0],c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){var b;b=OpenLayers.Util.isArray(a)?"wfs:FeatureCollection":"gml:featureMember";a=this.writeNode(b,a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);
-return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({Point:function(a){var b=this.createElementNSPlus("gml:Point");this.writeNode("coordinates",[a],b);return b},coordinates:function(a){for(var b=a.length,c=Array(b),d,e=0;e<b;++e)d=a[e],c[e]=this.xy?d.x+","+d.y:d.y+","+d.x,void 0!=d.z&&(c[e]+=","+d.z);return this.createElementNSPlus("gml:coordinates",{attributes:{decimal:".",cs:",",ts:" "},value:1==b?c[0]:c.join(" ")})},LineString:function(a){var b=
-this.createElementNSPlus("gml:LineString");this.writeNode("coordinates",a.components,b);return b},Polygon:function(a){var b=this.createElementNSPlus("gml:Polygon");this.writeNode("outerBoundaryIs",a.components[0],b);for(var c=1;c<a.components.length;++c)this.writeNode("innerBoundaryIs",a.components[c],b);return b},outerBoundaryIs:function(a){var b=this.createElementNSPlus("gml:outerBoundaryIs");this.writeNode("LinearRing",a,b);return b},innerBoundaryIs:function(a){var b=this.createElementNSPlus("gml:innerBoundaryIs");
-this.writeNode("LinearRing",a,b);return b},LinearRing:function(a){var b=this.createElementNSPlus("gml:LinearRing");this.writeNode("coordinates",a.components,b);return b},Box:function(a){var b=this.createElementNSPlus("gml:Box");this.writeNode("coordinates",[{x:a.left,y:a.bottom},{x:a.right,y:a.top}],b);this.srsName&&b.setAttribute("srsName",this.srsName);return b}},OpenLayers.Format.GML.Base.prototype.writers.gml),feature:OpenLayers.Format.GML.Base.prototype.writers.feature,wfs:OpenLayers.Format.GML.Base.prototype.writers.wfs},
-CLASS_NAME:"OpenLayers.Format.GML.v2"});OpenLayers.Format.Filter.v1_0_0=OpenLayers.Class(OpenLayers.Format.GML.v2,OpenLayers.Format.Filter.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",initialize:function(a){OpenLayers.Format.GML.v2.prototype.initialize.apply(this,[a])},readers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsNotEqualTo:function(a,
-b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLike:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(a,c);var d=a.getAttribute("wildCard"),e=a.getAttribute("singleChar"),f=a.getAttribute("escape");c.value2regex(d,e,f);b.filters.push(c)}},OpenLayers.Format.Filter.v1.prototype.readers.ogc),gml:OpenLayers.Format.GML.v2.prototype.readers.gml,
-feature:OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsNotEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNotEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLike:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLike",
-{attributes:{wildCard:"*",singleChar:".",escape:"!"}});this.writeNode("PropertyName",a,b);this.writeNode("Literal",a.regex2value(),b);return b},BBOX:function(a){var b=this.createElementNSPlus("ogc:BBOX");a.property&&this.writeNode("PropertyName",a,b);var c=this.writeNode("gml:Box",a.value,b);a.projection&&c.setAttribute("srsName",a.projection);return b}},OpenLayers.Format.Filter.v1.prototype.writers.ogc),gml:OpenLayers.Format.GML.v2.prototype.writers.gml,feature:OpenLayers.Format.GML.v2.prototype.writers.feature},
-writeSpatial:function(a,b){var c=this.createElementNSPlus("ogc:"+b);this.writeNode("PropertyName",a,c);if(a.value instanceof OpenLayers.Filter.Function)this.writeNode("Function",a.value,c);else{var d;d=a.value instanceof OpenLayers.Geometry?this.writeNode("feature:_geometry",a.value).firstChild:this.writeNode("gml:Box",a.value);a.projection&&d.setAttribute("srsName",a.projection);c.appendChild(d)}return c},CLASS_NAME:"OpenLayers.Format.Filter.v1_0_0"});OpenLayers.Format.WFST.v1_0_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,OpenLayers.Format.WFST.v1,{version:"1.0.0",srsNameInQuery:!1,schemaLocations:{wfs:"http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"},initialize:function(a){OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this,[a]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[a])},readNode:function(a,b,c){return OpenLayers.Format.GML.v2.prototype.readNode.apply(this,arguments)},readers:{wfs:OpenLayers.Util.applyDefaults({WFS_TransactionResponse:function(a,
-b){b.insertIds=[];b.success=!1;this.readChildNodes(a,b)},InsertResult:function(a,b){var c={fids:[]};this.readChildNodes(a,c);b.insertIds=b.insertIds.concat(c.fids)},TransactionResult:function(a,b){this.readChildNodes(a,b)},Status:function(a,b){this.readChildNodes(a,b)},SUCCESS:function(a,b){b.success=!0}},OpenLayers.Format.WFST.v1.prototype.readers.wfs),gml:OpenLayers.Format.GML.v2.prototype.readers.gml,feature:OpenLayers.Format.GML.v2.prototype.readers.feature,ogc:OpenLayers.Format.Filter.v1_0_0.prototype.readers.ogc},
-writers:{wfs:OpenLayers.Util.applyDefaults({Query:function(a){a=OpenLayers.Util.extend({featureNS:this.featureNS,featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName,srsNameInQuery:this.srsNameInQuery},a);var b=a.featurePrefix,c=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(b?b+":":"")+a.featureType}});a.srsNameInQuery&&a.srsName&&c.setAttribute("srsName",a.srsName);a.featureNS&&c.setAttribute("xmlns:"+b,a.featureNS);if(a.propertyNames)for(var b=0,d=a.propertyNames.length;b<
-d;b++)this.writeNode("ogc:PropertyName",{property:a.propertyNames[b]},c);a.filter&&(this.setFilterProperty(a.filter),this.writeNode("ogc:Filter",a.filter,c));return c}},OpenLayers.Format.WFST.v1.prototype.writers.wfs),gml:OpenLayers.Format.GML.v2.prototype.writers.gml,feature:OpenLayers.Format.GML.v2.prototype.writers.feature,ogc:OpenLayers.Format.Filter.v1_0_0.prototype.writers.ogc},CLASS_NAME:"OpenLayers.Format.WFST.v1_0_0"});OpenLayers.ElementsIndexer=OpenLayers.Class({maxZIndex:null,order:null,indices:null,compare:null,initialize:function(a){this.compare=a?OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER:OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;this.clear()},insert:function(a){this.exists(a)&&this.remove(a);var b=a.id;this.determineZIndex(a);for(var c=-1,d=this.order.length,e;1<d-c;)e=parseInt((c+d)/2),0<this.compare(this,a,OpenLayers.Util.getElement(this.order[e]))?c=e:d=e;this.order.splice(d,
-0,b);this.indices[b]=this.getZIndex(a);return this.getNextElement(d)},remove:function(a){a=a.id;var b=OpenLayers.Util.indexOf(this.order,a);0<=b&&(this.order.splice(b,1),delete this.indices[a],this.maxZIndex=0<this.order.length?this.indices[this.order[this.order.length-1]]:0)},clear:function(){this.order=[];this.indices={};this.maxZIndex=0},exists:function(a){return null!=this.indices[a.id]},getZIndex:function(a){return a._style.graphicZIndex},determineZIndex:function(a){var b=a._style.graphicZIndex;
-null==b?(b=this.maxZIndex,a._style.graphicZIndex=b):b>this.maxZIndex&&(this.maxZIndex=b)},getNextElement:function(a){a+=1;if(a<this.order.length){var b=OpenLayers.Util.getElement(this.order[a]);void 0==b&&(b=this.getNextElement(a));return b}return null},CLASS_NAME:"OpenLayers.ElementsIndexer"});
-OpenLayers.ElementsIndexer.IndexingMethods={Z_ORDER:function(a,b,c){b=a.getZIndex(b);var d=0;c&&(a=a.getZIndex(c),d=b-a);return d},Z_ORDER_DRAWING_ORDER:function(a,b,c){a=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(a,b,c);c&&0==a&&(a=1);return a},Z_ORDER_Y_ORDER:function(a,b,c){a=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(a,b,c);c&&0===a&&(b=c._boundsBottom-b._boundsBottom,a=0===b?1:b);return a}};
-OpenLayers.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,vectorRoot:null,textRoot:null,xmlns:null,xOffset:0,indexer:null,BACKGROUND_ID_SUFFIX:"_background",LABEL_ID_SUFFIX:"_label",LABEL_OUTLINE_SUFFIX:"_outline",initialize:function(a,b){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot("_root");this.vectorRoot=this.createRoot("_vroot");this.textRoot=this.createRoot("_troot");this.root.appendChild(this.vectorRoot);
-this.root.appendChild(this.textRoot);this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);b&&(b.zIndexing||b.yOrdering)&&(this.indexer=new OpenLayers.ElementsIndexer(b.yOrdering))},destroy:function(){this.clear();this.xmlns=this.root=this.rendererRoot=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments)},clear:function(){var a,b=this.vectorRoot;if(b)for(;a=b.firstChild;)b.removeChild(a);if(b=this.textRoot)for(;a=b.firstChild;)b.removeChild(a);this.indexer&&
-this.indexer.clear()},setExtent:function(a,b){var c=OpenLayers.Renderer.prototype.setExtent.apply(this,arguments),d=this.getResolution();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var e,f=a.getWidth()/this.map.getExtent().getWidth();a=a.scale(1/f);f=this.map.getMaxExtent();f.right>a.left&&f.right<a.right?e=!0:f.left>a.left&&f.left<a.right&&(e=!1);if(e!==this.rightOfDateLine||b)c=!1,this.xOffset=!0===e?f.getWidth()/d:0;this.rightOfDateLine=e}return c},getNodeType:function(a,b){},drawGeometry:function(a,
-b,c){var d=a.CLASS_NAME,e=!0;if("OpenLayers.Geometry.Collection"==d||"OpenLayers.Geometry.MultiPoint"==d||"OpenLayers.Geometry.MultiLineString"==d||"OpenLayers.Geometry.MultiPolygon"==d){for(var d=0,f=a.components.length;d<f;d++)e=this.drawGeometry(a.components[d],b,c)&&e;return e}d=e=!1;"none"!=b.display&&(b.backgroundGraphic?this.redrawBackgroundNode(a.id,a,b,c):d=!0,e=this.redrawNode(a.id,a,b,c));!1==e&&(b=document.getElementById(a.id))&&(b._style.backgroundGraphic&&(d=!0),b.parentNode.removeChild(b));
-d&&(b=document.getElementById(a.id+this.BACKGROUND_ID_SUFFIX))&&b.parentNode.removeChild(b);return e},redrawNode:function(a,b,c,d){c=this.applyDefaultSymbolizer(c);a=this.nodeFactory(a,this.getNodeType(b,c));a._featureId=d;a._boundsBottom=b.getBounds().bottom;a._geometryClass=b.CLASS_NAME;a._style=c;b=this.drawGeometryNode(a,b,c);if(!1===b)return!1;a=b.node;this.indexer?(c=this.indexer.insert(a))?this.vectorRoot.insertBefore(a,c):this.vectorRoot.appendChild(a):a.parentNode!==this.vectorRoot&&this.vectorRoot.appendChild(a);
-this.postDraw(a);return b.complete},redrawBackgroundNode:function(a,b,c,d){c=OpenLayers.Util.extend({},c);c.externalGraphic=c.backgroundGraphic;c.graphicXOffset=c.backgroundXOffset;c.graphicYOffset=c.backgroundYOffset;c.graphicZIndex=c.backgroundGraphicZIndex;c.graphicWidth=c.backgroundWidth||c.graphicWidth;c.graphicHeight=c.backgroundHeight||c.graphicHeight;c.backgroundGraphic=null;c.backgroundXOffset=null;c.backgroundYOffset=null;c.backgroundGraphicZIndex=null;return this.redrawNode(a+this.BACKGROUND_ID_SUFFIX,
-b,c,null)},drawGeometryNode:function(a,b,c){c=c||a._style;var d={isFilled:void 0===c.fill?!0:c.fill,isStroked:void 0===c.stroke?!!c.strokeWidth:c.stroke},e;switch(b.CLASS_NAME){case "OpenLayers.Geometry.Point":!1===c.graphic&&(d.isFilled=!1,d.isStroked=!1);e=this.drawPoint(a,b);break;case "OpenLayers.Geometry.LineString":d.isFilled=!1;e=this.drawLineString(a,b);break;case "OpenLayers.Geometry.LinearRing":e=this.drawLinearRing(a,b);break;case "OpenLayers.Geometry.Polygon":e=this.drawPolygon(a,b);break;
-case "OpenLayers.Geometry.Rectangle":e=this.drawRectangle(a,b)}a._options=d;return!1!=e?{node:this.setStyle(a,c,d,b),complete:e}:!1},postDraw:function(a){},drawPoint:function(a,b){},drawLineString:function(a,b){},drawLinearRing:function(a,b){},drawPolygon:function(a,b){},drawRectangle:function(a,b){},drawCircle:function(a,b){},removeText:function(a){var b=document.getElementById(a+this.LABEL_ID_SUFFIX);b&&this.textRoot.removeChild(b);(a=document.getElementById(a+this.LABEL_OUTLINE_SUFFIX))&&this.textRoot.removeChild(a)},
-getFeatureIdFromEvent:function(a){var b=a.target,c=b&&b.correspondingUseElement;return(c?c:b||a.srcElement)._featureId},eraseGeometry:function(a,b){if("OpenLayers.Geometry.MultiPoint"==a.CLASS_NAME||"OpenLayers.Geometry.MultiLineString"==a.CLASS_NAME||"OpenLayers.Geometry.MultiPolygon"==a.CLASS_NAME||"OpenLayers.Geometry.Collection"==a.CLASS_NAME)for(var c=0,d=a.components.length;c<d;c++)this.eraseGeometry(a.components[c],b);else(c=OpenLayers.Util.getElement(a.id))&&c.parentNode&&(c.geometry&&(c.geometry.destroy(),
-c.geometry=null),c.parentNode.removeChild(c),this.indexer&&this.indexer.remove(c),c._style.backgroundGraphic&&(c=OpenLayers.Util.getElement(a.id+this.BACKGROUND_ID_SUFFIX))&&c.parentNode&&c.parentNode.removeChild(c))},nodeFactory:function(a,b){var c=OpenLayers.Util.getElement(a);c?this.nodeTypeCompare(c,b)||(c.parentNode.removeChild(c),c=this.nodeFactory(a,b)):c=this.createNode(b,a);return c},nodeTypeCompare:function(a,b){},createNode:function(a,b){},moveRoot:function(a){var b=this.root;a.root.parentNode==
-this.rendererRoot&&(b=a.root);b.parentNode.removeChild(b);a.rendererRoot.appendChild(b)},getRenderLayerId:function(){return this.root.parentNode.parentNode.id},isComplexSymbol:function(a){return"circle"!=a&&!!a},CLASS_NAME:"OpenLayers.Renderer.Elements"});OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,getParameters:function(a){a=a||window.location.href;var b=OpenLayers.Util.getParameters(a),c=a.indexOf("#");0<c&&(a="?"+a.substring(c+1,a.length),OpenLayers.Util.extend(b,OpenLayers.Util.getParameters(a)));return b},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var b=0,c=this.map.controls.length;b<c;b++){var d=this.map.controls[b];if(d!=this&&
-"OpenLayers.Control.ArgParser"==d.CLASS_NAME){d.displayProjection!=this.displayProjection&&(this.displayProjection=d.displayProjection);break}}b==this.map.controls.length&&(b=this.getParameters(),b.layers&&(this.layers=b.layers,this.map.events.register("addlayer",this,this.configureLayers),this.configureLayers()),b.lat&&b.lon&&(this.center=new OpenLayers.LonLat(parseFloat(b.lon),parseFloat(b.lat)),b.zoom&&(this.zoom=parseFloat(b.zoom)),this.map.events.register("changebaselayer",this,this.setCenter),
-this.setCenter()))},setCenter:function(){this.map.baseLayer&&(this.map.events.unregister("changebaselayer",this,this.setCenter),this.displayProjection&&this.center.transform(this.displayProjection,this.map.getProjectionObject()),this.map.setCenter(this.center,this.zoom))},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister("addlayer",this,this.configureLayers);for(var a=0,b=this.layers.length;a<b;a++){var c=this.map.layers[a],d=this.layers.charAt(a);
-"B"==d?this.map.setBaseLayer(c):"T"!=d&&"F"!=d||c.setVisibility("T"==d)}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.Permalink=OpenLayers.Class(OpenLayers.Control,{argParserClass:OpenLayers.Control.ArgParser,element:null,anchor:!1,base:"",displayProjection:null,initialize:function(a,b,c){null===a||"object"!=typeof a||OpenLayers.Util.isElement(a)?(OpenLayers.Control.prototype.initialize.apply(this,[c]),this.element=OpenLayers.Util.getElement(a),this.base=b||document.location.href):(this.base=document.location.href,OpenLayers.Control.prototype.initialize.apply(this,[a]),null!=this.element&&(this.element=
-OpenLayers.Util.getElement(this.element)))},destroy:function(){this.element&&this.element.parentNode==this.div&&(this.div.removeChild(this.element),this.element=null);this.map&&this.map.events.unregister("moveend",this,this.updateLink);OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var b=0,c=this.map.controls.length;b<c;b++){var d=this.map.controls[b];if(d.CLASS_NAME==this.argParserClass.CLASS_NAME){d.displayProjection!=
-this.displayProjection&&(this.displayProjection=d.displayProjection);break}}b==this.map.controls.length&&this.map.addControl(new this.argParserClass({displayProjection:this.displayProjection}))},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||this.anchor||(this.element=document.createElement("a"),this.element.innerHTML=OpenLayers.i18n("Permalink"),this.element.href="",this.div.appendChild(this.element));this.map.events.on({moveend:this.updateLink,changelayer:this.updateLink,
-changebaselayer:this.updateLink,scope:this});this.updateLink();return this.div},updateLink:function(){var a=this.anchor?"#":"?",b=this.base,c=null;-1!=b.indexOf("#")&&!1==this.anchor&&(c=b.substring(b.indexOf("#"),b.length));-1!=b.indexOf(a)&&(b=b.substring(0,b.indexOf(a)));b=b.split("#")[0]+a+OpenLayers.Util.getParameterString(this.createParams());c&&(b+=c);this.anchor&&!this.element?window.location.href=b:this.element.href=b},createParams:function(a,b,c){a=a||this.map.getCenter();var d=OpenLayers.Util.getParameters(this.base);
-if(a)for(d.zoom=b||this.map.getZoom(),b=a.lat,a=a.lon,this.displayProjection&&(b=OpenLayers.Projection.transform({x:a,y:b},this.map.getProjectionObject(),this.displayProjection),a=b.x,b=b.y),d.lat=Math.round(1E5*b)/1E5,d.lon=Math.round(1E5*a)/1E5,c=c||this.map.layers,d.layers="",a=0,b=c.length;a<b;a++){var e=c[a];d.layers=e.isBaseLayer?d.layers+(e==this.map.baseLayer?"B":"0"):d.layers+(e.getVisibility()?"T":"F")}return d},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Layer.TMS=OpenLayers.Class(OpenLayers.Layer.Grid,{serviceVersion:"1.0.0",layername:null,type:null,isBaseLayer:!0,tileOrigin:null,serverResolutions:null,zoomOffset:0,initialize:function(a,b,c){var d=[];d.push(a,b,{},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,d)},clone:function(a){null==a&&(a=new OpenLayers.Layer.TMS(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);var b=this.getServerResolution(),
-c=Math.round((a.left-this.tileOrigin.lon)/(b*this.tileSize.w));a=Math.round((a.bottom-this.tileOrigin.lat)/(b*this.tileSize.h));b=this.getServerZoom();c=this.serviceVersion+"/"+this.layername+"/"+b+"/"+c+"/"+a+"."+this.type;a=this.url;OpenLayers.Util.isArray(a)&&(a=this.selectUrl(c,a));return a+c},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.bottom))},CLASS_NAME:"OpenLayers.Layer.TMS"});OpenLayers.Format.WCSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",CLASS_NAME:"OpenLayers.Format.WCSCapabilities"});OpenLayers.Format.WCSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g,splitSpace:/\s+/},defaultPrefix:"wcs",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},CLASS_NAME:"OpenLayers.Format.WCSCapabilities.v1"});OpenLayers.Format.WCSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1,{namespaces:{wcs:"http://www.opengis.net/wcs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows"},errorProperty:"service",readers:{wcs:{WCS_Capabilities:function(a,b){this.readChildNodes(a,b)},Service:function(a,b){b.service={};this.readChildNodes(a,b.service)},name:function(a,b){b.name=this.getChildValue(a)},label:function(a,b){b.label=
-this.getChildValue(a)},keywords:function(a,b){b.keywords=[];this.readChildNodes(a,b.keywords)},keyword:function(a,b){b.push(this.getChildValue(a))},responsibleParty:function(a,b){b.responsibleParty={};this.readChildNodes(a,b.responsibleParty)},individualName:function(a,b){b.individualName=this.getChildValue(a)},organisationName:function(a,b){b.organisationName=this.getChildValue(a)},positionName:function(a,b){b.positionName=this.getChildValue(a)},contactInfo:function(a,b){b.contactInfo={};this.readChildNodes(a,
-b.contactInfo)},phone:function(a,b){b.phone={};this.readChildNodes(a,b.phone)},voice:function(a,b){b.voice=this.getChildValue(a)},facsimile:function(a,b){b.facsimile=this.getChildValue(a)},address:function(a,b){b.address={};this.readChildNodes(a,b.address)},deliveryPoint:function(a,b){b.deliveryPoint=this.getChildValue(a)},city:function(a,b){b.city=this.getChildValue(a)},postalCode:function(a,b){b.postalCode=this.getChildValue(a)},country:function(a,b){b.country=this.getChildValue(a)},electronicMailAddress:function(a,
-b){b.electronicMailAddress=this.getChildValue(a)},fees:function(a,b){b.fees=this.getChildValue(a)},accessConstraints:function(a,b){b.accessConstraints=this.getChildValue(a)},ContentMetadata:function(a,b){b.contentMetadata=[];this.readChildNodes(a,b.contentMetadata)},CoverageOfferingBrief:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},name:function(a,b){b.name=this.getChildValue(a)},label:function(a,b){b.label=this.getChildValue(a)},lonLatEnvelope:function(a,b){var c=this.getElementsByTagNameNS(a,
-"http://www.opengis.net/gml","pos");if(2==c.length){var d={},e={};OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[c[0],d]);OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[c[1],e]);b.lonLatEnvelope={};b.lonLatEnvelope.srsName=a.getAttribute("srsName");b.lonLatEnvelope.min=d.points[0];b.lonLatEnvelope.max=e.points[0]}}}},CLASS_NAME:"OpenLayers.Format.WCSCapabilities.v1_0_0"});OpenLayers.Strategy.Fixed=OpenLayers.Class(OpenLayers.Strategy,{preload:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.apply(this,arguments);if(a)if(this.layer.events.on({refresh:this.load,scope:this}),!0==this.layer.visibility||this.preload)this.load();else this.layer.events.on({visibilitychanged:this.load,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({refresh:this.load,visibilitychanged:this.load,
-scope:this});return a},load:function(a){var b=this.layer;b.events.triggerEvent("loadstart",{filter:b.filter});b.protocol.read(OpenLayers.Util.applyDefaults({callback:this.merge,filter:b.filter,scope:this},a));b.events.un({visibilitychanged:this.load,scope:this})},merge:function(a){var b=this.layer;b.destroyFeatures();var c=a.features;if(c&&0<c.length){var d=b.projection,e=b.map.getProjectionObject();if(!e.equals(d))for(var f,g=0,h=c.length;g<h;++g)(f=c[g].geometry)&&f.transform(d,e);b.addFeatures(c)}b.events.triggerEvent("loadend",
-{response:a})},CLASS_NAME:"OpenLayers.Strategy.Fixed"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"\u2212",zoomOutId:"olZoomOutLink",draw:function(){var a=OpenLayers.Control.prototype.draw.apply(this),b=this.getOrCreateLinks(a),c=b.zoomIn,b=b.zoomOut,d=this.map.events;b.parentNode!==a&&(d=this.events,d.attachToElement(b.parentNode));d.register("buttonclick",this,this.onZoomClick);this.zoomInLink=c;this.zoomOutLink=b;return a},getOrCreateLinks:function(a){var b=document.getElementById(this.zoomInId),
-c=document.getElementById(this.zoomOutId);b||(b=document.createElement("a"),b.href="#zoomIn",b.appendChild(document.createTextNode(this.zoomInText)),b.className="olControlZoomIn",a.appendChild(b));OpenLayers.Element.addClass(b,"olButton");c||(c=document.createElement("a"),c.href="#zoomOut",c.appendChild(document.createTextNode(this.zoomOutText)),c.className="olControlZoomOut",a.appendChild(c));OpenLayers.Element.addClass(c,"olButton");return{zoomIn:b,zoomOut:c}},onZoomClick:function(a){a=a.buttonElement;
-a===this.zoomInLink?this.map.zoomIn():a===this.zoomOutLink&&this.map.zoomOut()},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onZoomClick);delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Layer.PointTrack=OpenLayers.Class(OpenLayers.Layer.Vector,{dataFrom:null,styleFrom:null,addNodes:function(a,b){if(2>a.length)throw Error("At least two point features have to be added to create a line from");for(var c=Array(a.length-1),d,e,f,g=0,h=a.length;g<h;g++){d=a[g];f=d.geometry;if(!f)f=d.lonlat,f=new OpenLayers.Geometry.Point(f.lon,f.lat);else if("OpenLayers.Geometry.Point"!=f.CLASS_NAME)throw new TypeError("Only features with point geometries are supported.");if(0<g){d=null!=this.dataFrom?
-a[g+this.dataFrom].data||a[g+this.dataFrom].attributes:null;var k=null!=this.styleFrom?a[g+this.styleFrom].style:null;e=new OpenLayers.Geometry.LineString([e,f]);c[g-1]=new OpenLayers.Feature.Vector(e,d,k)}e=f}this.addFeatures(c,b)},CLASS_NAME:"OpenLayers.Layer.PointTrack"});OpenLayers.Layer.PointTrack.SOURCE_NODE=-1;OpenLayers.Layer.PointTrack.TARGET_NODE=0;OpenLayers.Layer.PointTrack.dataFrom={SOURCE_NODE:-1,TARGET_NODE:0};OpenLayers.Protocol.WFS=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.WFS.DEFAULTS);var b=OpenLayers.Protocol.WFS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFS version: "+a.version;return new b(a)};
-OpenLayers.Protocol.WFS.fromWMSLayer=function(a,b){var c,d;c=a.params.LAYERS;c=(OpenLayers.Util.isArray(c)?c[0]:c).split(":");1<c.length&&(d=c[0]);c=c.pop();d={url:a.url,featureType:c,featurePrefix:d,srsName:a.projection&&a.projection.getCode()||a.map&&a.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(b,d))};OpenLayers.Protocol.WFS.DEFAULTS={version:"1.0.0"};OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,markers:null,drawn:!1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[]},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},setOpacity:function(a){if(a!=this.opacity){this.opacity=a;a=0;for(var b=this.markers.length;a<b;a++)this.markers[a].setOpacity(this.opacity)}},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,
-arguments);if(b||!this.drawn){for(var d=0,e=this.markers.length;d<e;d++)this.drawMarker(this.markers[d]);this.drawn=!0}},addMarker:function(a){this.markers.push(a);1>this.opacity&&a.setOpacity(this.opacity);this.map&&this.map.getExtent()&&(a.map=this.map,this.drawMarker(a))},removeMarker:function(a){this.markers&&this.markers.length&&(OpenLayers.Util.removeItem(this.markers,a),a.erase())},clearMarkers:function(){if(null!=this.markers)for(;0<this.markers.length;)this.removeMarker(this.markers[0])},
-drawMarker:function(a){var b=this.map.getLayerPxFromLonLat(a.lonlat);null==b?a.display(!1):a.isDrawn()?a.icon&&a.icon.moveTo(b):(a=a.draw(b),this.div.appendChild(a))},getDataExtent:function(){var a=null;if(this.markers&&0<this.markers.length)for(var a=new OpenLayers.Bounds,b=0,c=this.markers.length;b<c;b++)a.extend(this.markers[b].lonlat);return a},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.Pan=OpenLayers.Class(OpenLayers.Control.Button,{slideFactor:50,slideRatio:null,direction:null,initialize:function(a,b){this.direction=a;this.CLASS_NAME+=this.direction;OpenLayers.Control.prototype.initialize.apply(this,[b])},trigger:function(){if(this.map){var a=OpenLayers.Function.bind(function(a){return this.slideRatio?this.map.getSize()[a]*this.slideRatio:this.slideFactor},this);switch(this.direction){case OpenLayers.Control.Pan.NORTH:this.map.pan(0,-a("h"));break;case OpenLayers.Control.Pan.SOUTH:this.map.pan(0,
-a("h"));break;case OpenLayers.Control.Pan.WEST:this.map.pan(-a("w"),0);break;case OpenLayers.Control.Pan.EAST:this.map.pan(a("w"),0)}}},CLASS_NAME:"OpenLayers.Control.Pan"});OpenLayers.Control.Pan.NORTH="North";OpenLayers.Control.Pan.SOUTH="South";OpenLayers.Control.Pan.EAST="East";OpenLayers.Control.Pan.WEST="West";OpenLayers.Format.CSWGetDomain=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.CSWGetDomain.DEFAULTS);var b=OpenLayers.Format.CSWGetDomain["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSWGetDomain version: "+a.version;return new b(a)};OpenLayers.Format.CSWGetDomain.DEFAULTS={version:"2.0.2"};OpenLayers.Format.CSWGetDomain.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",csw:"http://www.opengis.net/cat/csw/2.0.2"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",PropertyName:null,ParameterName:null,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==
-a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{csw:{GetDomainResponse:function(a,b){this.readChildNodes(a,b)},DomainValues:function(a,b){OpenLayers.Util.isArray(b.DomainValues)||(b.DomainValues=[]);for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;this.readChildNodes(a,d);b.DomainValues.push(d)},PropertyName:function(a,b){b.PropertyName=this.getChildValue(a)},ParameterName:function(a,b){b.ParameterName=this.getChildValue(a)},ListOfValues:function(a,
-b){OpenLayers.Util.isArray(b.ListOfValues)||(b.ListOfValues=[]);this.readChildNodes(a,b.ListOfValues)},Value:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.push({Value:d})},ConceptualScheme:function(a,b){b.ConceptualScheme={};this.readChildNodes(a,b.ConceptualScheme)},Name:function(a,b){b.Name=this.getChildValue(a)},Document:function(a,b){b.Document=this.getChildValue(a)},Authority:function(a,b){b.Authority=this.getChildValue(a)},
-RangeOfValues:function(a,b){b.RangeOfValues={};this.readChildNodes(a,b.RangeOfValues)},MinValue:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.MinValue=d},MaxValue:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.MaxValue=d}}},write:function(a){a=this.writeNode("csw:GetDomain",a);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{csw:{GetDomain:function(a){var b=
-this.createElementNSPlus("csw:GetDomain",{attributes:{service:"CSW",version:this.version}});a.PropertyName||this.PropertyName?this.writeNode("csw:PropertyName",a.PropertyName||this.PropertyName,b):(a.ParameterName||this.ParameterName)&&this.writeNode("csw:ParameterName",a.ParameterName||this.ParameterName,b);this.readChildNodes(b,a);return b},PropertyName:function(a){return this.createElementNSPlus("csw:PropertyName",{value:a})},ParameterName:function(a){return this.createElementNSPlus("csw:ParameterName",
-{value:a})}}},CLASS_NAME:"OpenLayers.Format.CSWGetDomain.v2_0_2"});OpenLayers.Format.ArcXML.Features=OpenLayers.Class(OpenLayers.Format.XML,{read:function(a){return(new OpenLayers.Format.ArcXML).read(a).features.feature}});OpenLayers.Control.Snapping=OpenLayers.Class(OpenLayers.Control,{DEFAULTS:{tolerance:10,node:!0,edge:!0,vertex:!0},greedy:!0,precedence:["node","vertex","edge"],resolution:null,geoToleranceCache:null,layer:null,feature:null,point:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.options=a||{};this.options.layer&&this.setLayer(this.options.layer);a=OpenLayers.Util.extend({},this.options.defaults);this.defaults=OpenLayers.Util.applyDefaults(a,this.DEFAULTS);this.setTargets(this.options.targets);
-0===this.targets.length&&this.layer&&this.addTargetLayer(this.layer);this.geoToleranceCache={}},setLayer:function(a){this.active?(this.deactivate(),this.layer=a,this.activate()):this.layer=a},setTargets:function(a){this.targets=[];if(a&&a.length)for(var b,c=0,d=a.length;c<d;++c)b=a[c],b instanceof OpenLayers.Layer.Vector?this.addTargetLayer(b):this.addTarget(b)},addTargetLayer:function(a){this.addTarget({layer:a})},addTarget:function(a){a=OpenLayers.Util.applyDefaults(a,this.defaults);a.nodeTolerance=
-a.nodeTolerance||a.tolerance;a.vertexTolerance=a.vertexTolerance||a.tolerance;a.edgeTolerance=a.edgeTolerance||a.tolerance;this.targets.push(a)},removeTargetLayer:function(a){for(var b,c=this.targets.length-1;0<=c;--c)b=this.targets[c],b.layer===a&&this.removeTarget(b)},removeTarget:function(a){return OpenLayers.Util.removeItem(this.targets,a)},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a&&this.layer&&this.layer.events)this.layer.events.on({sketchstarted:this.onSketchModified,
-sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.call(this);a&&this.layer&&this.layer.events&&this.layer.events.un({sketchstarted:this.onSketchModified,sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});this.point=this.feature=null;return a},onSketchModified:function(a){this.feature=a.feature;this.considerSnapping(a.vertex,a.vertex)},onVertexModified:function(a){this.feature=
-a.feature;var b=this.layer.map.getLonLatFromViewPortPx(a.pixel);this.considerSnapping(a.vertex,new OpenLayers.Geometry.Point(b.lon,b.lat))},considerSnapping:function(a,b){for(var c={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY,x:null,y:null},d=!1,e,f,g=0,h=this.targets.length;g<h;++g)if(f=this.targets[g],e=this.testTarget(f,b))if(this.greedy){c=e;c.target=f;d=!0;break}else if(e.rank<c.rank||e.rank===c.rank&&e.dist<c.dist)c=e,c.target=f,d=!0;d&&(!1!==this.events.triggerEvent("beforesnap",
-{point:a,x:c.x,y:c.y,distance:c.dist,layer:c.target.layer,snapType:this.precedence[c.rank]})?(a.x=c.x,a.y=c.y,this.point=a,this.events.triggerEvent("snap",{point:a,snapType:this.precedence[c.rank],layer:c.target.layer,distance:c.dist})):d=!1);this.point&&!d&&(a.x=b.x,a.y=b.y,this.point=null,this.events.triggerEvent("unsnap",{point:a}))},testTarget:function(a,b){var c=this.layer.map.getResolution();if("minResolution"in a&&c<a.minResolution||"maxResolution"in a&&c>=a.maxResolution)return null;for(var c=
-{node:this.getGeoTolerance(a.nodeTolerance,c),vertex:this.getGeoTolerance(a.vertexTolerance,c),edge:this.getGeoTolerance(a.edgeTolerance,c)},d=Math.max(c.node,c.vertex,c.edge),e={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY},f=!1,g=a.layer.features,h,k,l,m,n,p,q=this.precedence.length,r=new OpenLayers.LonLat(b.x,b.y),s=0,t=g.length;s<t;++s)if(h=g[s],h!==this.feature&&(!h._sketch&&h.state!==OpenLayers.State.DELETE&&(!a.filter||a.filter.evaluate(h)))&&h.atPoint(r,d,d))for(var u=0,v=Math.min(e.rank+
-1,q);u<v;++u)if(k=this.precedence[u],a[k])if("edge"===k){if(l=h.geometry.distanceTo(b,{details:!0}),n=l.distance,n<=c[k]&&n<e.dist){e={rank:u,dist:n,x:l.x0,y:l.y0};f=!0;break}}else{l=h.geometry.getVertices("node"===k);p=!1;for(var w=0,x=l.length;w<x;++w)m=l[w],n=m.distanceTo(b),n<=c[k]&&(u<e.rank||u===e.rank&&n<e.dist)&&(e={rank:u,dist:n,x:m.x,y:m.y},p=f=!0);if(p)break}return f?e:null},getGeoTolerance:function(a,b){b!==this.resolution&&(this.resolution=b,this.geoToleranceCache={});var c=this.geoToleranceCache[a];
-void 0===c&&(c=a*b,this.geoToleranceCache[a]=c);return c},destroy:function(){this.active&&this.deactivate();delete this.layer;delete this.targets;OpenLayers.Control.prototype.destroy.call(this)},CLASS_NAME:"OpenLayers.Control.Snapping"});OpenLayers.Format.OWSCommon.v1_1_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows/1.1",xlink:"http://www.w3.org/1999/xlink"},readers:{ows:OpenLayers.Util.applyDefaults({ExceptionReport:function(a,b){b.exceptionReport={version:a.getAttribute("version"),language:a.getAttribute("xml:lang"),exceptions:[]};this.readChildNodes(a,b.exceptionReport)},AllowedValues:function(a,b){b.allowedValues={};this.readChildNodes(a,b.allowedValues)},AnyValue:function(a,b){b.anyValue=
-!0},DataType:function(a,b){b.dataType=this.getChildValue(a)},Range:function(a,b){b.range={};this.readChildNodes(a,b.range)},MinimumValue:function(a,b){b.minValue=this.getChildValue(a)},MaximumValue:function(a,b){b.maxValue=this.getChildValue(a)},Identifier:function(a,b){b.identifier=this.getChildValue(a)},SupportedCRS:function(a,b){b.supportedCRS=this.getChildValue(a)}},OpenLayers.Format.OWSCommon.v1.prototype.readers.ows)},writers:{ows:OpenLayers.Util.applyDefaults({Range:function(a){var b=this.createElementNSPlus("ows:Range",
-{attributes:{"ows:rangeClosure":a.closure}});this.writeNode("ows:MinimumValue",a.minValue,b);this.writeNode("ows:MaximumValue",a.maxValue,b);return b},MinimumValue:function(a){return this.createElementNSPlus("ows:MinimumValue",{value:a})},MaximumValue:function(a){return this.createElementNSPlus("ows:MaximumValue",{value:a})},Value:function(a){return this.createElementNSPlus("ows:Value",{value:a})}},OpenLayers.Format.OWSCommon.v1.prototype.writers.ows)},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_1_0"});OpenLayers.Format.WCSGetCoverage=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",wcs:"http://www.opengis.net/wcs/1.1",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.1.2",schemaLocation:"http://www.opengis.net/wcs/1.1 http://schemas.opengis.net/wcs/1.1/wcsGetCoverage.xsd",write:function(a){a=this.writeNode("wcs:GetCoverage",
-a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{wcs:{GetCoverage:function(a){var b=this.createElementNSPlus("wcs:GetCoverage",{attributes:{version:a.version||this.VERSION,service:"WCS"}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("wcs:DomainSubset",a.domainSubset,b);this.writeNode("wcs:Output",a.output,b);return b},DomainSubset:function(a){var b=this.createElementNSPlus("wcs:DomainSubset",
-{});this.writeNode("ows:BoundingBox",a.boundingBox,b);a.temporalSubset&&this.writeNode("wcs:TemporalSubset",a.temporalSubset,b);return b},TemporalSubset:function(a){for(var b=this.createElementNSPlus("wcs:TemporalSubset",{}),c=0,d=a.timePeriods.length;c<d;++c)this.writeNode("wcs:TimePeriod",a.timePeriods[c],b);return b},TimePeriod:function(a){var b=this.createElementNSPlus("wcs:TimePeriod",{});this.writeNode("wcs:BeginPosition",a.begin,b);this.writeNode("wcs:EndPosition",a.end,b);a.resolution&&this.writeNode("wcs:TimeResolution",
-a.resolution,b);return b},BeginPosition:function(a){return this.createElementNSPlus("wcs:BeginPosition",{value:a})},EndPosition:function(a){return this.createElementNSPlus("wcs:EndPosition",{value:a})},TimeResolution:function(a){return this.createElementNSPlus("wcs:TimeResolution",{value:a})},Output:function(a){var b=this.createElementNSPlus("wcs:Output",{attributes:{format:a.format,store:a.store}});a.gridCRS&&this.writeNode("wcs:GridCRS",a.gridCRS,b);return b},GridCRS:function(a){var b=this.createElementNSPlus("wcs:GridCRS",
-{});this.writeNode("wcs:GridBaseCRS",a.baseCRS,b);a.type&&this.writeNode("wcs:GridType",a.type,b);a.origin&&this.writeNode("wcs:GridOrigin",a.origin,b);this.writeNode("wcs:GridOffsets",a.offsets,b);a.CS&&this.writeNode("wcs:GridCS",a.CS,b);return b},GridBaseCRS:function(a){return this.createElementNSPlus("wcs:GridBaseCRS",{value:a})},GridOrigin:function(a){return this.createElementNSPlus("wcs:GridOrigin",{value:a})},GridType:function(a){return this.createElementNSPlus("wcs:GridType",{value:a})},GridOffsets:function(a){return this.createElementNSPlus("wcs:GridOffsets",
-{value:a})},GridCS:function(a){return this.createElementNSPlus("wcs:GridCS",{value:a})}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows},CLASS_NAME:"OpenLayers.Format.WCSGetCoverage"});OpenLayers.Format.KML=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{kml:"http://www.opengis.net/kml/2.2",gx:"http://www.google.com/kml/ext/2.2"},kmlns:"http://earth.google.com/kml/2.0",placemarksDesc:"No description available",foldersName:"OpenLayers export",foldersDesc:"Exported on "+new Date,extractAttributes:!0,kvpAttributes:!1,extractStyles:!1,extractTracks:!1,trackAttributes:null,internalns:null,features:null,styles:null,styleBaseUrl:"",fetched:null,maxDepth:0,initialize:function(a){this.regExes=
-{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,kmlColor:/(\w{2})(\w{2})(\w{2})(\w{2})/,kmlIconPalette:/root:\/\/icons\/palette-(\d+)(\.\w+)/,straightBracket:/\$\[(.*?)\]/g};this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){this.features=[];this.styles={};this.fetched={};return this.parseData(a,{depth:0,styleBaseUrl:this.styleBaseUrl})},parseData:function(a,b){"string"==typeof a&&
-(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var c=["Link","NetworkLink","Style","StyleMap","Placemark"],d=0,e=c.length;d<e;++d){var f=c[d],g=this.getElementsByTagNameNS(a,"*",f);if(0!=g.length)switch(f.toLowerCase()){case "link":case "networklink":this.parseLinks(g,b);break;case "style":this.extractStyles&&this.parseStyles(g,b);break;case "stylemap":this.extractStyles&&this.parseStyleMaps(g,b);break;case "placemark":this.parseFeatures(g,b)}}return this.features},parseLinks:function(a,
-b){if(b.depth>=this.maxDepth)return!1;var c=OpenLayers.Util.extend({},b);c.depth++;for(var d=0,e=a.length;d<e;d++){var f=this.parseProperty(a[d],"*","href");f&&!this.fetched[f]&&(this.fetched[f]=!0,(f=this.fetchLink(f))&&this.parseData(f,c))}},fetchLink:function(a){if(a=OpenLayers.Request.GET({url:a,async:!1}))return a.responseText},parseStyles:function(a,b){for(var c=0,d=a.length;c<d;c++){var e=this.parseStyle(a[c]);e&&(this.styles[(b.styleBaseUrl||"")+"#"+e.id]=e)}},parseKmlColor:function(a){var b=
-null;a&&(a=a.match(this.regExes.kmlColor))&&(b={color:"#"+a[4]+a[3]+a[2],opacity:parseInt(a[1],16)/255});return b},parseStyle:function(a){for(var b={},c=["LineStyle","PolyStyle","IconStyle","BalloonStyle","LabelStyle"],d,e,f=0,g=c.length;f<g;++f)if(d=c[f],e=this.getElementsByTagNameNS(a,"*",d)[0])switch(d.toLowerCase()){case "linestyle":d=this.parseProperty(e,"*","color");if(d=this.parseKmlColor(d))b.strokeColor=d.color,b.strokeOpacity=d.opacity;(d=this.parseProperty(e,"*","width"))&&(b.strokeWidth=
-d);break;case "polystyle":d=this.parseProperty(e,"*","color");if(d=this.parseKmlColor(d))b.fillOpacity=d.opacity,b.fillColor=d.color;"0"==this.parseProperty(e,"*","fill")&&(b.fillColor="none");"0"==this.parseProperty(e,"*","outline")&&(b.strokeWidth="0");break;case "iconstyle":var h=parseFloat(this.parseProperty(e,"*","scale")||1);d=32*h;var k=32*h,l=this.getElementsByTagNameNS(e,"*","Icon")[0];if(l){var m=this.parseProperty(l,"*","href");if(m){var n=this.parseProperty(l,"*","w"),p=this.parseProperty(l,
-"*","h");!OpenLayers.String.startsWith(m,"http://maps.google.com/mapfiles/kml")||(n||p)||(p=n=64,h/=2);n=n||p;p=p||n;n&&(d=parseInt(n)*h);p&&(k=parseInt(p)*h);if(p=m.match(this.regExes.kmlIconPalette))n=p[1],p=p[2],m=this.parseProperty(l,"*","x"),l=this.parseProperty(l,"*","y"),m="http://maps.google.com/mapfiles/kml/pal"+n+"/icon"+(8*(l?7-l/32:7)+(m?m/32:0))+p;b.graphicOpacity=1;b.externalGraphic=m}}if(e=this.getElementsByTagNameNS(e,"*","hotSpot")[0])m=parseFloat(e.getAttribute("x")),l=parseFloat(e.getAttribute("y")),
-n=e.getAttribute("xunits"),"pixels"==n?b.graphicXOffset=-m*h:"insetPixels"==n?b.graphicXOffset=-d+m*h:"fraction"==n&&(b.graphicXOffset=-d*m),e=e.getAttribute("yunits"),"pixels"==e?b.graphicYOffset=-k+l*h+1:"insetPixels"==e?b.graphicYOffset=-(l*h)+1:"fraction"==e&&(b.graphicYOffset=-k*(1-l)+1);b.graphicWidth=d;b.graphicHeight=k;break;case "balloonstyle":(e=OpenLayers.Util.getXmlNodeValue(e))&&(b.balloonStyle=e.replace(this.regExes.straightBracket,"${$1}"));break;case "labelstyle":if(d=this.parseProperty(e,
-"*","color"),d=this.parseKmlColor(d))b.fontColor=d.color,b.fontOpacity=d.opacity}!b.strokeColor&&b.fillColor&&(b.strokeColor=b.fillColor);(a=a.getAttribute("id"))&&b&&(b.id=a);return b},parseStyleMaps:function(a,b){for(var c=0,d=a.length;c<d;c++)for(var e=a[c],f=this.getElementsByTagNameNS(e,"*","Pair"),e=e.getAttribute("id"),g=0,h=f.length;g<h;g++){var k=f[g],l=this.parseProperty(k,"*","key");(k=this.parseProperty(k,"*","styleUrl"))&&"normal"==l&&(this.styles[(b.styleBaseUrl||"")+"#"+e]=this.styles[(b.styleBaseUrl||
-"")+k])}},parseFeatures:function(a,b){for(var c=[],d=0,e=a.length;d<e;d++){var f=a[d],g=this.parseFeature.apply(this,[f]);if(g){this.extractStyles&&(g.attributes&&g.attributes.styleUrl)&&(g.style=this.getStyle(g.attributes.styleUrl,b));if(this.extractStyles){var h=this.getElementsByTagNameNS(f,"*","Style")[0];h&&(h=this.parseStyle(h))&&(g.style=OpenLayers.Util.extend(g.style,h))}this.extractTracks?(f=this.getElementsByTagNameNS(f,this.namespaces.gx,"Track"))&&0<f.length&&(g={features:[],feature:g},
-this.readNode(f[0],g),0<g.features.length&&c.push.apply(c,g.features)):c.push(g)}else throw"Bad Placemark: "+d;}this.features=this.features.concat(c)},readers:{kml:{when:function(a,b){b.whens.push(OpenLayers.Date.parse(this.getChildValue(a)))},_trackPointAttribute:function(a,b){var c=a.nodeName.split(":").pop();b.attributes[c].push(this.getChildValue(a))}},gx:{Track:function(a,b){var c={whens:[],points:[],angles:[]};if(this.trackAttributes){var d;c.attributes={};for(var e=0,f=this.trackAttributes.length;e<
-f;++e)d=this.trackAttributes[e],c.attributes[d]=[],d in this.readers.kml||(this.readers.kml[d]=this.readers.kml._trackPointAttribute)}this.readChildNodes(a,c);if(c.whens.length!==c.points.length)throw Error("gx:Track with unequal number of when ("+c.whens.length+") and gx:coord ("+c.points.length+") elements.");var g=0<c.angles.length;if(g&&c.whens.length!==c.angles.length)throw Error("gx:Track with unequal number of when ("+c.whens.length+") and gx:angles ("+c.angles.length+") elements.");for(var h,
-e=0,f=c.whens.length;e<f;++e){h=b.feature.clone();h.fid=b.feature.fid||b.feature.id;d=c.points[e];h.geometry=d;"z"in d&&(h.attributes.altitude=d.z);this.internalProjection&&this.externalProjection&&h.geometry.transform(this.externalProjection,this.internalProjection);if(this.trackAttributes)for(var k=0,l=this.trackAttributes.length;k<l;++k)d=this.trackAttributes[k],h.attributes[d]=c.attributes[d][e];h.attributes.when=c.whens[e];h.attributes.trackId=b.feature.id;g&&(d=c.angles[e],h.attributes.heading=
-parseFloat(d[0]),h.attributes.tilt=parseFloat(d[1]),h.attributes.roll=parseFloat(d[2]));b.features.push(h)}},coord:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(/\s+/),d=new OpenLayers.Geometry.Point(c[0],c[1]);2<c.length&&(d.z=parseFloat(c[2]));b.points.push(d)},angles:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(/\s+/);b.angles.push(c)}}},parseFeature:function(a){for(var b=["MultiGeometry","Polygon","LineString","Point"],
-c,d,e,f=0,g=b.length;f<g;++f)if(c=b[f],this.internalns=a.namespaceURI?a.namespaceURI:this.kmlns,d=this.getElementsByTagNameNS(a,this.internalns,c),0<d.length){if(b=this.parseGeometry[c.toLowerCase()])e=b.apply(this,[d[0]]),this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection);else throw new TypeError("Unsupported geometry type: "+c);break}var h;this.extractAttributes&&(h=this.parseAttributes(a));c=new OpenLayers.Feature.Vector(e,h);a=a.getAttribute("id")||
-a.getAttribute("name");null!=a&&(c.fid=a);return c},getStyle:function(a,b){var c=OpenLayers.Util.removeTail(a),d=OpenLayers.Util.extend({},b);d.depth++;d.styleBaseUrl=c;!this.styles[a]&&!OpenLayers.String.startsWith(a,"#")&&d.depth<=this.maxDepth&&!this.fetched[c]&&(c=this.fetchLink(c))&&this.parseData(c,d);return OpenLayers.Util.extend({},this.styles[a])},parseGeometry:{point:function(a){var b=this.getElementsByTagNameNS(a,this.internalns,"coordinates");a=[];if(0<b.length){var c=b[0].firstChild.nodeValue,
-c=c.replace(this.regExes.removeSpace,"");a=c.split(",")}b=null;if(1<a.length)2==a.length&&(a[2]=null),b=new OpenLayers.Geometry.Point(a[0],a[1],a[2]);else throw"Bad coordinate string: "+c;return b},linestring:function(a,b){var c=this.getElementsByTagNameNS(a,this.internalns,"coordinates"),d=null;if(0<c.length){for(var c=this.getChildValue(c[0]),c=c.replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),d=c.split(this.regExes.splitSpace),e=d.length,f=Array(e),g,h,k=0;k<e;++k)if(g=
-d[k].split(","),h=g.length,1<h)2==g.length&&(g[2]=null),f[k]=new OpenLayers.Geometry.Point(g[0],g[1],g[2]);else throw"Bad LineString point coordinates: "+d[k];if(e)d=b?new OpenLayers.Geometry.LinearRing(f):new OpenLayers.Geometry.LineString(f);else throw"Bad LineString coordinates: "+c;}return d},polygon:function(a){a=this.getElementsByTagNameNS(a,this.internalns,"LinearRing");var b=a.length,c=Array(b);if(0<b)for(var d=0,e=a.length;d<e;++d)if(b=this.parseGeometry.linestring.apply(this,[a[d],!0]))c[d]=
-b;else throw"Bad LinearRing geometry: "+d;return new OpenLayers.Geometry.Polygon(c)},multigeometry:function(a){for(var b,c=[],d=a.childNodes,e=0,f=d.length;e<f;++e)a=d[e],1==a.nodeType&&(b=a.prefix?a.nodeName.split(":")[1]:a.nodeName,(b=this.parseGeometry[b.toLowerCase()])&&c.push(b.apply(this,[a])));return new OpenLayers.Geometry.Collection(c)}},parseAttributes:function(a){var b={},c=a.getElementsByTagName("ExtendedData");c.length&&(b=this.parseExtendedData(c[0]));var d,e,f;a=a.childNodes;for(var c=
-0,g=a.length;c<g;++c)if(d=a[c],1==d.nodeType&&(e=d.childNodes,1<=e.length&&3>=e.length)){switch(e.length){case 1:f=e[0];break;case 2:f=e[0];e=e[1];f=3==f.nodeType||4==f.nodeType?f:e;break;default:f=e[1]}if(3==f.nodeType||4==f.nodeType)if(d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,f=OpenLayers.Util.getXmlNodeValue(f))f=f.replace(this.regExes.trimSpace,""),b[d]=f}return b},parseExtendedData:function(a){var b={},c,d,e,f,g=a.getElementsByTagName("Data");c=0;for(d=g.length;c<d;c++){e=g[c];f=e.getAttribute("name");
-var h={},k=e.getElementsByTagName("value");k.length&&(h.value=this.getChildValue(k[0]));this.kvpAttributes?b[f]=h.value:(e=e.getElementsByTagName("displayName"),e.length&&(h.displayName=this.getChildValue(e[0])),b[f]=h)}a=a.getElementsByTagName("SimpleData");c=0;for(d=a.length;c<d;c++)h={},e=a[c],f=e.getAttribute("name"),h.value=this.getChildValue(e),this.kvpAttributes?b[f]=h.value:(h.displayName=f,b[f]=h);return b},parseProperty:function(a,b,c){var d;a=this.getElementsByTagNameNS(a,b,c);try{d=OpenLayers.Util.getXmlNodeValue(a[0])}catch(e){d=
-null}return d},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=this.createElementNS(this.kmlns,"kml"),c=this.createFolderXML(),d=0,e=a.length;d<e;++d)c.appendChild(this.createPlacemarkXML(a[d]));b.appendChild(c);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFolderXML:function(){var a=this.createElementNS(this.kmlns,"Folder");if(this.foldersName){var b=this.createElementNS(this.kmlns,"name"),c=this.createTextNode(this.foldersName);b.appendChild(c);a.appendChild(b)}this.foldersDesc&&
-(b=this.createElementNS(this.kmlns,"description"),c=this.createTextNode(this.foldersDesc),b.appendChild(c),a.appendChild(b));return a},createPlacemarkXML:function(a){var b=this.createElementNS(this.kmlns,"name"),c=a.style&&a.style.label?a.style.label:a.id;b.appendChild(this.createTextNode(a.attributes.name||c));var d=this.createElementNS(this.kmlns,"description");d.appendChild(this.createTextNode(a.attributes.description||this.placemarksDesc));c=this.createElementNS(this.kmlns,"Placemark");null!=
-a.fid&&c.setAttribute("id",a.fid);c.appendChild(b);c.appendChild(d);b=this.buildGeometryNode(a.geometry);c.appendChild(b);a.attributes&&(a=this.buildExtendedData(a.attributes))&&c.appendChild(a);return c},buildGeometryNode:function(a){var b=a.CLASS_NAME,b=b.substring(b.lastIndexOf(".")+1),b=this.buildGeometry[b.toLowerCase()],c=null;b&&(c=b.apply(this,[a]));return c},buildGeometry:{point:function(a){var b=this.createElementNS(this.kmlns,"Point");b.appendChild(this.buildCoordinatesNode(a));return b},
-multipoint:function(a){return this.buildGeometry.collection.apply(this,[a])},linestring:function(a){var b=this.createElementNS(this.kmlns,"LineString");b.appendChild(this.buildCoordinatesNode(a));return b},multilinestring:function(a){return this.buildGeometry.collection.apply(this,[a])},linearring:function(a){var b=this.createElementNS(this.kmlns,"LinearRing");b.appendChild(this.buildCoordinatesNode(a));return b},polygon:function(a){var b=this.createElementNS(this.kmlns,"Polygon");a=a.components;
-for(var c,d,e=0,f=a.length;e<f;++e)c=0==e?"outerBoundaryIs":"innerBoundaryIs",c=this.createElementNS(this.kmlns,c),d=this.buildGeometry.linearring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},multipolygon:function(a){return this.buildGeometry.collection.apply(this,[a])},collection:function(a){for(var b=this.createElementNS(this.kmlns,"MultiGeometry"),c,d=0,e=a.components.length;d<e;++d)(c=this.buildGeometryNode.apply(this,[a.components[d]]))&&b.appendChild(c);return b}},buildCoordinatesNode:function(a){var b=
-this.createElementNS(this.kmlns,"coordinates"),c;if(c=a.components){for(var d=c.length,e=Array(d),f=0;f<d;++f)a=c[f],e[f]=this.buildCoordinates(a);c=e.join(" ")}else c=this.buildCoordinates(a);c=this.createTextNode(c);b.appendChild(c);return b},buildCoordinates:function(a){this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));return a.x+","+a.y},buildExtendedData:function(a){var b=this.createElementNS(this.kmlns,"ExtendedData"),
-c;for(c in a)if(a[c]&&"name"!=c&&"description"!=c&&"styleUrl"!=c){var d=this.createElementNS(this.kmlns,"Data");d.setAttribute("name",c);var e=this.createElementNS(this.kmlns,"value");if("object"==typeof a[c]){if(a[c].value&&e.appendChild(this.createTextNode(a[c].value)),a[c].displayName){var f=this.createElementNS(this.kmlns,"displayName");f.appendChild(this.getXMLDoc().createCDATASection(a[c].displayName));d.appendChild(f)}}else e.appendChild(this.createTextNode(a[c]));d.appendChild(e);b.appendChild(d)}return this.isSimpleContent(b)?
-null:b},CLASS_NAME:"OpenLayers.Format.KML"});OpenLayers.Format.WMSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.1",profile:null,CLASS_NAME:"OpenLayers.Format.WMSCapabilities"});OpenLayers.Format.WMSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wms:"http://www.opengis.net/wms",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"wms",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=a;a&&9==a.nodeType&&(a=a.documentElement);var c={};this.readNode(a,c);void 0===c.service&&(a=new OpenLayers.Format.OGCExceptionReport,c.error=a.read(b));return c},readers:{wms:{Service:function(a,
-b){b.service={};this.readChildNodes(a,b.service)},Name:function(a,b){b.name=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},BoundingBox:function(a,b){var c={};c.bbox=[parseFloat(a.getAttribute("minx")),parseFloat(a.getAttribute("miny")),parseFloat(a.getAttribute("maxx")),parseFloat(a.getAttribute("maxy"))];var d={x:parseFloat(a.getAttribute("resx")),y:parseFloat(a.getAttribute("resy"))};isNaN(d.x)&&isNaN(d.y)||(c.res=
-d);return c},OnlineResource:function(a,b){b.href=this.getAttributeNS(a,this.namespaces.xlink,"href")},ContactInformation:function(a,b){b.contactInformation={};this.readChildNodes(a,b.contactInformation)},ContactPersonPrimary:function(a,b){b.personPrimary={};this.readChildNodes(a,b.personPrimary)},ContactPerson:function(a,b){b.person=this.getChildValue(a)},ContactOrganization:function(a,b){b.organization=this.getChildValue(a)},ContactPosition:function(a,b){b.position=this.getChildValue(a)},ContactAddress:function(a,
-b){b.contactAddress={};this.readChildNodes(a,b.contactAddress)},AddressType:function(a,b){b.type=this.getChildValue(a)},Address:function(a,b){b.address=this.getChildValue(a)},City:function(a,b){b.city=this.getChildValue(a)},StateOrProvince:function(a,b){b.stateOrProvince=this.getChildValue(a)},PostCode:function(a,b){b.postcode=this.getChildValue(a)},Country:function(a,b){b.country=this.getChildValue(a)},ContactVoiceTelephone:function(a,b){b.phone=this.getChildValue(a)},ContactFacsimileTelephone:function(a,
-b){b.fax=this.getChildValue(a)},ContactElectronicMailAddress:function(a,b){b.email=this.getChildValue(a)},Fees:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.fees=c)},AccessConstraints:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.accessConstraints=c)},Capability:function(a,b){b.capability={nestedLayers:[],layers:[]};this.readChildNodes(a,b.capability)},Request:function(a,b){b.request={};this.readChildNodes(a,b.request)},GetCapabilities:function(a,
-b){b.getcapabilities={formats:[]};this.readChildNodes(a,b.getcapabilities)},Format:function(a,b){OpenLayers.Util.isArray(b.formats)?b.formats.push(this.getChildValue(a)):b.format=this.getChildValue(a)},DCPType:function(a,b){this.readChildNodes(a,b)},HTTP:function(a,b){this.readChildNodes(a,b)},Get:function(a,b){b.get={};this.readChildNodes(a,b.get);b.href||(b.href=b.get.href)},Post:function(a,b){b.post={};this.readChildNodes(a,b.post);b.href||(b.href=b.get.href)},GetMap:function(a,b){b.getmap={formats:[]};
-this.readChildNodes(a,b.getmap)},GetFeatureInfo:function(a,b){b.getfeatureinfo={formats:[]};this.readChildNodes(a,b.getfeatureinfo)},Exception:function(a,b){b.exception={formats:[]};this.readChildNodes(a,b.exception)},Layer:function(a,b){var c,d;b.capability?(d=b.capability,c=b):d=b;var e=a.getAttributeNode("queryable"),f=e&&e.specified?a.getAttribute("queryable"):null,g=(e=a.getAttributeNode("cascaded"))&&e.specified?a.getAttribute("cascaded"):null,e=(e=a.getAttributeNode("opaque"))&&e.specified?
-a.getAttribute("opaque"):null,h=a.getAttribute("noSubsets"),k=a.getAttribute("fixedWidth"),l=a.getAttribute("fixedHeight"),m=c||{},n=OpenLayers.Util.extend;c={nestedLayers:[],styles:c?[].concat(c.styles):[],srs:c?n({},m.srs):{},metadataURLs:[],bbox:c?n({},m.bbox):{},llbbox:m.llbbox,dimensions:c?n({},m.dimensions):{},authorityURLs:c?n({},m.authorityURLs):{},identifiers:{},keywords:[],queryable:f&&""!==f?"1"===f||"true"===f:m.queryable||!1,cascaded:null!==g?parseInt(g):m.cascaded||0,opaque:e?"1"===
-e||"true"===e:m.opaque||!1,noSubsets:null!==h?"1"===h||"true"===h:m.noSubsets||!1,fixedWidth:null!=k?parseInt(k):m.fixedWidth||0,fixedHeight:null!=l?parseInt(l):m.fixedHeight||0,minScale:m.minScale,maxScale:m.maxScale,attribution:m.attribution};b.nestedLayers.push(c);c.capability=d;this.readChildNodes(a,c);delete c.capability;c.name&&(f=c.name.split(":"),g=d.request,e=g.getfeatureinfo,0<f.length&&(c.prefix=f[0]),d.layers.push(c),void 0===c.formats&&(c.formats=g.getmap.formats),void 0===c.infoFormats&&
-e&&(c.infoFormats=e.formats))},Attribution:function(a,b){b.attribution={};this.readChildNodes(a,b.attribution)},LogoURL:function(a,b){b.logo={width:a.getAttribute("width"),height:a.getAttribute("height")};this.readChildNodes(a,b.logo)},Style:function(a,b){var c={};b.styles.push(c);this.readChildNodes(a,c)},LegendURL:function(a,b){var c={width:a.getAttribute("width"),height:a.getAttribute("height")};b.legend=c;this.readChildNodes(a,c)},MetadataURL:function(a,b){var c={type:a.getAttribute("type")};
-b.metadataURLs.push(c);this.readChildNodes(a,c)},DataURL:function(a,b){b.dataURL={};this.readChildNodes(a,b.dataURL)},FeatureListURL:function(a,b){b.featureListURL={};this.readChildNodes(a,b.featureListURL)},AuthorityURL:function(a,b){var c=a.getAttribute("name"),d={};this.readChildNodes(a,d);b.authorityURLs[c]=d.href},Identifier:function(a,b){var c=a.getAttribute("authority");b.identifiers[c]=this.getChildValue(a)},KeywordList:function(a,b){this.readChildNodes(a,b)},SRS:function(a,b){b.srs[this.getChildValue(a)]=
-!0}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1"});OpenLayers.Format.WMSCapabilities.v1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{wms:OpenLayers.Util.applyDefaults({WMT_MS_Capabilities:function(a,b){this.readChildNodes(a,b)},Keyword:function(a,b){b.keywords&&b.keywords.push(this.getChildValue(a))},DescribeLayer:function(a,b){b.describelayer={formats:[]};this.readChildNodes(a,b.describelayer)},GetLegendGraphic:function(a,b){b.getlegendgraphic={formats:[]};this.readChildNodes(a,b.getlegendgraphic)},GetStyles:function(a,b){b.getstyles=
-{formats:[]};this.readChildNodes(a,b.getstyles)},PutStyles:function(a,b){b.putstyles={formats:[]};this.readChildNodes(a,b.putstyles)},UserDefinedSymbolization:function(a,b){var c={supportSLD:1==parseInt(a.getAttribute("SupportSLD")),userLayer:1==parseInt(a.getAttribute("UserLayer")),userStyle:1==parseInt(a.getAttribute("UserStyle")),remoteWFS:1==parseInt(a.getAttribute("RemoteWFS"))};b.userSymbols=c},LatLonBoundingBox:function(a,b){b.llbbox=[parseFloat(a.getAttribute("minx")),parseFloat(a.getAttribute("miny")),
-parseFloat(a.getAttribute("maxx")),parseFloat(a.getAttribute("maxy"))]},BoundingBox:function(a,b){var c=OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms.BoundingBox.apply(this,[a,b]);c.srs=a.getAttribute("SRS");b.bbox[c.srs]=c},ScaleHint:function(a,b){var c=a.getAttribute("min"),d=a.getAttribute("max"),e=Math.pow(2,0.5),f=OpenLayers.INCHES_PER_UNIT.m;0!=c&&(b.maxScale=parseFloat((c/e*f*OpenLayers.DOTS_PER_INCH).toPrecision(13)));d!=Number.POSITIVE_INFINITY&&(b.minScale=parseFloat((d/e*f*
-OpenLayers.DOTS_PER_INCH).toPrecision(13)))},Dimension:function(a,b){var c={name:a.getAttribute("name").toLowerCase(),units:a.getAttribute("units"),unitsymbol:a.getAttribute("unitSymbol")};b.dimensions[c.name]=c},Extent:function(a,b){var c=a.getAttribute("name").toLowerCase();if(c in b.dimensions){c=b.dimensions[c];c.nearestVal="1"===a.getAttribute("nearestValue");c.multipleVal="1"===a.getAttribute("multipleValues");c.current="1"===a.getAttribute("current");c["default"]=a.getAttribute("default")||
-"";var d=this.getChildValue(a);c.values=d.split(",")}}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1"});OpenLayers.Format.WMSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.0",readers:{wms:OpenLayers.Util.applyDefaults({SRS:function(a,b){for(var c=this.getChildValue(a).split(/ +/),d=0,e=c.length;d<e;d++)b.srs[c[d]]=!0}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_0"});OpenLayers.Protocol.WFS.v1=OpenLayers.Class(OpenLayers.Protocol,{version:null,srsName:"EPSG:4326",featureType:null,featureNS:null,geometryName:"the_geom",schema:null,featurePrefix:"feature",formatOptions:null,readFormat:null,readOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=OpenLayers.Format.WFST(OpenLayers.Util.extend({version:this.version,featureType:this.featureType,featureNS:this.featureNS,featurePrefix:this.featurePrefix,geometryName:this.geometryName,
-srsName:this.srsName,schema:this.schema},this.formatOptions)));!a.geometryName&&1<parseFloat(this.format.version)&&this.setGeometryName(null)},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),
-c=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",a)]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},setFeatureType:function(a){this.featureType=a;this.format.featureType=a},setGeometryName:function(a){this.geometryName=a;this.format.geometryName=a},handleRead:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);if(b.callback){var c=
-a.priv;200<=c.status&&300>c.status?(c=this.parseResponse(c,b.readOptions))&&!1!==c.success?(b.readOptions&&"object"==b.readOptions.output?OpenLayers.Util.extend(a,c):a.features=c,a.code=OpenLayers.Protocol.Response.SUCCESS):(a.code=OpenLayers.Protocol.Response.FAILURE,a.error=c):a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseResponse:function(a,b){var c=a.responseXML;c&&c.documentElement||(c=a.responseText);if(!c||0>=c.length)return null;c=null!==this.readFormat?this.readFormat.read(c):
-this.format.read(c,b);if(!this.featureNS){var d=this.readFormat||this.format;this.featureNS=d.featureNS;d.autoConfig=!1;this.geometryName||this.setGeometryName(d.geometryName)}return c},commit:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:a});c.priv=OpenLayers.Request.POST({url:b.url,headers:b.headers,data:this.format.write(a,b),callback:this.createCallback(this.handleCommit,c,b)});
-return c},handleCommit:function(a,b){if(b.callback){var c=a.priv,d=c.responseXML;d&&d.documentElement||(d=c.responseText);c=this.format.read(d)||{};a.insertIds=c.insertIds||[];c.success?a.code=OpenLayers.Protocol.Response.SUCCESS:(a.code=OpenLayers.Protocol.Response.FAILURE,a.error=c);b.callback.call(b.scope,a)}},filterDelete:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);new OpenLayers.Protocol.Response({requestType:"commit"});var c=this.format.createElementNSPlus("wfs:Transaction",
-{attributes:{service:"WFS",version:this.version}}),d=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(b.featureNS?this.featurePrefix+":":"")+b.featureType}});b.featureNS&&d.setAttribute("xmlns:"+this.featurePrefix,b.featureNS);var e=this.format.writeNode("ogc:Filter",a);d.appendChild(e);c.appendChild(d);c=OpenLayers.Format.XML.prototype.write.apply(this.format,[c]);return OpenLayers.Request.POST({url:this.url,callback:b.callback||function(){},data:c})},abort:function(a){a&&a.priv.abort()},
-CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{click:{"in":"click",out:"clickout"},mousemove:{"in":"over",out:"out"},dblclick:{"in":"dblclick",out:null},mousedown:{"in":null,out:null},mouseup:{"in":null,out:null},touchstart:{"in":"click",out:"clickout"}},feature:null,lastFeature:null,down:null,up:null,clickTolerance:4,geometryTypes:null,stopClick:!0,stopDown:!0,stopUp:!1,initialize:function(a,b,c,d){OpenLayers.Handler.prototype.initialize.apply(this,[a,c,d]);this.layer=
-b},touchstart:function(a){this.startTouch();return OpenLayers.Event.isMultiTouch(a)?!0:this.mousedown(a)},touchmove:function(a){OpenLayers.Event.preventDefault(a)},mousedown:function(a){if(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))this.down=a.xy;return this.handle(a)?!this.stopDown:!0},mouseup:function(a){this.up=a.xy;return this.handle(a)?!this.stopUp:!0},click:function(a){return this.handle(a)?!this.stopClick:!0},mousemove:function(a){if(!this.callbacks.over&&!this.callbacks.out)return!0;
-this.handle(a);return!0},dblclick:function(a){return!this.handle(a)},geometryTypeMatches:function(a){return null==this.geometryTypes||-1<OpenLayers.Util.indexOf(this.geometryTypes,a.geometry.CLASS_NAME)},handle:function(a){this.feature&&!this.feature.layer&&(this.feature=null);var b=a.type,c=!1,d=!!this.feature,e="click"==b||"dblclick"==b||"touchstart"==b;(this.feature=this.layer.getFeatureFromEvent(a))&&!this.feature.layer&&(this.feature=null);this.lastFeature&&!this.lastFeature.layer&&(this.lastFeature=
-null);this.feature?("touchstart"===b&&OpenLayers.Event.preventDefault(a),a=this.feature!=this.lastFeature,this.geometryTypeMatches(this.feature)?(d&&a?(this.lastFeature&&this.triggerCallback(b,"out",[this.lastFeature]),this.triggerCallback(b,"in",[this.feature])):d&&!e||this.triggerCallback(b,"in",[this.feature]),this.lastFeature=this.feature,c=!0):(this.lastFeature&&(d&&a||e)&&this.triggerCallback(b,"out",[this.lastFeature]),this.feature=null)):this.lastFeature&&(d||e)&&this.triggerCallback(b,"out",
-[this.lastFeature]);return c},triggerCallback:function(a,b,c){if(b=this.EVENTMAP[a][b])"click"==a&&this.up&&this.down?(Math.sqrt(Math.pow(this.up.x-this.down.x,2)+Math.pow(this.up.y-this.down.y,2))<=this.clickTolerance&&this.callback(b,c),this.up=this.down=null):this.callback(b,c)},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.moveLayerToTop(),this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),a=!0);
-return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.moveLayerBack(),this.up=this.down=this.lastFeature=this.feature=null,this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),a=!0);return a},handleMapEvents:function(a){"removelayer"!=a.type&&"order"!=a.property||this.moveLayerToTop()},moveLayerToTop:function(){var a=Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1;this.layer.setZIndex(a)},
-moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.Layer.Vector.RootContainer=OpenLayers.Class(OpenLayers.Layer.Vector,{displayInLayerSwitcher:!1,layers:null,display:function(){},getFeatureFromEvent:function(a){for(var b=this.layers,c,d=0;d<b.length;d++)if(c=b[d].getFeatureFromEvent(a))return c},setMap:function(a){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);this.collectRoots();a.events.register("changelayer",this,this.handleChangeLayer)},removeMap:function(a){a.events.unregister("changelayer",this,this.handleChangeLayer);
-this.resetRoots();OpenLayers.Layer.Vector.prototype.removeMap.apply(this,arguments)},collectRoots:function(){for(var a,b=0;b<this.map.layers.length;++b)a=this.map.layers[b],-1!=OpenLayers.Util.indexOf(this.layers,a)&&a.renderer.moveRoot(this.renderer)},resetRoots:function(){for(var a,b=0;b<this.layers.length;++b)a=this.layers[b],this.renderer&&a.renderer.getRenderLayerId()==this.id&&this.renderer.moveRoot(a.renderer)},handleChangeLayer:function(a){var b=a.layer;"order"==a.property&&-1!=OpenLayers.Util.indexOf(this.layers,
-b)&&(this.resetRoots(),this.collectRoots())},CLASS_NAME:"OpenLayers.Layer.Vector.RootContainer"});OpenLayers.Control.SelectFeature=OpenLayers.Class(OpenLayers.Control,{multipleKey:null,toggleKey:null,multiple:!1,clickout:!0,toggle:!1,hover:!1,highlightOnly:!1,box:!1,onBeforeSelect:function(){},onSelect:function(){},onUnselect:function(){},scope:null,geometryTypes:null,layer:null,layers:null,callbacks:null,selectStyle:null,renderIntent:"select",handlers:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);null===this.scope&&(this.scope=this);this.initLayer(a);var c=
-{click:this.clickFeature,clickout:this.clickoutFeature};this.hover&&(c.over=this.overFeature,c.out=this.outFeature);this.callbacks=OpenLayers.Util.extend(c,this.callbacks);this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};this.box&&(this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"}))},initLayer:function(a){OpenLayers.Util.isArray(a)?(this.layers=a,this.layer=
-new OpenLayers.Layer.Vector.RootContainer(this.id+"_container",{layers:a})):this.layer=a},destroy:function(){this.active&&this.layers&&this.map.removeLayer(this.layer);OpenLayers.Control.prototype.destroy.apply(this,arguments);this.layers&&this.layer.destroy()},activate:function(){this.active||(this.layers&&this.map.addLayer(this.layer),this.handlers.feature.activate(),this.box&&this.handlers.box&&this.handlers.box.activate());return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.active&&
-(this.handlers.feature.deactivate(),this.handlers.box&&this.handlers.box.deactivate(),this.layers&&this.map.removeLayer(this.layer));return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},unselectAll:function(a){var b=this.layers||[this.layer],c,d,e,f;for(e=0;e<b.length;++e)if(c=b[e],f=0,null!=c.selectedFeatures)for(;c.selectedFeatures.length>f;)d=c.selectedFeatures[f],a&&a.except==d?++f:this.unselect(d)},clickFeature:function(a){this.hover||(-1<OpenLayers.Util.indexOf(a.layer.selectedFeatures,
-a)?this.toggleSelect()?this.unselect(a):this.multipleSelect()||this.unselectAll({except:a}):(this.multipleSelect()||this.unselectAll({except:a}),this.select(a)))},multipleSelect:function(){return this.multiple||this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]},toggleSelect:function(){return this.toggle||this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]},clickoutFeature:function(a){!this.hover&&this.clickout&&this.unselectAll()},overFeature:function(a){var b=
-a.layer;this.hover&&(this.highlightOnly?this.highlight(a):-1==OpenLayers.Util.indexOf(b.selectedFeatures,a)&&this.select(a))},outFeature:function(a){if(this.hover)if(this.highlightOnly){if(a._lastHighlighter==this.id)if(a._prevHighlighter&&a._prevHighlighter!=this.id){delete a._lastHighlighter;var b=this.map.getControl(a._prevHighlighter);b&&b.highlight(a)}else this.unhighlight(a)}else this.unselect(a)},highlight:function(a){var b=a.layer;!1!==this.events.triggerEvent("beforefeaturehighlighted",{feature:a})&&
-(a._prevHighlighter=a._lastHighlighter,a._lastHighlighter=this.id,b.drawFeature(a,this.selectStyle||this.renderIntent),this.events.triggerEvent("featurehighlighted",{feature:a}))},unhighlight:function(a){var b=a.layer;void 0==a._prevHighlighter?delete a._lastHighlighter:(a._prevHighlighter!=this.id&&(a._lastHighlighter=a._prevHighlighter),delete a._prevHighlighter);b.drawFeature(a,a.style||a.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:a})},select:function(a){var b=
-this.onBeforeSelect.call(this.scope,a),c=a.layer;!1!==b&&(b=c.events.triggerEvent("beforefeatureselected",{feature:a}),!1!==b&&(c.selectedFeatures.push(a),this.highlight(a),this.handlers.feature.lastFeature||(this.handlers.feature.lastFeature=c.selectedFeatures[0]),c.events.triggerEvent("featureselected",{feature:a}),this.onSelect.call(this.scope,a)))},unselect:function(a){var b=a.layer;this.unhighlight(a);OpenLayers.Util.removeItem(b.selectedFeatures,a);b.events.triggerEvent("featureunselected",
-{feature:a});this.onUnselect.call(this.scope,a)},selectBox:function(a){if(a instanceof OpenLayers.Bounds){var b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom});a=this.map.getLonLatFromPixel({x:a.right,y:a.top});b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);this.multipleSelect()||this.unselectAll();a=this.multiple;this.multiple=!0;var c=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:c});for(var d,e=0;e<c.length;++e){d=c[e];for(var f=0,g=d.features.length;f<g;++f){var h=
-d.features[f];h.getVisibility()&&(null==this.geometryTypes||-1<OpenLayers.Util.indexOf(this.geometryTypes,h.geometry.CLASS_NAME))&&b.toGeometry().intersects(h.geometry)&&-1==OpenLayers.Util.indexOf(d.selectedFeatures,h)&&this.select(h)}}this.multiple=a;this.events.triggerEvent("boxselectionend",{layers:c})}},setMap:function(a){this.handlers.feature.setMap(a);this.box&&this.handlers.box.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setLayer:function(a){var b=this.active;this.unselectAll();
-this.deactivate();this.layers&&(this.layer.destroy(),this.layers=null);this.initLayer(a);this.handlers.feature.layer=this.layer;b&&this.activate()},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:!1,citeCompliant:!1,mouseDown:!1,stoppedDown:null,lastDown:null,lastUp:null,persist:!1,stopDown:!1,stopUp:!1,layerOptions:null,pixelTolerance:5,lastTouchPx:null,initialize:function(a,b,c){c&&c.layerOptions&&c.layerOptions.styleMap||(this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{}));OpenLayers.Handler.prototype.initialize.apply(this,arguments)},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,
-arguments))return!1;var a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a);this.map.addLayer(this.layer);return!0},createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();
-this.layer.addFeatures([this.point],{silent:!0})},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments))return!1;this.cancel();null!=this.layer.map&&(this.destroyFeature(!0),this.layer.destroy(!1));this.layer=null;return!0},destroyFeature:function(a){!this.layer||!a&&this.persist||this.layer.destroyFeatures();this.point=null},destroyPersistedFeature:function(){var a=this.layer;a&&1<a.features.length&&this.layer.features[0].destroy()},finalize:function(a){this.mouseDown=
-!1;this.lastTouchPx=this.lastUp=this.lastDown=null;this.callback(a?"cancel":"done",[this.geometryClone()]);this.destroyFeature(a)},cancel:function(){this.finalize(!0)},click:function(a){OpenLayers.Event.stop(a);return!1},dblclick:function(a){OpenLayers.Event.stop(a);return!1},modifyFeature:function(a){this.point||this.createFeature(a);a=this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=a.lon;this.point.geometry.y=a.lat;this.callback("modify",[this.point.geometry,this.point,!1]);this.point.geometry.clearBounds();
-this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.point,this.style)},getGeometry:function(){var a=this.point&&this.point.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiPoint([a]));return a},geometryClone:function(){var a=this.getGeometry();return a&&a.clone()},mousedown:function(a){return this.down(a)},touchstart:function(a){this.startTouch();this.lastTouchPx=a.xy;return this.down(a)},mousemove:function(a){return this.move(a)},touchmove:function(a){this.lastTouchPx=a.xy;
-return this.move(a)},mouseup:function(a){return this.up(a)},touchend:function(a){a.xy=this.lastTouchPx;return this.up(a)},down:function(a){this.mouseDown=!0;this.lastDown=a.xy;this.touch||this.modifyFeature(a.xy);this.stoppedDown=this.stopDown;return!this.stopDown},move:function(a){this.touch||this.mouseDown&&!this.stoppedDown||this.modifyFeature(a.xy);return!0},up:function(a){this.mouseDown=!1;this.stoppedDown=this.stopDown;if(!this.checkModifiers(a)||this.lastUp&&this.lastUp.equals(a.xy)||!this.lastDown||
-!this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance))return!0;this.touch&&this.modifyFeature(a.xy);this.persist&&this.destroyPersistedFeature();this.lastUp=a.xy;this.finalize();return!this.stopUp},mouseout:function(a){OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)&&(this.stoppedDown=this.stopDown,this.mouseDown=!1)},passesTolerance:function(a,b,c){var d=!0;null!=c&&a&&b&&a.distanceTo(b)>c&&(d=!1);return d},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:!1,freehandToggle:"shiftKey",timerId:null,redoStack:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([this.point.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);
-this.point.geometry.clearBounds();this.layer.addFeatures([this.line,this.point],{silent:!0})},destroyFeature:function(a){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,a);this.line=null},destroyPersistedFeature:function(){var a=this.layer;a&&2<a.features.length&&this.layer.features[0].destroy()},removePoint:function(){this.point&&this.layer.removeFeatures([this.point])},addPoint:function(a){this.layer.removeFeatures([this.point]);a=this.layer.getLonLatFromViewPortPx(a);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a.lon,
-a.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack},insertXY:function(a,b){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(a,b),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack},insertDeltaXY:function(a,b){var c=this.getCurrentPointIndex()-
-1,c=this.line.geometry.components[c];!c||(isNaN(c.x)||isNaN(c.y))||this.insertXY(c.x+a,c.y+b)},insertDirectionLength:function(a,b){a*=Math.PI/180;var c=b*Math.cos(a),d=b*Math.sin(a);this.insertDeltaXY(c,d)},insertDeflectionLength:function(a,b){var c=this.getCurrentPointIndex()-1;if(0<c){var d=this.line.geometry.components[c],c=this.line.geometry.components[c-1],d=Math.atan2(d.y-c.y,d.x-c.x);this.insertDirectionLength(180*d/Math.PI+a,b)}},getCurrentPointIndex:function(){return this.line.geometry.components.length-
-1},undo:function(){var a=this.line.geometry,b=a.components,c=this.getCurrentPointIndex()-1,d=b[c],e=a.removeComponent(d);e&&(this.touch&&0<c&&(b=a.components,a=b[c-1],c=this.getCurrentPointIndex(),b=b[c],b.x=a.x,b.y=a.y),this.redoStack||(this.redoStack=[]),this.redoStack.push(d),this.drawFeature());return e},redo:function(){var a=this.redoStack&&this.redoStack.pop();a&&(this.line.geometry.addComponent(a,this.getCurrentPointIndex()),this.drawFeature());return!!a},freehandMode:function(a){return this.freehandToggle&&
-a[this.freehandToggle]?!this.freehand:this.freehand},modifyFeature:function(a,b){this.line||this.createFeature(a);var c=this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=c.lon;this.point.geometry.y=c.lat;this.callback("modify",[this.point.geometry,this.getSketch(),b]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.line},getGeometry:function(){var a=
-this.line&&this.line.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiLineString([a]));return a},touchstart:function(a){if(this.timerId&&this.passesTolerance(this.lastTouchPx,a.xy,this.doubleTouchTolerance))return this.finishGeometry(),window.clearTimeout(this.timerId),this.timerId=null,!1;this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,
-a)},down:function(a){var b=this.stopDown;this.freehandMode(a)&&(b=!0,this.touch&&(this.modifyFeature(a.xy,!!this.lastUp),OpenLayers.Event.stop(a)));this.touch||this.lastDown&&this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)||this.modifyFeature(a.xy,!!this.lastUp);this.mouseDown=!0;this.lastDown=a.xy;this.stoppedDown=b;return!b},move:function(a){if(this.stoppedDown&&this.freehandMode(a))return this.persist&&this.destroyPersistedFeature(),this.maxVertices&&this.line&&this.line.geometry.components.length===
-this.maxVertices?(this.removePoint(),this.finalize()):this.addPoint(a.xy),!1;this.touch||this.mouseDown&&!this.stoppedDown||this.modifyFeature(a.xy,!!this.lastUp);return!0},up:function(a){!this.mouseDown||this.lastUp&&this.lastUp.equals(a.xy)||(this.stoppedDown&&this.freehandMode(a)?(this.persist&&this.destroyPersistedFeature(),this.removePoint(),this.finalize()):this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)&&(this.touch&&this.modifyFeature(a.xy),null==this.lastUp&&this.persist&&this.destroyPersistedFeature(),
-this.addPoint(a.xy),this.lastUp=a.xy,this.line.geometry.components.length===this.maxVertices+1&&this.finishGeometry()));this.stoppedDown=this.stopDown;this.mouseDown=!1;return!this.stopUp},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-1]);this.removePoint();this.finalize()},dblclick:function(a){this.freehandMode(a)||this.finishGeometry();return!1},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Spherical=OpenLayers.Spherical||{};OpenLayers.Spherical.DEFAULT_RADIUS=6378137;OpenLayers.Spherical.computeDistanceBetween=function(a,b,c){c=c||OpenLayers.Spherical.DEFAULT_RADIUS;var d=Math.sin(Math.PI*(b.lon-a.lon)/360),e=Math.sin(Math.PI*(b.lat-a.lat)/360);a=e*e+d*d*Math.cos(Math.PI*a.lat/180)*Math.cos(Math.PI*b.lat/180);return 2*c*Math.atan2(Math.sqrt(a),Math.sqrt(1-a))};
-OpenLayers.Spherical.computeHeading=function(a,b){var c=Math.sin(Math.PI*(a.lon-b.lon)/180)*Math.cos(Math.PI*b.lat/180),d=Math.cos(Math.PI*a.lat/180)*Math.sin(Math.PI*b.lat/180)-Math.sin(Math.PI*a.lat/180)*Math.cos(Math.PI*b.lat/180)*Math.cos(Math.PI*(a.lon-b.lon)/180);return 180*Math.atan2(c,d)/Math.PI};OpenLayers.Control.CacheWrite=OpenLayers.Class(OpenLayers.Control,{layers:null,imageFormat:"image/png",quotaRegEx:/quota/i,setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);var b,c=this.layers||a.layers;for(b=c.length-1;0<=b;--b)this.addLayer({layer:c[b]});if(!this.layers)a.events.on({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this})},addLayer:function(a){a.layer.events.on({tileloadstart:this.makeSameOrigin,tileloaded:this.onTileLoaded,scope:this})},removeLayer:function(a){a.layer.events.un({tileloadstart:this.makeSameOrigin,
-tileloaded:this.onTileLoaded,scope:this})},makeSameOrigin:function(a){if(this.active&&(a=a.tile,a instanceof OpenLayers.Tile.Image&&!a.crossOriginKeyword&&"data:"!==a.url.substr(0,5))){var b=OpenLayers.Request.makeSameOrigin(a.url,OpenLayers.ProxyHost);OpenLayers.Control.CacheWrite.urlMap[b]=a.url;a.url=b}},onTileLoaded:function(a){this.active&&(!a.aborted&&a.tile instanceof OpenLayers.Tile.Image&&"data:"!==a.tile.url.substr(0,5))&&(this.cache({tile:a.tile}),delete OpenLayers.Control.CacheWrite.urlMap[a.tile.url])},
-cache:function(a){if(window.localStorage){a=a.tile;try{var b=a.getCanvasContext();b&&window.localStorage.setItem("olCache_"+(OpenLayers.Control.CacheWrite.urlMap[a.url]||a.url),b.canvas.toDataURL(this.imageFormat))}catch(c){(b=c.name||c.message)&&this.quotaRegEx.test(b)?this.events.triggerEvent("cachefull",{tile:a}):OpenLayers.Console.error(c.toString())}}},destroy:function(){if(this.layers||this.map){var a,b=this.layers||this.map.layers;for(a=b.length-1;0<=a;--a)this.removeLayer({layer:b[a]})}this.map&&
-this.map.events.un({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.CacheWrite"});OpenLayers.Control.CacheWrite.clearCache=function(){if(window.localStorage){var a,b;for(a=window.localStorage.length-1;0<=a;--a)b=window.localStorage.key(a),"olCache_"===b.substr(0,8)&&window.localStorage.removeItem(b)}};OpenLayers.Control.CacheWrite.urlMap={};OpenLayers.Format.Context=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{layerOptions:null,layerParams:null,read:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.read.apply(this,arguments);if(b&&b.map)if(this.context=c,b.map instanceof OpenLayers.Map)c=this.mergeContextToMap(c,b.map);else{var d=b.map;if(OpenLayers.Util.isElement(d)||"string"==typeof d)d={div:d};c=this.contextToMap(c,d)}return c},getLayerFromContext:function(a){var b,c,d={queryable:a.queryable,visibility:a.visibility,
-maxExtent:a.maxExtent,metadata:OpenLayers.Util.applyDefaults(a.metadata,{styles:a.styles,formats:a.formats,"abstract":a["abstract"],dataURL:a.dataURL}),numZoomLevels:a.numZoomLevels,units:a.units,isBaseLayer:a.isBaseLayer,opacity:a.opacity,displayInLayerSwitcher:a.displayInLayerSwitcher,singleTile:a.singleTile,tileSize:a.tileSize?new OpenLayers.Size(a.tileSize.width,a.tileSize.height):void 0,minScale:a.minScale||a.maxScaleDenominator,maxScale:a.maxScale||a.minScaleDenominator,srs:a.srs,dimensions:a.dimensions,
-metadataURL:a.metadataURL};this.layerOptions&&OpenLayers.Util.applyDefaults(d,this.layerOptions);var e={layers:a.name,transparent:a.transparent,version:a.version};if(a.formats&&0<a.formats.length)for(e.format=a.formats[0].value,b=0,c=a.formats.length;b<c;b++){var f=a.formats[b];if(!0==f.current){e.format=f.value;break}}if(a.styles&&0<a.styles.length)for(b=0,c=a.styles.length;b<c;b++)if(f=a.styles[b],!0==f.current){f.href?e.sld=f.href:f.body?e.sld_body=f.body:e.styles=f.name;break}this.layerParams&&
-OpenLayers.Util.applyDefaults(e,this.layerParams);b=null;c=a.service;c==OpenLayers.Format.Context.serviceTypes.WFS?(d.strategies=[new OpenLayers.Strategy.BBOX],d.protocol=new OpenLayers.Protocol.WFS({url:a.url,featurePrefix:a.name.split(":")[0],featureType:a.name.split(":").pop()}),b=new OpenLayers.Layer.Vector(a.title||a.name,d)):c==OpenLayers.Format.Context.serviceTypes.KML?(d.strategies=[new OpenLayers.Strategy.Fixed],d.protocol=new OpenLayers.Protocol.HTTP({url:a.url,format:new OpenLayers.Format.KML}),
-b=new OpenLayers.Layer.Vector(a.title||a.name,d)):c==OpenLayers.Format.Context.serviceTypes.GML?(d.strategies=[new OpenLayers.Strategy.Fixed],d.protocol=new OpenLayers.Protocol.HTTP({url:a.url,format:new OpenLayers.Format.GML}),b=new OpenLayers.Layer.Vector(a.title||a.name,d)):a.features?(b=new OpenLayers.Layer.Vector(a.title||a.name,d),b.addFeatures(a.features)):!0!==a.categoryLayer&&(b=new OpenLayers.Layer.WMS(a.title||a.name,a.url,e,d));return b},getLayersFromContext:function(a){for(var b=[],c=
-0,d=a.length;c<d;c++){var e=this.getLayerFromContext(a[c]);null!==e&&b.push(e)}return b},contextToMap:function(a,b){b=OpenLayers.Util.applyDefaults({maxExtent:a.maxExtent,projection:a.projection,units:a.units},b);b.maxExtent&&(b.maxResolution=b.maxExtent.getWidth()/OpenLayers.Map.TILE_WIDTH);b.metadata={contactInformation:a.contactInformation,"abstract":a["abstract"],keywords:a.keywords,logo:a.logo,descriptionURL:a.descriptionURL};var c=new OpenLayers.Map(b);c.addLayers(this.getLayersFromContext(a.layersContext));
-c.setCenter(a.bounds.getCenterLonLat(),c.getZoomForExtent(a.bounds,!0));return c},mergeContextToMap:function(a,b){b.addLayers(this.getLayersFromContext(a.layersContext));return b},write:function(a,b){a=this.toContext(a);return OpenLayers.Format.XML.VersionedOGC.prototype.write.apply(this,arguments)},CLASS_NAME:"OpenLayers.Format.Context"});
-OpenLayers.Format.Context.serviceTypes={WMS:"urn:ogc:serviceType:WMS",WFS:"urn:ogc:serviceType:WFS",WCS:"urn:ogc:serviceType:WCS",GML:"urn:ogc:serviceType:GML",SLD:"urn:ogc:serviceType:SLD",FES:"urn:ogc:serviceType:FES",KML:"urn:ogc:serviceType:KML"};OpenLayers.Format.WMC=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"1.1.0",layerToContext:function(a){var b=this.getParser(),c={queryable:a.queryable,visibility:a.visibility,name:a.params.LAYERS,title:a.name,"abstract":a.metadata["abstract"],dataURL:a.metadata.dataURL,metadataURL:a.metadataURL,server:{version:a.params.VERSION,url:a.url},maxExtent:a.maxExtent,transparent:a.params.TRANSPARENT,numZoomLevels:a.numZoomLevels,units:a.units,isBaseLayer:a.isBaseLayer,opacity:1==a.opacity?void 0:
-a.opacity,displayInLayerSwitcher:a.displayInLayerSwitcher,singleTile:a.singleTile,tileSize:a.singleTile||!a.tileSize?void 0:{width:a.tileSize.w,height:a.tileSize.h},minScale:a.options.resolutions||a.options.scales||a.options.maxResolution||a.options.minScale?a.minScale:void 0,maxScale:a.options.resolutions||a.options.scales||a.options.minResolution||a.options.maxScale?a.maxScale:void 0,formats:[],styles:[],srs:a.srs,dimensions:a.dimensions};a.metadata.servertitle&&(c.server.title=a.metadata.servertitle);
-if(a.metadata.formats&&0<a.metadata.formats.length)for(var d=0,e=a.metadata.formats.length;d<e;d++){var f=a.metadata.formats[d];c.formats.push({value:f.value,current:f.value==a.params.FORMAT})}else c.formats.push({value:a.params.FORMAT,current:!0});if(a.metadata.styles&&0<a.metadata.styles.length)for(d=0,e=a.metadata.styles.length;d<e;d++)b=a.metadata.styles[d],b.current=b.href==a.params.SLD||b.body==a.params.SLD_BODY||b.name==a.params.STYLES?!0:!1,c.styles.push(b);else c.styles.push({href:a.params.SLD,
-body:a.params.SLD_BODY,name:a.params.STYLES||b.defaultStyleName,title:b.defaultStyleTitle,current:!0});return c},toContext:function(a){var b={},c=a.layers;if("OpenLayers.Map"==a.CLASS_NAME){var d=a.metadata||{};b.size=a.getSize();b.bounds=a.getExtent();b.projection=a.projection;b.title=a.title;b.keywords=d.keywords;b["abstract"]=d["abstract"];b.logo=d.logo;b.descriptionURL=d.descriptionURL;b.contactInformation=d.contactInformation;b.maxExtent=a.maxExtent}else OpenLayers.Util.applyDefaults(b,a),void 0!=
-b.layers&&delete b.layers;void 0==b.layersContext&&(b.layersContext=[]);if(void 0!=c&&OpenLayers.Util.isArray(c))for(a=0,d=c.length;a<d;a++){var e=c[a];e instanceof OpenLayers.Layer.WMS&&b.layersContext.push(this.layerToContext(e))}return b},CLASS_NAME:"OpenLayers.Format.WMC"});OpenLayers.Format.WMC.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ol:"http://openlayers.org/context",wmc:"http://www.opengis.net/context",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"",getNamespacePrefix:function(a){var b=null;if(null==a)b=this.namespaces[this.defaultPrefix];else for(b in this.namespaces)if(this.namespaces[b]==a)break;return b},defaultPrefix:"wmc",rootPrefix:null,defaultStyleName:"",
-defaultStyleTitle:"Default",initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a=a.documentElement;this.rootPrefix=a.prefix;var b={version:a.getAttribute("version")};this.runChildNodes(b,a);return b},runChildNodes:function(a,b){for(var c=b.childNodes,d,e,f,g=0,h=c.length;g<h;++g)d=c[g],1==d.nodeType&&(e=this.getNamespacePrefix(d.namespaceURI),f=d.nodeName.split(":").pop(),
-(e=this["read_"+e+"_"+f])&&e.apply(this,[a,d]))},read_wmc_General:function(a,b){this.runChildNodes(a,b)},read_wmc_BoundingBox:function(a,b){a.projection=b.getAttribute("SRS");a.bounds=new OpenLayers.Bounds(b.getAttribute("minx"),b.getAttribute("miny"),b.getAttribute("maxx"),b.getAttribute("maxy"))},read_wmc_LayerList:function(a,b){a.layersContext=[];this.runChildNodes(a,b)},read_wmc_Layer:function(a,b){var c={visibility:"1"!=b.getAttribute("hidden"),queryable:"1"==b.getAttribute("queryable"),formats:[],
-styles:[],metadata:{}};this.runChildNodes(c,b);a.layersContext.push(c)},read_wmc_Extension:function(a,b){this.runChildNodes(a,b)},read_ol_units:function(a,b){a.units=this.getChildValue(b)},read_ol_maxExtent:function(a,b){var c=new OpenLayers.Bounds(b.getAttribute("minx"),b.getAttribute("miny"),b.getAttribute("maxx"),b.getAttribute("maxy"));a.maxExtent=c},read_ol_transparent:function(a,b){a.transparent=this.getChildValue(b)},read_ol_numZoomLevels:function(a,b){a.numZoomLevels=parseInt(this.getChildValue(b))},
-read_ol_opacity:function(a,b){a.opacity=parseFloat(this.getChildValue(b))},read_ol_singleTile:function(a,b){a.singleTile="true"==this.getChildValue(b)},read_ol_tileSize:function(a,b){var c={width:b.getAttribute("width"),height:b.getAttribute("height")};a.tileSize=c},read_ol_isBaseLayer:function(a,b){a.isBaseLayer="true"==this.getChildValue(b)},read_ol_displayInLayerSwitcher:function(a,b){a.displayInLayerSwitcher="true"==this.getChildValue(b)},read_wmc_Server:function(a,b){a.version=b.getAttribute("version");
-a.url=this.getOnlineResource_href(b);a.metadata.servertitle=b.getAttribute("title")},read_wmc_FormatList:function(a,b){this.runChildNodes(a,b)},read_wmc_Format:function(a,b){var c={value:this.getChildValue(b)};"1"==b.getAttribute("current")&&(c.current=!0);a.formats.push(c)},read_wmc_StyleList:function(a,b){this.runChildNodes(a,b)},read_wmc_Style:function(a,b){var c={};this.runChildNodes(c,b);"1"==b.getAttribute("current")&&(c.current=!0);a.styles.push(c)},read_wmc_SLD:function(a,b){this.runChildNodes(a,
-b)},read_sld_StyledLayerDescriptor:function(a,b){var c=OpenLayers.Format.XML.prototype.write.apply(this,[b]);a.body=c},read_sld_FeatureTypeStyle:function(a,b){var c=OpenLayers.Format.XML.prototype.write.apply(this,[b]);a.body=c},read_wmc_OnlineResource:function(a,b){a.href=this.getAttributeNS(b,this.namespaces.xlink,"href")},read_wmc_Name:function(a,b){var c=this.getChildValue(b);c&&(a.name=c)},read_wmc_Title:function(a,b){var c=this.getChildValue(b);c&&(a.title=c)},read_wmc_MetadataURL:function(a,
-b){a.metadataURL=this.getOnlineResource_href(b)},read_wmc_KeywordList:function(a,b){a.keywords=[];this.runChildNodes(a.keywords,b)},read_wmc_Keyword:function(a,b){a.push(this.getChildValue(b))},read_wmc_Abstract:function(a,b){var c=this.getChildValue(b);c&&(a["abstract"]=c)},read_wmc_LogoURL:function(a,b){a.logo={width:b.getAttribute("width"),height:b.getAttribute("height"),format:b.getAttribute("format"),href:this.getOnlineResource_href(b)}},read_wmc_DescriptionURL:function(a,b){a.descriptionURL=
-this.getOnlineResource_href(b)},read_wmc_ContactInformation:function(a,b){var c={};this.runChildNodes(c,b);a.contactInformation=c},read_wmc_ContactPersonPrimary:function(a,b){var c={};this.runChildNodes(c,b);a.personPrimary=c},read_wmc_ContactPerson:function(a,b){var c=this.getChildValue(b);c&&(a.person=c)},read_wmc_ContactOrganization:function(a,b){var c=this.getChildValue(b);c&&(a.organization=c)},read_wmc_ContactPosition:function(a,b){var c=this.getChildValue(b);c&&(a.position=c)},read_wmc_ContactAddress:function(a,
-b){var c={};this.runChildNodes(c,b);a.contactAddress=c},read_wmc_AddressType:function(a,b){var c=this.getChildValue(b);c&&(a.type=c)},read_wmc_Address:function(a,b){var c=this.getChildValue(b);c&&(a.address=c)},read_wmc_City:function(a,b){var c=this.getChildValue(b);c&&(a.city=c)},read_wmc_StateOrProvince:function(a,b){var c=this.getChildValue(b);c&&(a.stateOrProvince=c)},read_wmc_PostCode:function(a,b){var c=this.getChildValue(b);c&&(a.postcode=c)},read_wmc_Country:function(a,b){var c=this.getChildValue(b);
-c&&(a.country=c)},read_wmc_ContactVoiceTelephone:function(a,b){var c=this.getChildValue(b);c&&(a.phone=c)},read_wmc_ContactFacsimileTelephone:function(a,b){var c=this.getChildValue(b);c&&(a.fax=c)},read_wmc_ContactElectronicMailAddress:function(a,b){var c=this.getChildValue(b);c&&(a.email=c)},read_wmc_DataURL:function(a,b){a.dataURL=this.getOnlineResource_href(b)},read_wmc_LegendURL:function(a,b){var c={width:b.getAttribute("width"),height:b.getAttribute("height"),format:b.getAttribute("format"),
-href:this.getOnlineResource_href(b)};a.legend=c},read_wmc_DimensionList:function(a,b){a.dimensions={};this.runChildNodes(a.dimensions,b)},read_wmc_Dimension:function(a,b){var c={name:b.getAttribute("name").toLowerCase(),units:b.getAttribute("units")||"",unitSymbol:b.getAttribute("unitSymbol")||"",userValue:b.getAttribute("userValue")||"",nearestValue:"1"===b.getAttribute("nearestValue"),multipleValues:"1"===b.getAttribute("multipleValues"),current:"1"===b.getAttribute("current"),"default":b.getAttribute("default")||
-""},d=this.getChildValue(b);c.values=d.split(",");a[c.name]=c},write:function(a,b){var c=this.createElementDefaultNS("ViewContext");this.setAttributes(c,{version:this.VERSION,id:b&&"string"==typeof b.id?b.id:OpenLayers.Util.createUniqueID("OpenLayers_Context_")});this.setAttributeNS(c,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);c.appendChild(this.write_wmc_General(a));c.appendChild(this.write_wmc_LayerList(a));return OpenLayers.Format.XML.prototype.write.apply(this,[c])},createElementDefaultNS:function(a,
-b,c){a=this.createElementNS(this.namespaces[this.defaultPrefix],a);b&&a.appendChild(this.createTextNode(b));c&&this.setAttributes(a,c);return a},setAttributes:function(a,b){var c,d;for(d in b)c=b[d].toString(),c.match(/[A-Z]/)?this.setAttributeNS(a,null,d,c):a.setAttribute(d,c)},write_wmc_General:function(a){var b=this.createElementDefaultNS("General");a.size&&b.appendChild(this.createElementDefaultNS("Window",null,{width:a.size.w,height:a.size.h}));var c=a.bounds;b.appendChild(this.createElementDefaultNS("BoundingBox",
-null,{minx:c.left.toPrecision(18),miny:c.bottom.toPrecision(18),maxx:c.right.toPrecision(18),maxy:c.top.toPrecision(18),SRS:a.projection}));b.appendChild(this.createElementDefaultNS("Title",a.title));a.keywords&&b.appendChild(this.write_wmc_KeywordList(a.keywords));a["abstract"]&&b.appendChild(this.createElementDefaultNS("Abstract",a["abstract"]));a.logo&&b.appendChild(this.write_wmc_URLType("LogoURL",a.logo.href,a.logo));a.descriptionURL&&b.appendChild(this.write_wmc_URLType("DescriptionURL",a.descriptionURL));
-a.contactInformation&&b.appendChild(this.write_wmc_ContactInformation(a.contactInformation));b.appendChild(this.write_ol_MapExtension(a));return b},write_wmc_KeywordList:function(a){for(var b=this.createElementDefaultNS("KeywordList"),c=0,d=a.length;c<d;c++)b.appendChild(this.createElementDefaultNS("Keyword",a[c]));return b},write_wmc_ContactInformation:function(a){var b=this.createElementDefaultNS("ContactInformation");a.personPrimary&&b.appendChild(this.write_wmc_ContactPersonPrimary(a.personPrimary));
-a.position&&b.appendChild(this.createElementDefaultNS("ContactPosition",a.position));a.contactAddress&&b.appendChild(this.write_wmc_ContactAddress(a.contactAddress));a.phone&&b.appendChild(this.createElementDefaultNS("ContactVoiceTelephone",a.phone));a.fax&&b.appendChild(this.createElementDefaultNS("ContactFacsimileTelephone",a.fax));a.email&&b.appendChild(this.createElementDefaultNS("ContactElectronicMailAddress",a.email));return b},write_wmc_ContactPersonPrimary:function(a){var b=this.createElementDefaultNS("ContactPersonPrimary");
-a.person&&b.appendChild(this.createElementDefaultNS("ContactPerson",a.person));a.organization&&b.appendChild(this.createElementDefaultNS("ContactOrganization",a.organization));return b},write_wmc_ContactAddress:function(a){var b=this.createElementDefaultNS("ContactAddress");a.type&&b.appendChild(this.createElementDefaultNS("AddressType",a.type));a.address&&b.appendChild(this.createElementDefaultNS("Address",a.address));a.city&&b.appendChild(this.createElementDefaultNS("City",a.city));a.stateOrProvince&&
-b.appendChild(this.createElementDefaultNS("StateOrProvince",a.stateOrProvince));a.postcode&&b.appendChild(this.createElementDefaultNS("PostCode",a.postcode));a.country&&b.appendChild(this.createElementDefaultNS("Country",a.country));return b},write_ol_MapExtension:function(a){var b=this.createElementDefaultNS("Extension");if(a=a.maxExtent){var c=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(c,{minx:a.left.toPrecision(18),miny:a.bottom.toPrecision(18),maxx:a.right.toPrecision(18),
-maxy:a.top.toPrecision(18)});b.appendChild(c)}return b},write_wmc_LayerList:function(a){for(var b=this.createElementDefaultNS("LayerList"),c=0,d=a.layersContext.length;c<d;++c)b.appendChild(this.write_wmc_Layer(a.layersContext[c]));return b},write_wmc_Layer:function(a){var b=this.createElementDefaultNS("Layer",null,{queryable:a.queryable?"1":"0",hidden:a.visibility?"0":"1"});b.appendChild(this.write_wmc_Server(a));b.appendChild(this.createElementDefaultNS("Name",a.name));b.appendChild(this.createElementDefaultNS("Title",
-a.title));a["abstract"]&&b.appendChild(this.createElementDefaultNS("Abstract",a["abstract"]));a.dataURL&&b.appendChild(this.write_wmc_URLType("DataURL",a.dataURL));a.metadataURL&&b.appendChild(this.write_wmc_URLType("MetadataURL",a.metadataURL));return b},write_wmc_LayerExtension:function(a){var b=this.createElementDefaultNS("Extension"),c=a.maxExtent,d=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(d,{minx:c.left.toPrecision(18),miny:c.bottom.toPrecision(18),maxx:c.right.toPrecision(18),
-maxy:c.top.toPrecision(18)});b.appendChild(d);a.tileSize&&!a.singleTile&&(c=this.createElementNS(this.namespaces.ol,"ol:tileSize"),this.setAttributes(c,a.tileSize),b.appendChild(c));for(var c="transparent numZoomLevels units isBaseLayer opacity displayInLayerSwitcher singleTile".split(" "),e=0,f=c.length;e<f;++e)(d=this.createOLPropertyNode(a,c[e]))&&b.appendChild(d);return b},createOLPropertyNode:function(a,b){var c=null;null!=a[b]&&(c=this.createElementNS(this.namespaces.ol,"ol:"+b),c.appendChild(this.createTextNode(a[b].toString())));
-return c},write_wmc_Server:function(a){a=a.server;var b=this.createElementDefaultNS("Server"),c={service:"OGC:WMS",version:a.version};a.title&&(c.title=a.title);this.setAttributes(b,c);b.appendChild(this.write_wmc_OnlineResource(a.url));return b},write_wmc_URLType:function(a,b,c){a=this.createElementDefaultNS(a);a.appendChild(this.write_wmc_OnlineResource(b));if(c){b=["width","height","format"];for(var d=0;d<b.length;d++)b[d]in c&&a.setAttribute(b[d],c[b[d]])}return a},write_wmc_DimensionList:function(a){var b=
-this.createElementDefaultNS("DimensionList"),c;for(c in a.dimensions){var d={},e=a.dimensions[c],f;for(f in e)d[f]="boolean"==typeof e[f]?Number(e[f]):e[f];e="";d.values&&(e=d.values.join(","),delete d.values);b.appendChild(this.createElementDefaultNS("Dimension",e,d))}return b},write_wmc_FormatList:function(a){for(var b=this.createElementDefaultNS("FormatList"),c=0,d=a.formats.length;c<d;c++){var e=a.formats[c];b.appendChild(this.createElementDefaultNS("Format",e.value,e.current&&!0==e.current?{current:"1"}:
-null))}return b},write_wmc_StyleList:function(a){var b=this.createElementDefaultNS("StyleList");if((a=a.styles)&&OpenLayers.Util.isArray(a))for(var c,d=0,e=a.length;d<e;d++){var f=a[d],g=this.createElementDefaultNS("Style",null,f.current&&!0==f.current?{current:"1"}:null);f.href?(c=this.createElementDefaultNS("SLD"),f.name&&c.appendChild(this.createElementDefaultNS("Name",f.name)),f.title&&c.appendChild(this.createElementDefaultNS("Title",f.title)),f.legend&&c.appendChild(this.write_wmc_URLType("LegendURL",
-f.legend.href,f.legend)),f=this.write_wmc_OnlineResource(f.href),c.appendChild(f),g.appendChild(c)):f.body?(c=this.createElementDefaultNS("SLD"),f.name&&c.appendChild(this.createElementDefaultNS("Name",f.name)),f.title&&c.appendChild(this.createElementDefaultNS("Title",f.title)),f.legend&&c.appendChild(this.write_wmc_URLType("LegendURL",f.legend.href,f.legend)),f=OpenLayers.Format.XML.prototype.read.apply(this,[f.body]).documentElement,c.ownerDocument&&c.ownerDocument.importNode&&(f=c.ownerDocument.importNode(f,
-!0)),c.appendChild(f),g.appendChild(c)):(g.appendChild(this.createElementDefaultNS("Name",f.name)),g.appendChild(this.createElementDefaultNS("Title",f.title)),f["abstract"]&&g.appendChild(this.createElementDefaultNS("Abstract",f["abstract"])),f.legend&&g.appendChild(this.write_wmc_URLType("LegendURL",f.legend.href,f.legend)));b.appendChild(g)}return b},write_wmc_OnlineResource:function(a){var b=this.createElementDefaultNS("OnlineResource");this.setAttributeNS(b,this.namespaces.xlink,"xlink:type",
-"simple");this.setAttributeNS(b,this.namespaces.xlink,"xlink:href",a);return b},getOnlineResource_href:function(a){var b={};a=a.getElementsByTagName("OnlineResource");0<a.length&&this.read_wmc_OnlineResource(b,a[0]);return b.href},CLASS_NAME:"OpenLayers.Format.WMC.v1"});OpenLayers.Control.PanPanel=OpenLayers.Class(OpenLayers.Control.Panel,{slideFactor:50,slideRatio:null,initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);a={slideFactor:this.slideFactor,slideRatio:this.slideRatio};this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST,a)])},
-CLASS_NAME:"OpenLayers.Control.PanPanel"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({removelayer:this.updateAttribution,addlayer:this.updateAttribution,changelayer:this.updateAttribution,changebaselayer:this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({changebaselayer:this.updateAttribution,changelayer:this.updateAttribution,
-addlayer:this.updateAttribution,removelayer:this.updateAttribution,scope:this});this.updateAttribution();return this.div},updateAttribution:function(){var a=[];if(this.map&&this.map.layers){for(var b=0,c=this.map.layers.length;b<c;b++){var d=this.map.layers[b];d.attribution&&d.getVisibility()&&-1===OpenLayers.Util.indexOf(a,d.attribution)&&a.push(d.attribution)}this.div.innerHTML=OpenLayers.String.format(this.template,{layers:a.join(this.separator)})}},CLASS_NAME:"OpenLayers.Control.Attribution"});OpenLayers.Kinetic=OpenLayers.Class({threshold:0,deceleration:0.0035,nbPoints:100,delay:200,points:void 0,timerId:void 0,initialize:function(a){OpenLayers.Util.extend(this,a)},begin:function(){OpenLayers.Animation.stop(this.timerId);this.timerId=void 0;this.points=[]},update:function(a){this.points.unshift({xy:a,tick:(new Date).getTime()});this.points.length>this.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;d<e;d++){f=this.points[d];if(c-
-f.tick>this.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(0==d||d<this.threshold)))return c=Math.asin((a.y-b.xy.y)/c),b.xy.x<=a.x&&(c=Math.PI-c),{speed:d,theta:c}},move:function(a,b){var c=a.speed,d=Math.cos(a.theta),e=-Math.sin(a.theta),f=(new Date).getTime(),g=0,h=0;this.timerId=OpenLayers.Animation.start(OpenLayers.Function.bind(function(){if(null!=this.timerId){var a=(new Date).getTime()-f,l=-this.deceleration*Math.pow(a,
-2)/2+c*a,m=l*d,l=l*e,n,p;n=!1;0>=-this.deceleration*a+c&&(OpenLayers.Animation.stop(this.timerId),this.timerId=null,n=!0);a=m-g;p=l-h;g=m;h=l;b(a,p,n)}},this))},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Format.WPSExecute=OpenLayers.Class(OpenLayers.Format.XML,OpenLayers.Format.Filter.v1_1_0,{namespaces:{ows:"http://www.opengis.net/ows/1.1",gml:"http://www.opengis.net/gml",wps:"http://www.opengis.net/wps/1.0.0",wfs:"http://www.opengis.net/wfs",ogc:"http://www.opengis.net/ogc",wcs:"http://www.opengis.net/wcs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.0.0",
-schemaLocation:"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd",schemaLocationAttr:function(a){},write:function(a){var b;window.ActiveXObject?this.xmldom=b=new ActiveXObject("Microsoft.XMLDOM"):b=document.implementation.createDocument("","",null);a=this.writeNode("wps:Execute",a,b);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},read:function(a){"string"==typeof a&&(a=
-OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},writers:{wps:{Execute:function(a){var b=this.createElementNSPlus("wps:Execute",{attributes:{version:this.VERSION,service:"WPS"}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("wps:DataInputs",a.dataInputs,b);this.writeNode("wps:ResponseForm",a.responseForm,b);return b},ResponseForm:function(a){var b=this.createElementNSPlus("wps:ResponseForm",{});a.rawDataOutput&&
-this.writeNode("wps:RawDataOutput",a.rawDataOutput,b);a.responseDocument&&this.writeNode("wps:ResponseDocument",a.responseDocument,b);return b},ResponseDocument:function(a){var b=this.createElementNSPlus("wps:ResponseDocument",{attributes:{storeExecuteResponse:a.storeExecuteResponse,lineage:a.lineage,status:a.status}});if(a.outputs)for(var c=0,d=a.outputs.length;c<d;c++)this.writeNode("wps:Output",a.outputs[c],b);return b},Output:function(a){var b=this.createElementNSPlus("wps:Output",{attributes:{asReference:a.asReference,
-mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("ows:Title",a.title,b);this.writeNode("ows:Abstract",a["abstract"],b);return b},RawDataOutput:function(a){var b=this.createElementNSPlus("wps:RawDataOutput",{attributes:{mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}});this.writeNode("ows:Identifier",a.identifier,b);return b},DataInputs:function(a){for(var b=this.createElementNSPlus("wps:DataInputs",{}),c=0,d=a.length;c<
-d;++c)this.writeNode("wps:Input",a[c],b);return b},Input:function(a){var b=this.createElementNSPlus("wps:Input",{});this.writeNode("ows:Identifier",a.identifier,b);a.title&&this.writeNode("ows:Title",a.title,b);a.data&&this.writeNode("wps:Data",a.data,b);a.reference&&this.writeNode("wps:Reference",a.reference,b);a.boundingBoxData&&this.writeNode("wps:BoundingBoxData",a.boundingBoxData,b);return b},Data:function(a){var b=this.createElementNSPlus("wps:Data",{});a.literalData?this.writeNode("wps:LiteralData",
-a.literalData,b):a.complexData?this.writeNode("wps:ComplexData",a.complexData,b):a.boundingBoxData&&this.writeNode("ows:BoundingBox",a.boundingBoxData,b);return b},LiteralData:function(a){return this.createElementNSPlus("wps:LiteralData",{attributes:{uom:a.uom},value:a.value})},ComplexData:function(a){var b=this.createElementNSPlus("wps:ComplexData",{attributes:{mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}}),c=a.value;"string"===typeof c?b.appendChild(this.getXMLDoc().createCDATASection(a.value)):
-b.appendChild(c);return b},Reference:function(a){var b=this.createElementNSPlus("wps:Reference",{attributes:{mimeType:a.mimeType,"xlink:href":a.href,method:a.method,encoding:a.encoding,schema:a.schema}});a.body&&this.writeNode("wps:Body",a.body,b);return b},BoundingBoxData:function(a,b){this.writers.ows.BoundingBox.apply(this,[a,b,"wps:BoundingBoxData"])},Body:function(a){var b=this.createElementNSPlus("wps:Body",{});a.wcs?this.writeNode("wcs:GetCoverage",a.wcs,b):a.wfs?(this.featureType=a.wfs.featureType,
-this.version=a.wfs.version,this.writeNode("wfs:GetFeature",a.wfs,b)):this.writeNode("wps:Execute",a,b);return b}},wcs:OpenLayers.Format.WCSGetCoverage.prototype.writers.wcs,wfs:OpenLayers.Format.WFST.v1_1_0.prototype.writers.wfs,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc,ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows},readers:{wps:{ExecuteResponse:function(a,b){b.executeResponse={lang:a.getAttribute("lang"),statusLocation:a.getAttribute("statusLocation"),serviceInstance:a.getAttribute("serviceInstance"),
-service:a.getAttribute("service")};this.readChildNodes(a,b.executeResponse)},Process:function(a,b){b.process={};this.readChildNodes(a,b.process)},Status:function(a,b){b.status={creationTime:a.getAttribute("creationTime")};this.readChildNodes(a,b.status)},ProcessSucceeded:function(a,b){b.processSucceeded=!0},ProcessOutputs:function(a,b){b.processOutputs=[];this.readChildNodes(a,b.processOutputs)},Output:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},Reference:function(a,b){b.reference=
-{href:a.getAttribute("href"),mimeType:a.getAttribute("mimeType"),encoding:a.getAttribute("encoding"),schema:a.getAttribute("schema")}},Data:function(a,b){b.data={};this.readChildNodes(a,b)},LiteralData:function(a,b){b.literalData={dataType:a.getAttribute("dataType"),uom:a.getAttribute("uom"),value:this.getChildValue(a)}},ComplexData:function(a,b){b.complexData={mimeType:a.getAttribute("mimeType"),schema:a.getAttribute("schema"),encoding:a.getAttribute("encoding"),value:""};if(this.isSimpleContent(a)){var c;
-for(c=a.firstChild;c;c=c.nextSibling)switch(c.nodeType){case 3:case 4:b.complexData.value+=c.nodeValue}}else for(c=a.firstChild;c;c=c.nextSibling)1==c.nodeType&&(b.complexData.value=c)},BoundingBox:function(a,b){b.boundingBoxData={dimensions:a.getAttribute("dimensions"),crs:a.getAttribute("crs")};this.readChildNodes(a,b.boundingBoxData)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSExecute"});OpenLayers.Layer.GeoRSS=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,icon:null,popupSize:null,useFeedTitle:!0,initialize:function(a,b,c){OpenLayers.Layer.Markers.prototype.initialize.apply(this,[a,c]);this.location=b;this.features=[]},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null},loadRSS:function(){this.loaded||(this.events.triggerEvent("loadstart"),OpenLayers.Request.GET({url:this.location,
-success:this.parseData,scope:this}),this.loaded=!0)},moveTo:function(a,b,c){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);this.visibility&&!this.loaded&&this.loadRSS()},parseData:function(a){var b=a.responseXML;b&&b.documentElement||(b=OpenLayers.Format.XML.prototype.read(a.responseText));if(this.useFeedTitle){a=null;try{a=b.getElementsByTagNameNS("*","title")[0].firstChild.nodeValue}catch(c){a=b.getElementsByTagName("title")[0].firstChild.nodeValue}a&&this.setName(a)}a={};OpenLayers.Util.extend(a,
-this.formatOptions);this.map&&!this.projection.equals(this.map.getProjectionObject())&&(a.externalProjection=this.projection,a.internalProjection=this.map.getProjectionObject());b=(new OpenLayers.Format.GeoRSS(a)).read(b);a=0;for(var d=b.length;a<d;a++){var e={},f=b[a];if(f.geometry){var g=f.attributes.title?f.attributes.title:"Untitled",h=f.attributes.description?f.attributes.description:"No description.",k=f.attributes.link?f.attributes.link:"",f=f.geometry.getBounds().getCenterLonLat();e.icon=
-null==this.icon?OpenLayers.Marker.defaultIcon():this.icon.clone();e.popupSize=this.popupSize?this.popupSize.clone():new OpenLayers.Size(250,120);if(g||h){e.title=g;e.description=h;var l='<div class="olLayerGeoRSSClose">[x]</div>',l=l+'<div class="olLayerGeoRSSTitle">';k&&(l+='<a class="link" href="'+k+'" target="_blank">');l+=g;k&&(l+="</a>");l+="</div>";l+='<div style="" class="olLayerGeoRSSDescription">';l+=h;l+="</div>";e.popupContentHTML=l}f=new OpenLayers.Feature(this,f,e);this.features.push(f);
-e=f.createMarker();e.events.register("click",f,this.markerClick);this.addMarker(e)}}this.events.triggerEvent("loadend")},markerClick:function(a){var b=this==this.layer.selectedFeature;this.layer.selectedFeature=b?null:this;for(var c=0,d=this.layer.map.popups.length;c<d;c++)this.layer.map.removePopup(this.layer.map.popups[c]);b||(b=this.createPopup(),OpenLayers.Event.observe(b.div,"click",OpenLayers.Function.bind(function(){for(var a=0,b=this.layer.map.popups.length;a<b;a++)this.layer.map.removePopup(this.layer.map.popups[a])},
-this)),this.layer.map.addPopup(b));OpenLayers.Event.stop(a)},clearFeatures:function(){if(null!=this.features)for(;0<this.features.length;){var a=this.features[0];OpenLayers.Util.removeItem(this.features,a);a.destroy()}},CLASS_NAME:"OpenLayers.Layer.GeoRSS"});OpenLayers.Symbolizer.Point=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Point"});OpenLayers.Symbolizer.Line=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Line"});OpenLayers.Symbolizer.Text=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Text"});OpenLayers.Format.SLD.v1=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,{namespaces:{sld:"http://www.opengis.net/sld",ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"sld",schemaLocation:null,multipleSymbolizers:!1,featureTypeCounter:null,defaultSymbolizer:{fillColor:"#808080",fillOpacity:1,strokeColor:"#000000",strokeOpacity:1,strokeWidth:1,strokeDashstyle:"solid",pointRadius:3,
-graphicName:"square"},read:function(a,b){b=OpenLayers.Util.applyDefaults(b,this.options);var c={namedLayers:!0===b.namedLayersAsArray?[]:{}};this.readChildNodes(a,c);return c},readers:OpenLayers.Util.applyDefaults({sld:{StyledLayerDescriptor:function(a,b){b.version=a.getAttribute("version");this.readChildNodes(a,b)},Name:function(a,b){b.name=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b.description=this.getChildValue(a)},NamedLayer:function(a,b){var c=
-{userStyles:[],namedStyles:[]};this.readChildNodes(a,c);for(var d=0,e=c.userStyles.length;d<e;++d)c.userStyles[d].layerName=c.name;OpenLayers.Util.isArray(b.namedLayers)?b.namedLayers.push(c):b.namedLayers[c.name]=c},NamedStyle:function(a,b){b.namedStyles.push(this.getChildName(a.firstChild))},UserStyle:function(a,b){var c={defaultsPerSymbolizer:!0,rules:[]};this.featureTypeCounter=-1;this.readChildNodes(a,c);this.multipleSymbolizers?(delete c.defaultsPerSymbolizer,c=new OpenLayers.Style2(c)):c=new OpenLayers.Style(this.defaultSymbolizer,
-c);b.userStyles.push(c)},IsDefault:function(a,b){"1"==this.getChildValue(a)&&(b.isDefault=!0)},FeatureTypeStyle:function(a,b){++this.featureTypeCounter;var c={rules:this.multipleSymbolizers?b.rules:[]};this.readChildNodes(a,c);this.multipleSymbolizers||(b.rules=c.rules)},Rule:function(a,b){var c;this.multipleSymbolizers&&(c={symbolizers:[]});c=new OpenLayers.Rule(c);this.readChildNodes(a,c);b.rules.push(c)},ElseFilter:function(a,b){b.elseFilter=!0},MinScaleDenominator:function(a,b){b.minScaleDenominator=
-parseFloat(this.getChildValue(a))},MaxScaleDenominator:function(a,b){b.maxScaleDenominator=parseFloat(this.getChildValue(a))},TextSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Text(c))):b.symbolizer.Text=OpenLayers.Util.applyDefaults(c,b.symbolizer.Text)},LabelPlacement:function(a,b){this.readChildNodes(a,b)},PointPlacement:function(a,b){var c={};this.readChildNodes(a,c);c.labelRotation=
-c.rotation;delete c.rotation;var d,e=b.labelAnchorPointX,f=b.labelAnchorPointY;e<=1/3?d="l":e>1/3&&e<2/3?d="c":e>=2/3&&(d="r");f<=1/3?d+="b":f>1/3&&f<2/3?d+="m":f>=2/3&&(d+="t");c.labelAlign=d;OpenLayers.Util.applyDefaults(b,c)},AnchorPoint:function(a,b){this.readChildNodes(a,b)},AnchorPointX:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelAnchorPointX=c)},AnchorPointY:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelAnchorPointY=c)},Displacement:function(a,
-b){this.readChildNodes(a,b)},DisplacementX:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelXOffset=c)},DisplacementY:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelYOffset=c)},LinePlacement:function(a,b){this.readChildNodes(a,b)},PerpendicularOffset:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelPerpendicularOffset=c)},Label:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.label=c)},Font:function(a,b){this.readChildNodes(a,
-b)},Halo:function(a,b){var c={};this.readChildNodes(a,c);b.haloRadius=c.haloRadius;b.haloColor=c.fillColor;b.haloOpacity=c.fillOpacity},Radius:function(a,b){var c=this.readers.ogc._expression.call(this,a);null!=c&&(b.haloRadius=c)},RasterSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Raster(c))):b.symbolizer.Raster=OpenLayers.Util.applyDefaults(c,b.symbolizer.Raster)},Geometry:function(a,
-b){b.geometry={};this.readChildNodes(a,b.geometry)},ColorMap:function(a,b){b.colorMap=[];this.readChildNodes(a,b.colorMap)},ColorMapEntry:function(a,b){var c=a.getAttribute("quantity"),d=a.getAttribute("opacity");b.push({color:a.getAttribute("color"),quantity:null!==c?parseFloat(c):void 0,label:a.getAttribute("label")||void 0,opacity:null!==d?parseFloat(d):void 0})},LineSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Line(c))):
-b.symbolizer.Line=OpenLayers.Util.applyDefaults(c,b.symbolizer.Line)},PolygonSymbolizer:function(a,b){var c={fill:!1,stroke:!1};this.multipleSymbolizers||(c=b.symbolizer.Polygon||c);this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Polygon(c))):b.symbolizer.Polygon=c},PointSymbolizer:function(a,b){var c={fill:!1,stroke:!1,graphic:!1};this.multipleSymbolizers||(c=b.symbolizer.Point||c);this.readChildNodes(a,c);this.multipleSymbolizers?
-(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Point(c))):b.symbolizer.Point=c},Stroke:function(a,b){b.stroke=!0;this.readChildNodes(a,b)},Fill:function(a,b){b.fill=!0;this.readChildNodes(a,b)},CssParameter:function(a,b){var c=a.getAttribute("name"),d=this.cssMap[c];b.label&&("fill"===c?d="fontColor":"fill-opacity"===c&&(d="fontOpacity"));d&&(c=this.readers.ogc._expression.call(this,a))&&(b[d]=c)},Graphic:function(a,b){b.graphic=!0;var c={};this.readChildNodes(a,c);
-for(var d="stroke strokeColor strokeWidth strokeOpacity strokeLinecap fill fillColor fillOpacity graphicName rotation graphicFormat".split(" "),e,f,g=0,h=d.length;g<h;++g)e=d[g],f=c[e],void 0!=f&&(b[e]=f);void 0!=c.opacity&&(b.graphicOpacity=c.opacity);void 0!=c.size&&(isNaN(c.size/2)?b.graphicWidth=c.size:b.pointRadius=c.size/2);void 0!=c.href&&(b.externalGraphic=c.href);void 0!=c.rotation&&(b.rotation=c.rotation)},ExternalGraphic:function(a,b){this.readChildNodes(a,b)},Mark:function(a,b){this.readChildNodes(a,
-b)},WellKnownName:function(a,b){b.graphicName=this.getChildValue(a)},Opacity:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.opacity=c)},Size:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.size=c)},Rotation:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.rotation=c)},OnlineResource:function(a,b){b.href=this.getAttributeNS(a,this.namespaces.xlink,"href")},Format:function(a,b){b.graphicFormat=this.getChildValue(a)}}},OpenLayers.Format.Filter.v1_0_0.prototype.readers),
-cssMap:{stroke:"strokeColor","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","stroke-dasharray":"strokeDashstyle",fill:"fillColor","fill-opacity":"fillOpacity","font-family":"fontFamily","font-size":"fontSize","font-weight":"fontWeight","font-style":"fontStyle"},getCssProperty:function(a){var b=null,c;for(c in this.cssMap)if(this.cssMap[c]==a){b=c;break}return b},getGraphicFormat:function(a){var b,c;for(c in this.graphicFormats)if(this.graphicFormats[c].test(a)){b=
-c;break}return b||this.defaultGraphicFormat},defaultGraphicFormat:"image/png",graphicFormats:{"image/jpeg":/\.jpe?g$/i,"image/gif":/\.gif$/i,"image/png":/\.png$/i},write:function(a){return this.writers.sld.StyledLayerDescriptor.apply(this,[a])},writers:OpenLayers.Util.applyDefaults({sld:{_OGCExpression:function(a,b){var c=this.createElementNSPlus(a),d="string"==typeof b?b.split("${"):[b];c.appendChild(this.createTextNode(d[0]));for(var e,f,g=1,h=d.length;g<h;g++)e=d[g],f=e.indexOf("}"),0<f?(this.writeNode("ogc:PropertyName",
-{property:e.substring(0,f)},c),c.appendChild(this.createTextNode(e.substring(++f)))):c.appendChild(this.createTextNode("${"+e));return c},StyledLayerDescriptor:function(a){var b=this.createElementNSPlus("sld:StyledLayerDescriptor",{attributes:{version:this.VERSION,"xsi:schemaLocation":this.schemaLocation}});b.setAttribute("xmlns:ogc",this.namespaces.ogc);b.setAttribute("xmlns:gml",this.namespaces.gml);a.name&&this.writeNode("Name",a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&
-this.writeNode("Abstract",a.description,b);if(OpenLayers.Util.isArray(a.namedLayers))for(var c=0,d=a.namedLayers.length;c<d;++c)this.writeNode("NamedLayer",a.namedLayers[c],b);else for(c in a.namedLayers)this.writeNode("NamedLayer",a.namedLayers[c],b);return b},Name:function(a){return this.createElementNSPlus("sld:Name",{value:a})},Title:function(a){return this.createElementNSPlus("sld:Title",{value:a})},Abstract:function(a){return this.createElementNSPlus("sld:Abstract",{value:a})},NamedLayer:function(a){var b=
-this.createElementNSPlus("sld:NamedLayer");this.writeNode("Name",a.name,b);if(a.namedStyles)for(var c=0,d=a.namedStyles.length;c<d;++c)this.writeNode("NamedStyle",a.namedStyles[c],b);if(a.userStyles)for(c=0,d=a.userStyles.length;c<d;++c)this.writeNode("UserStyle",a.userStyles[c],b);return b},NamedStyle:function(a){var b=this.createElementNSPlus("sld:NamedStyle");this.writeNode("Name",a,b);return b},UserStyle:function(a){var b=this.createElementNSPlus("sld:UserStyle");a.name&&this.writeNode("Name",
-a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&this.writeNode("Abstract",a.description,b);a.isDefault&&this.writeNode("IsDefault",a.isDefault,b);if(this.multipleSymbolizers&&a.rules){for(var c={0:[]},d=[0],e,f,g,h,k,l=0,m=a.rules.length;l<m;++l)if(e=a.rules[l],e.symbolizers){f={};for(var n=0,p=e.symbolizers.length;n<p;++n)g=e.symbolizers[n],h=g.zIndex,h in f||(k=e.clone(),k.symbolizers=[],f[h]=k),f[h].symbolizers.push(g.clone());for(h in f)h in c||(d.push(h),c[h]=[]),c[h].push(f[h])}else c[0].push(e.clone());
-d.sort();l=0;for(m=d.length;l<m;++l)e=c[d[l]],0<e.length&&(k=a.clone(),k.rules=c[d[l]],this.writeNode("FeatureTypeStyle",k,b))}else this.writeNode("FeatureTypeStyle",a,b);return b},IsDefault:function(a){return this.createElementNSPlus("sld:IsDefault",{value:a?"1":"0"})},FeatureTypeStyle:function(a){for(var b=this.createElementNSPlus("sld:FeatureTypeStyle"),c=0,d=a.rules.length;c<d;++c)this.writeNode("Rule",a.rules[c],b);return b},Rule:function(a){var b=this.createElementNSPlus("sld:Rule");a.name&&
-this.writeNode("Name",a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&this.writeNode("Abstract",a.description,b);a.elseFilter?this.writeNode("ElseFilter",null,b):a.filter&&this.writeNode("ogc:Filter",a.filter,b);void 0!=a.minScaleDenominator&&this.writeNode("MinScaleDenominator",a.minScaleDenominator,b);void 0!=a.maxScaleDenominator&&this.writeNode("MaxScaleDenominator",a.maxScaleDenominator,b);var c,d;if(this.multipleSymbolizers&&a.symbolizers)for(var e=0,f=a.symbolizers.length;e<
-f;++e)d=a.symbolizers[e],c=d.CLASS_NAME.split(".").pop(),this.writeNode(c+"Symbolizer",d,b);else for(var f=OpenLayers.Style.SYMBOLIZER_PREFIXES,e=0,g=f.length;e<g;++e)c=f[e],(d=a.symbolizer[c])&&this.writeNode(c+"Symbolizer",d,b);return b},ElseFilter:function(){return this.createElementNSPlus("sld:ElseFilter")},MinScaleDenominator:function(a){return this.createElementNSPlus("sld:MinScaleDenominator",{value:a})},MaxScaleDenominator:function(a){return this.createElementNSPlus("sld:MaxScaleDenominator",
-{value:a})},LineSymbolizer:function(a){var b=this.createElementNSPlus("sld:LineSymbolizer");this.writeNode("Stroke",a,b);return b},Stroke:function(a){var b=this.createElementNSPlus("sld:Stroke");void 0!=a.strokeColor&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeColor"},b);void 0!=a.strokeOpacity&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeOpacity"},b);void 0!=a.strokeWidth&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeWidth"},b);void 0!=a.strokeDashstyle&&"solid"!==
-a.strokeDashstyle&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeDashstyle"},b);void 0!=a.strokeLinecap&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeLinecap"},b);return b},CssParameter:function(a){return this.createElementNSPlus("sld:CssParameter",{attributes:{name:this.getCssProperty(a.key)},value:a.symbolizer[a.key]})},TextSymbolizer:function(a){var b=this.createElementNSPlus("sld:TextSymbolizer");null!=a.label&&this.writeNode("Label",a.label,b);null==a.fontFamily&&null==a.fontSize&&
-null==a.fontWeight&&null==a.fontStyle||this.writeNode("Font",a,b);null==a.labelAnchorPointX&&null==a.labelAnchorPointY&&null==a.labelAlign&&null==a.labelXOffset&&null==a.labelYOffset&&null==a.labelRotation&&null==a.labelPerpendicularOffset||this.writeNode("LabelPlacement",a,b);null==a.haloRadius&&null==a.haloColor&&null==a.haloOpacity||this.writeNode("Halo",a,b);null==a.fontColor&&null==a.fontOpacity||this.writeNode("Fill",{fillColor:a.fontColor,fillOpacity:a.fontOpacity},b);return b},LabelPlacement:function(a){var b=
-this.createElementNSPlus("sld:LabelPlacement");null==a.labelAnchorPointX&&null==a.labelAnchorPointY&&null==a.labelAlign&&null==a.labelXOffset&&null==a.labelYOffset&&null==a.labelRotation||null!=a.labelPerpendicularOffset||this.writeNode("PointPlacement",a,b);null!=a.labelPerpendicularOffset&&this.writeNode("LinePlacement",a,b);return b},LinePlacement:function(a){var b=this.createElementNSPlus("sld:LinePlacement");this.writeNode("PerpendicularOffset",a.labelPerpendicularOffset,b);return b},PerpendicularOffset:function(a){return this.createElementNSPlus("sld:PerpendicularOffset",
-{value:a})},PointPlacement:function(a){var b=this.createElementNSPlus("sld:PointPlacement");null==a.labelAnchorPointX&&null==a.labelAnchorPointY&&null==a.labelAlign||this.writeNode("AnchorPoint",a,b);null==a.labelXOffset&&null==a.labelYOffset||this.writeNode("Displacement",a,b);null!=a.labelRotation&&this.writeNode("Rotation",a.labelRotation,b);return b},AnchorPoint:function(a){var b=this.createElementNSPlus("sld:AnchorPoint"),c=a.labelAnchorPointX,d=a.labelAnchorPointY;null!=c&&this.writeNode("AnchorPointX",
-c,b);null!=d&&this.writeNode("AnchorPointY",d,b);if(null==c&&null==d){var e=a.labelAlign.substr(0,1);a=a.labelAlign.substr(1,1);"l"===e?c=0:"c"===e?c=0.5:"r"===e&&(c=1);"b"===a?d=0:"m"===a?d=0.5:"t"===a&&(d=1);this.writeNode("AnchorPointX",c,b);this.writeNode("AnchorPointY",d,b)}return b},AnchorPointX:function(a){return this.createElementNSPlus("sld:AnchorPointX",{value:a})},AnchorPointY:function(a){return this.createElementNSPlus("sld:AnchorPointY",{value:a})},Displacement:function(a){var b=this.createElementNSPlus("sld:Displacement");
-null!=a.labelXOffset&&this.writeNode("DisplacementX",a.labelXOffset,b);null!=a.labelYOffset&&this.writeNode("DisplacementY",a.labelYOffset,b);return b},DisplacementX:function(a){return this.createElementNSPlus("sld:DisplacementX",{value:a})},DisplacementY:function(a){return this.createElementNSPlus("sld:DisplacementY",{value:a})},Font:function(a){var b=this.createElementNSPlus("sld:Font");a.fontFamily&&this.writeNode("CssParameter",{symbolizer:a,key:"fontFamily"},b);a.fontSize&&this.writeNode("CssParameter",
-{symbolizer:a,key:"fontSize"},b);a.fontWeight&&this.writeNode("CssParameter",{symbolizer:a,key:"fontWeight"},b);a.fontStyle&&this.writeNode("CssParameter",{symbolizer:a,key:"fontStyle"},b);return b},Label:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Label",a)},Halo:function(a){var b=this.createElementNSPlus("sld:Halo");a.haloRadius&&this.writeNode("Radius",a.haloRadius,b);(a.haloColor||a.haloOpacity)&&this.writeNode("Fill",{fillColor:a.haloColor,fillOpacity:a.haloOpacity},b);
-return b},Radius:function(a){return this.createElementNSPlus("sld:Radius",{value:a})},RasterSymbolizer:function(a){var b=this.createElementNSPlus("sld:RasterSymbolizer");a.geometry&&this.writeNode("Geometry",a.geometry,b);a.opacity&&this.writeNode("Opacity",a.opacity,b);a.colorMap&&this.writeNode("ColorMap",a.colorMap,b);return b},Geometry:function(a){var b=this.createElementNSPlus("sld:Geometry");a.property&&this.writeNode("ogc:PropertyName",a,b);return b},ColorMap:function(a){for(var b=this.createElementNSPlus("sld:ColorMap"),
-c=0,d=a.length;c<d;++c)this.writeNode("ColorMapEntry",a[c],b);return b},ColorMapEntry:function(a){var b=this.createElementNSPlus("sld:ColorMapEntry");b.setAttribute("color",a.color);void 0!==a.opacity&&b.setAttribute("opacity",parseFloat(a.opacity));void 0!==a.quantity&&b.setAttribute("quantity",parseFloat(a.quantity));void 0!==a.label&&b.setAttribute("label",a.label);return b},PolygonSymbolizer:function(a){var b=this.createElementNSPlus("sld:PolygonSymbolizer");!1!==a.fill&&this.writeNode("Fill",
-a,b);!1!==a.stroke&&this.writeNode("Stroke",a,b);return b},Fill:function(a){var b=this.createElementNSPlus("sld:Fill");a.fillColor&&this.writeNode("CssParameter",{symbolizer:a,key:"fillColor"},b);null!=a.fillOpacity&&this.writeNode("CssParameter",{symbolizer:a,key:"fillOpacity"},b);return b},PointSymbolizer:function(a){var b=this.createElementNSPlus("sld:PointSymbolizer");this.writeNode("Graphic",a,b);return b},Graphic:function(a){var b=this.createElementNSPlus("sld:Graphic");void 0!=a.externalGraphic?
-this.writeNode("ExternalGraphic",a,b):this.writeNode("Mark",a,b);void 0!=a.graphicOpacity&&this.writeNode("Opacity",a.graphicOpacity,b);void 0!=a.pointRadius?this.writeNode("Size",2*a.pointRadius,b):void 0!=a.graphicWidth&&this.writeNode("Size",a.graphicWidth,b);void 0!=a.rotation&&this.writeNode("Rotation",a.rotation,b);return b},ExternalGraphic:function(a){var b=this.createElementNSPlus("sld:ExternalGraphic");this.writeNode("OnlineResource",a.externalGraphic,b);a=a.graphicFormat||this.getGraphicFormat(a.externalGraphic);
-this.writeNode("Format",a,b);return b},Mark:function(a){var b=this.createElementNSPlus("sld:Mark");a.graphicName&&this.writeNode("WellKnownName",a.graphicName,b);!1!==a.fill&&this.writeNode("Fill",a,b);!1!==a.stroke&&this.writeNode("Stroke",a,b);return b},WellKnownName:function(a){return this.createElementNSPlus("sld:WellKnownName",{value:a})},Opacity:function(a){return this.createElementNSPlus("sld:Opacity",{value:a})},Size:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Size",
-a)},Rotation:function(a){return this.createElementNSPlus("sld:Rotation",{value:a})},OnlineResource:function(a){return this.createElementNSPlus("sld:OnlineResource",{attributes:{"xlink:type":"simple","xlink:href":a}})},Format:function(a){return this.createElementNSPlus("sld:Format",{value:a})}}},OpenLayers.Format.Filter.v1_0_0.prototype.writers),CLASS_NAME:"OpenLayers.Format.SLD.v1"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{},initialize:function(a,b,c,d){var e=[];c=OpenLayers.Util.upperCaseObject(c);1.3<=parseFloat(c.VERSION)&&!c.EXCEPTIONS&&(c.EXCEPTIONS="INIMAGE");e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));
-!this.noMagic&&(this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase())&&(null!=d&&d.isBaseLayer||(this.isBaseLayer=!1),"image/jpeg"==this.params.FORMAT&&(this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png"))},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return 1.3<=parseFloat(this.params.VERSION)&&
-!!(this.yx[a]||OpenLayers.Projection.defaults[a]&&OpenLayers.Projection.defaults[a].yx)},getURL:function(a){a=this.adjustBounds(a);var b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a,b){var c=this.map.getProjectionObject(),
-c=this.projection&&this.projection.equals(c)?this.projection.getCode():c.getCode(),c="none"==c?null:c;1.3<=parseFloat(this.params.VERSION)?this.params.CRS=c:this.params.SRS=c;"boolean"==typeof this.params.TRANSPARENT&&(a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE");return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Layer.KaMap=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,DEFAULT_PARAMS:{i:"jpeg",map:""},initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS)},getURL:function(a){a=this.adjustBounds(a);var b=this.map.getResolution(),c=Math.round(1E4*this.map.getScale())/1E4,d=Math.round(a.left/b);a=-Math.round(a.top/b);return this.getFullRequestString({t:a,l:d,s:c})},calculateGridLayout:function(a,
-b,c){b=c*this.tileSize.w;c*=this.tileSize.h;return{tilelon:b,tilelat:c,startcol:Math.floor(a.left/b)-this.buffer,startrow:Math.floor(a.top/c)+this.buffer}},getTileBoundsForGridIndex:function(a,b){this.getTileOrigin();var c=this.gridLayout,d=c.tilelon,e=c.tilelat,f=(c.startcol+b)*d,c=(c.startrow-a)*e;return new OpenLayers.Bounds(f,c,f+d,c+e)},clone:function(a){null==a&&(a=new OpenLayers.Layer.KaMap(this.name,this.url,this.params,this.getOptions()));a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
-[a]);null!=this.tileSize&&(a.tileSize=this.tileSize.clone());a.grid=[];return a},getTileBounds:function(a){var b=this.getResolution(),c=b*this.tileSize.w,b=b*this.tileSize.h,d=this.getLonLatFromViewPortPx(a);a=c*Math.floor(d.lon/c);d=b*Math.floor(d.lat/b);return new OpenLayers.Bounds(a,d,a+c,d+b)},CLASS_NAME:"OpenLayers.Layer.KaMap"});OpenLayers.Format.WMC.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd",initialize:function(a){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[a])},read_sld_MinScaleDenominator:function(a,b){var c=parseFloat(this.getChildValue(b));0<c&&(a.maxScale=c)},read_sld_MaxScaleDenominator:function(a,b){a.minScale=parseFloat(this.getChildValue(b))},read_wmc_SRS:function(a,b){"srs"in
-a||(a.srs={});a.srs[this.getChildValue(b)]=!0},write_wmc_Layer:function(a){var b=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,[a]);if(a.maxScale){var c=this.createElementNS(this.namespaces.sld,"sld:MinScaleDenominator");c.appendChild(this.createTextNode(a.maxScale.toPrecision(16)));b.appendChild(c)}a.minScale&&(c=this.createElementNS(this.namespaces.sld,"sld:MaxScaleDenominator"),c.appendChild(this.createTextNode(a.minScale.toPrecision(16))),b.appendChild(c));if(a.srs)for(var d in a.srs)b.appendChild(this.createElementDefaultNS("SRS",
-d));b.appendChild(this.write_wmc_FormatList(a));b.appendChild(this.write_wmc_StyleList(a));a.dimensions&&b.appendChild(this.write_wmc_DimensionList(a));b.appendChild(this.write_wmc_LayerExtension(a));return b},CLASS_NAME:"OpenLayers.Format.WMC.v1_1_0"});OpenLayers.Format.XLS=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",stringifyOutput:!0,CLASS_NAME:"OpenLayers.Format.XLS"});OpenLayers.Format.XLS.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xls:"http://www.opengis.net/xls",gml:"http://www.opengis.net/gml",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},xy:!0,defaultPrefix:"xls",schemaLocation:null,read:function(a,b){OpenLayers.Util.applyDefaults(b,this.options);var c={};this.readChildNodes(a,c);return c},readers:{xls:{XLS:function(a,b){b.version=a.getAttribute("version");
-this.readChildNodes(a,b)},Response:function(a,b){this.readChildNodes(a,b)},GeocodeResponse:function(a,b){b.responseLists=[];this.readChildNodes(a,b)},GeocodeResponseList:function(a,b){var c={features:[],numberOfGeocodedAddresses:parseInt(a.getAttribute("numberOfGeocodedAddresses"))};b.responseLists.push(c);this.readChildNodes(a,c)},GeocodedAddress:function(a,b){var c=new OpenLayers.Feature.Vector;b.features.push(c);this.readChildNodes(a,c);c.geometry=c.components[0]},GeocodeMatchCode:function(a,b){b.attributes.matchCode=
-{accuracy:parseFloat(a.getAttribute("accuracy")),matchType:a.getAttribute("matchType")}},Address:function(a,b){var c={countryCode:a.getAttribute("countryCode"),addressee:a.getAttribute("addressee"),street:[],place:[]};b.attributes.address=c;this.readChildNodes(a,c)},freeFormAddress:function(a,b){b.freeFormAddress=this.getChildValue(a)},StreetAddress:function(a,b){this.readChildNodes(a,b)},Building:function(a,b){b.building={number:a.getAttribute("number"),subdivision:a.getAttribute("subdivision"),
-buildingName:a.getAttribute("buildingName")}},Street:function(a,b){b.street.push(this.getChildValue(a))},Place:function(a,b){b.place[a.getAttribute("type")]=this.getChildValue(a)},PostalCode:function(a,b){b.postalCode=this.getChildValue(a)}},gml:OpenLayers.Format.GML.v3.prototype.readers.gml},write:function(a){return this.writers.xls.XLS.apply(this,[a])},writers:{xls:{XLS:function(a){var b=this.createElementNSPlus("xls:XLS",{attributes:{version:this.VERSION,"xsi:schemaLocation":this.schemaLocation}});
-this.writeNode("RequestHeader",a.header,b);this.writeNode("Request",a,b);return b},RequestHeader:function(a){return this.createElementNSPlus("xls:RequestHeader")},Request:function(a){var b=this.createElementNSPlus("xls:Request",{attributes:{methodName:"GeocodeRequest",requestID:a.requestID||"",version:this.VERSION}});this.writeNode("GeocodeRequest",a.addresses,b);return b},GeocodeRequest:function(a){for(var b=this.createElementNSPlus("xls:GeocodeRequest"),c=0,d=a.length;c<d;c++)this.writeNode("Address",
-a[c],b);return b},Address:function(a){var b=this.createElementNSPlus("xls:Address",{attributes:{countryCode:a.countryCode}});a.freeFormAddress?this.writeNode("freeFormAddress",a.freeFormAddress,b):(a.street&&this.writeNode("StreetAddress",a,b),a.municipality&&this.writeNode("Municipality",a.municipality,b),a.countrySubdivision&&this.writeNode("CountrySubdivision",a.countrySubdivision,b),a.postalCode&&this.writeNode("PostalCode",a.postalCode,b));return b},freeFormAddress:function(a){return this.createElementNSPlus("freeFormAddress",
-{value:a})},StreetAddress:function(a){var b=this.createElementNSPlus("xls:StreetAddress");a.building&&this.writeNode(b,"Building",a.building);a=a.street;OpenLayers.Util.isArray(a)||(a=[a]);for(var c=0,d=a.length;c<d;c++)this.writeNode("Street",a[c],b);return b},Building:function(a){return this.createElementNSPlus("xls:Building",{attributes:{number:a.number,subdivision:a.subdivision,buildingName:a.buildingName}})},Street:function(a){return this.createElementNSPlus("xls:Street",{value:a})},Municipality:function(a){return this.createElementNSPlus("xls:Place",
-{attributes:{type:"Municipality"},value:a})},CountrySubdivision:function(a){return this.createElementNSPlus("xls:Place",{attributes:{type:"CountrySubdivision"},value:a})},PostalCode:function(a){return this.createElementNSPlus("xls:PostalCode",{value:a})}}},CLASS_NAME:"OpenLayers.Format.XLS.v1"});OpenLayers.Format.XLS.v1_1_0=OpenLayers.Class(OpenLayers.Format.XLS.v1,{VERSION:"1.1",schemaLocation:"http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd",CLASS_NAME:"OpenLayers.Format.XLS.v1_1_0"});OpenLayers.Format.XLS.v1_1=OpenLayers.Format.XLS.v1_1_0;OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15E3,translationParameters:null,symbolMetrics:null,initialize:function(a){this.supported()&&(OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments),this.translationParameters={x:0,y:0},this.symbolMetrics={})},supported:function(){return document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG",
-"1.1")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"))},inValidRange:function(a,b,c){a+=c?0:this.translationParameters.x;b+=c?0:this.translationParameters.y;return a>=-this.MAX_PIXEL&&a<=this.MAX_PIXEL&&b>=-this.MAX_PIXEL&&b<=this.MAX_PIXEL},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=-a.left/d,d=a.top/d;if(b)return this.left=e,this.top=d,this.rendererRoot.setAttributeNS(null,
-"viewBox","0 0 "+this.size.w+" "+this.size.h),this.translate(this.xOffset,0),!0;(e=this.translate(e-this.left+this.xOffset,d-this.top))||this.setExtent(a,!0);return c&&e},translate:function(a,b){if(this.inValidRange(a,b,!0)){var c="";if(a||b)c="translate("+a+","+b+")";this.root.setAttributeNS(null,"transform",c);this.translationParameters={x:a,y:b};return!0}return!1},setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w);
-this.rendererRoot.setAttributeNS(null,"height",this.size.h)},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"image":this.isComplexSymbol(b.graphicName)?"svg":"circle";break;case "OpenLayers.Geometry.Rectangle":c="rect";break;case "OpenLayers.Geometry.LineString":c="polyline";break;case "OpenLayers.Geometry.LinearRing":c="polygon";break;case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c="path"}return c},setStyle:function(a,
-b,c){b=b||a._style;c=c||a._options;var d=b.title||b.graphicTitle;if(d){a.setAttributeNS(null,"title",d);var e=a.getElementsByTagName("title");0<e.length?e[0].firstChild.textContent=d:(e=this.nodeFactory(null,"title"),e.textContent=d,a.appendChild(e))}var e=parseFloat(a.getAttributeNS(null,"r")),d=1,f;if("OpenLayers.Geometry.Point"==a._geometryClass&&e){a.style.visibility="";if(!1===b.graphic)a.style.visibility="hidden";else if(b.externalGraphic){f=this.getPosition(a);b.graphicWidth&&b.graphicHeight&&
-a.setAttributeNS(null,"preserveAspectRatio","none");var e=b.graphicWidth||b.graphicHeight,g=b.graphicHeight||b.graphicWidth,e=e?e:2*b.pointRadius,g=g?g:2*b.pointRadius,h=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*g),k=b.graphicOpacity||b.fillOpacity;a.setAttributeNS(null,"x",(f.x+(void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*e))).toFixed());a.setAttributeNS(null,"y",(f.y+h).toFixed());a.setAttributeNS(null,"width",e);a.setAttributeNS(null,"height",g);a.setAttributeNS(this.xlinkns,"xlink:href",
-b.externalGraphic);a.setAttributeNS(null,"style","opacity: "+k);a.onclick=OpenLayers.Event.preventDefault}else if(this.isComplexSymbol(b.graphicName)){var e=3*b.pointRadius,g=2*e,l=this.importSymbol(b.graphicName);f=this.getPosition(a);d=3*this.symbolMetrics[l.id][0]/g;h=a.parentNode;k=a.nextSibling;h&&h.removeChild(a);a.firstChild&&a.removeChild(a.firstChild);a.appendChild(l.firstChild.cloneNode(!0));a.setAttributeNS(null,"viewBox",l.getAttributeNS(null,"viewBox"));a.setAttributeNS(null,"width",
-g);a.setAttributeNS(null,"height",g);a.setAttributeNS(null,"x",f.x-e);a.setAttributeNS(null,"y",f.y-e);k?h.insertBefore(a,k):h&&h.appendChild(a)}else a.setAttributeNS(null,"r",b.pointRadius);e=b.rotation;void 0===e&&void 0===a._rotation||!f||(a._rotation=e,e|=0,"svg"!==a.nodeName?a.setAttributeNS(null,"transform","rotate("+e+" "+f.x+" "+f.y+")"):(f=this.symbolMetrics[l.id],a.firstChild.setAttributeNS(null,"transform","rotate("+e+" "+f[1]+" "+f[2]+")")))}c.isFilled?(a.setAttributeNS(null,"fill",b.fillColor),
-a.setAttributeNS(null,"fill-opacity",b.fillOpacity)):a.setAttributeNS(null,"fill","none");c.isStroked?(a.setAttributeNS(null,"stroke",b.strokeColor),a.setAttributeNS(null,"stroke-opacity",b.strokeOpacity),a.setAttributeNS(null,"stroke-width",b.strokeWidth*d),a.setAttributeNS(null,"stroke-linecap",b.strokeLinecap||"round"),a.setAttributeNS(null,"stroke-linejoin","round"),b.strokeDashstyle&&a.setAttributeNS(null,"stroke-dasharray",this.dashStyle(b,d))):a.setAttributeNS(null,"stroke","none");b.pointerEvents&&
-a.setAttributeNS(null,"pointer-events",b.pointerEvents);null!=b.cursor&&a.setAttributeNS(null,"cursor",b.cursor);return a},dashStyle:function(a,b){var c=a.strokeWidth*b,d=a.strokeDashstyle;switch(d){case "solid":return"none";case "dot":return[1,4*c].join();case "dash":return[4*c,4*c].join();case "dashdot":return[4*c,4*c,1,4*c].join();case "longdash":return[8*c,4*c].join();case "longdashdot":return[8*c,4*c,1,4*c].join();default:return OpenLayers.String.trim(d).replace(/\s+/g,",")}},createNode:function(a,
-b){var c=document.createElementNS(this.xmlns,a);b&&c.setAttributeNS(null,"id",b);return c},nodeTypeCompare:function(a,b){return b==a.nodeName},createRenderRoot:function(){var a=this.nodeFactory(this.container.id+"_svgRoot","svg");a.style.display="block";return a},createRoot:function(a){return this.nodeFactory(this.container.id+a,"g")},createDefs:function(){var a=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(a);return a},drawPoint:function(a,b){return this.drawCircle(a,
-b,1)},drawCircle:function(a,b,c){var d=this.getResolution(),e=(b.x-this.featureDx)/d+this.left;b=this.top-b.y/d;return this.inValidRange(e,b)?(a.setAttributeNS(null,"cx",e),a.setAttributeNS(null,"cy",b),a.setAttributeNS(null,"r",c),a):!1},drawLineString:function(a,b){var c=this.getComponentsString(b.components);return c.path?(a.setAttributeNS(null,"points",c.path),c.complete?a:null):!1},drawLinearRing:function(a,b){var c=this.getComponentsString(b.components);return c.path?(a.setAttributeNS(null,
-"points",c.path),c.complete?a:null):!1},drawPolygon:function(a,b){for(var c="",d=!0,e=!0,f,g,h=0,k=b.components.length;h<k;h++)c+=" M",f=this.getComponentsString(b.components[h].components," "),(g=f.path)?(c+=" "+g,e=f.complete&&e):d=!1;return d?(a.setAttributeNS(null,"d",c+" z"),a.setAttributeNS(null,"fill-rule","evenodd"),e?a:null):!1},drawRectangle:function(a,b){var c=this.getResolution(),d=(b.x-this.featureDx)/c+this.left,e=this.top-b.y/c;return this.inValidRange(d,e)?(a.setAttributeNS(null,"x",
-d),a.setAttributeNS(null,"y",e),a.setAttributeNS(null,"width",b.width/c),a.setAttributeNS(null,"height",b.height/c),a):!1},drawText:function(a,b,c){var d=!!b.labelOutlineWidth;if(d){var e=OpenLayers.Util.extend({},b);e.fontColor=e.labelOutlineColor;e.fontStrokeColor=e.labelOutlineColor;e.fontStrokeWidth=b.labelOutlineWidth;b.labelOutlineOpacity&&(e.fontOpacity=b.labelOutlineOpacity);delete e.labelOutlineWidth;this.drawText(a,e,c)}var f=this.getResolution(),e=(c.x-this.featureDx)/f+this.left,g=c.y/
-f-this.top,d=d?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX,f=this.nodeFactory(a+d,"text");f.setAttributeNS(null,"x",e);f.setAttributeNS(null,"y",-g);b.fontColor&&f.setAttributeNS(null,"fill",b.fontColor);b.fontStrokeColor&&f.setAttributeNS(null,"stroke",b.fontStrokeColor);b.fontStrokeWidth&&f.setAttributeNS(null,"stroke-width",b.fontStrokeWidth);b.fontOpacity&&f.setAttributeNS(null,"opacity",b.fontOpacity);b.fontFamily&&f.setAttributeNS(null,"font-family",b.fontFamily);b.fontSize&&f.setAttributeNS(null,
-"font-size",b.fontSize);b.fontWeight&&f.setAttributeNS(null,"font-weight",b.fontWeight);b.fontStyle&&f.setAttributeNS(null,"font-style",b.fontStyle);!0===b.labelSelect?(f.setAttributeNS(null,"pointer-events","visible"),f._featureId=a):f.setAttributeNS(null,"pointer-events","none");g=b.labelAlign||OpenLayers.Renderer.defaultSymbolizer.labelAlign;f.setAttributeNS(null,"text-anchor",OpenLayers.Renderer.SVG.LABEL_ALIGN[g[0]]||"middle");!0===OpenLayers.IS_GECKO&&f.setAttributeNS(null,"dominant-baseline",
-OpenLayers.Renderer.SVG.LABEL_ALIGN[g[1]]||"central");for(var h=b.label.split("\n"),k=h.length;f.childNodes.length>k;)f.removeChild(f.lastChild);for(var l=0;l<k;l++){var m=this.nodeFactory(a+d+"_tspan_"+l,"tspan");!0===b.labelSelect&&(m._featureId=a,m._geometry=c,m._geometryClass=c.CLASS_NAME);!1===OpenLayers.IS_GECKO&&m.setAttributeNS(null,"baseline-shift",OpenLayers.Renderer.SVG.LABEL_VSHIFT[g[1]]||"-35%");m.setAttribute("x",e);if(0==l){var n=OpenLayers.Renderer.SVG.LABEL_VFACTOR[g[1]];null==n&&
-(n=-0.5);m.setAttribute("dy",n*(k-1)+"em")}else m.setAttribute("dy","1em");m.textContent=""===h[l]?" ":h[l];m.parentNode||f.appendChild(m)}f.parentNode||this.textRoot.appendChild(f)},getComponentsString:function(a,b){for(var c=[],d=!0,e=a.length,f=[],g,h=0;h<e;h++)g=a[h],c.push(g),(g=this.getShortString(g))?f.push(g):(0<h&&this.getShortString(a[h-1])&&f.push(this.clipLine(a[h],a[h-1])),h<e-1&&this.getShortString(a[h+1])&&f.push(this.clipLine(a[h],a[h+1])),d=!1);return{path:f.join(b||","),complete:d}},
-clipLine:function(a,b){if(b.equals(a))return"";var c=this.getResolution(),d=this.MAX_PIXEL-this.translationParameters.x,e=this.MAX_PIXEL-this.translationParameters.y,f=(b.x-this.featureDx)/c+this.left,g=this.top-b.y/c,h=(a.x-this.featureDx)/c+this.left,c=this.top-a.y/c,k;if(h<-d||h>d)k=(c-g)/(h-f),h=0>h?-d:d,c=g+(h-f)*k;if(c<-e||c>e)k=(h-f)/(c-g),c=0>c?-e:e,h=f+(c-g)*k;return h+","+c},getShortString:function(a){var b=this.getResolution(),c=(a.x-this.featureDx)/b+this.left;a=this.top-a.y/b;return this.inValidRange(c,
-a)?c+","+a:!1},getPosition:function(a){return{x:parseFloat(a.getAttributeNS(null,"cx")),y:parseFloat(a.getAttributeNS(null,"cy"))}},importSymbol:function(a){this.defs||(this.defs=this.createDefs());var b=this.container.id+"-"+a,c=document.getElementById(b);if(null!=c)return c;var d=OpenLayers.Renderer.symbol[a];if(!d)throw Error(a+" is not a valid symbol name");a=this.nodeFactory(b,"symbol");var e=this.nodeFactory(null,"polygon");a.appendChild(e);for(var c=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,
-0,0),f=[],g,h,k=0;k<d.length;k+=2)g=d[k],h=d[k+1],c.left=Math.min(c.left,g),c.bottom=Math.min(c.bottom,h),c.right=Math.max(c.right,g),c.top=Math.max(c.top,h),f.push(g,",",h);e.setAttributeNS(null,"points",f.join(" "));d=c.getWidth();e=c.getHeight();a.setAttributeNS(null,"viewBox",[c.left-d,c.bottom-e,3*d,3*e].join(" "));this.symbolMetrics[b]=[Math.max(d,e),c.getCenterLonLat().lon,c.getCenterLonLat().lat];this.defs.appendChild(a);return a},getFeatureIdFromEvent:function(a){var b=OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this,
-arguments);b||(b=a.target,b=b.parentNode&&b!=this.rendererRoot?b.parentNode._featureId:void 0);return b},CLASS_NAME:"OpenLayers.Renderer.SVG"});OpenLayers.Renderer.SVG.LABEL_ALIGN={l:"start",r:"end",b:"bottom",t:"hanging"};OpenLayers.Renderer.SVG.LABEL_VSHIFT={t:"-70%",b:"0"};OpenLayers.Renderer.SVG.LABEL_VFACTOR={t:0,b:-1};OpenLayers.Renderer.SVG.preventDefault=function(a){OpenLayers.Event.preventDefault(a)};OpenLayers.Format.SLD.v1_0_0=OpenLayers.Class(OpenLayers.Format.SLD.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0"});OpenLayers.Format.OWSContext=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"0.3.1",getVersion:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this,arguments);"0.3.0"===c&&(c=this.defaultVersion);return c},toContext:function(a){var b={};"OpenLayers.Map"==a.CLASS_NAME&&(b.bounds=a.getExtent(),b.maxExtent=a.maxExtent,b.projection=a.projection,b.size=a.getSize(),b.layers=a.layers);return b},CLASS_NAME:"OpenLayers.Format.OWSContext"});OpenLayers.Format.OWSContext.v0_3_1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{owc:"http://www.opengis.net/ows-context",gml:"http://www.opengis.net/gml",kml:"http://www.opengis.net/kml/2.2",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},VERSION:"0.3.1",schemaLocation:"http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd",
-defaultPrefix:"owc",extractAttributes:!0,xy:!0,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},featureNS:"http://mapserver.gis.umn.edu/mapserver",featureType:"vector",geometryName:"geometry",nestingLayerLookup:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this)},setNestingPath:function(a){if(a.layersContext)for(var b=0,c=a.layersContext.length;b<c;b++){var d=
-a.layersContext[b],e=[],f=a.title||"";a.metadata&&a.metadata.nestingPath&&(e=a.metadata.nestingPath.slice());""!=f&&e.push(f);d.metadata.nestingPath=e;d.layersContext&&this.setNestingPath(d)}},decomposeNestingPath:function(a){var b=[];if(OpenLayers.Util.isArray(a)){for(a=a.slice();0<a.length;)b.push(a.slice()),a.pop();b.reverse()}return b},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,
-b);this.setNestingPath({layersContext:b.layersContext});a=[];this.processLayer(a,b);delete b.layersContext;b.layersContext=a;return b},processLayer:function(a,b){if(b.layersContext)for(var c=0,d=b.layersContext.length;c<d;c++){var e=b.layersContext[c];a.push(e);e.layersContext&&this.processLayer(a,e)}},write:function(a,b){this.nestingLayerLookup={};b=b||{};OpenLayers.Util.applyDefaults(b,a);var c=this.writeNode("OWSContext",b);this.nestingLayerLookup=null;this.setAttributeNS(c,this.namespaces.xsi,
-"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[c])},readers:{kml:{Document:function(a,b){b.features=(new OpenLayers.Format.KML({kmlns:this.namespaces.kml,extractStyles:!0})).read(a)}},owc:{OWSContext:function(a,b){this.readChildNodes(a,b)},General:function(a,b){this.readChildNodes(a,b)},ResourceList:function(a,b){this.readChildNodes(a,b)},Layer:function(a,b){var c={metadata:{},visibility:"1"!=a.getAttribute("hidden"),queryable:"1"==a.getAttribute("queryable"),
-opacity:null!=a.getAttribute("opacity")?parseFloat(a.getAttribute("opacity")):null,name:a.getAttribute("name"),categoryLayer:null==a.getAttribute("name"),formats:[],styles:[]};b.layersContext||(b.layersContext=[]);b.layersContext.push(c);this.readChildNodes(a,c)},InlineGeometry:function(a,b){b.features=[];var c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMember"),d;1<=c.length&&(d=c[0]);d&&d.firstChild&&(c=d.firstChild.nextSibling?d.firstChild.nextSibling:d.firstChild,this.setNamespace("feature",
-c.namespaceURI),this.featureType=c.localName||c.nodeName.split(":").pop(),this.readChildNodes(a,b))},Server:function(a,b){if(!b.service&&!b.version||b.service!=OpenLayers.Format.Context.serviceTypes.WMS)b.service=a.getAttribute("service"),b.version=a.getAttribute("version"),this.readChildNodes(a,b)},Name:function(a,b){b.name=this.getChildValue(a);this.readChildNodes(a,b)},Title:function(a,b){b.title=this.getChildValue(a);this.readChildNodes(a,b)},StyleList:function(a,b){this.readChildNodes(a,b.styles)},
-Style:function(a,b){var c={};b.push(c);this.readChildNodes(a,c)},LegendURL:function(a,b){var c={};b.legend=c;this.readChildNodes(a,c)},OnlineResource:function(a,b){b.url=this.getAttributeNS(a,this.namespaces.xlink,"href");this.readChildNodes(a,b)}},ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows,gml:OpenLayers.Format.GML.v2.prototype.readers.gml,sld:OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld,feature:OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{owc:{OWSContext:function(a){var b=
-this.createElementNSPlus("OWSContext",{attributes:{version:this.VERSION,id:a.id||OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_")}});this.writeNode("General",a,b);this.writeNode("ResourceList",a,b);return b},General:function(a){var b=this.createElementNSPlus("General");this.writeNode("ows:BoundingBox",a,b);this.writeNode("ows:Title",a.title||"OpenLayers OWSContext",b);return b},ResourceList:function(a){for(var b=this.createElementNSPlus("ResourceList"),c=0,d=a.layers.length;c<d;c++){var e=
-a.layers[c],f=this.decomposeNestingPath(e.metadata.nestingPath);this.writeNode("_Layer",{layer:e,subPaths:f},b)}return b},Server:function(a){var b=this.createElementNSPlus("Server",{attributes:{version:a.version,service:a.service}});this.writeNode("OnlineResource",a,b);return b},OnlineResource:function(a){return this.createElementNSPlus("OnlineResource",{attributes:{"xlink:href":a.url}})},InlineGeometry:function(a){var b=this.createElementNSPlus("InlineGeometry"),c=a.getDataExtent();null!==c&&this.writeNode("gml:boundedBy",
-c,b);for(var c=0,d=a.features.length;c<d;c++)this.writeNode("gml:featureMember",a.features[c],b);return b},StyleList:function(a){for(var b=this.createElementNSPlus("StyleList"),c=0,d=a.length;c<d;c++)this.writeNode("Style",a[c],b);return b},Style:function(a){var b=this.createElementNSPlus("Style");this.writeNode("Name",a,b);this.writeNode("Title",a,b);a.legend&&this.writeNode("LegendURL",a,b);return b},Name:function(a){return this.createElementNSPlus("Name",{value:a.name})},Title:function(a){return this.createElementNSPlus("Title",
-{value:a.title})},LegendURL:function(a){var b=this.createElementNSPlus("LegendURL");this.writeNode("OnlineResource",a.legend,b);return b},_WMS:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:a.params.LAYERS,queryable:a.queryable?"1":"0",hidden:a.visibility?"0":"1",opacity:a.hasOwnProperty("opacity")?a.opacity:null}});this.writeNode("ows:Title",a.name,b);this.writeNode("ows:OutputFormat",a.params.FORMAT,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WMS,
-version:a.params.VERSION,url:a.url},b);a.metadata.styles&&0<a.metadata.styles.length&&this.writeNode("StyleList",a.metadata.styles,b);return b},_Layer:function(a){var b,c,d;b=a.layer;c=a.subPaths;d=null;0<c.length?(b=c[0].join("/"),c=b.lastIndexOf("/"),d=this.nestingLayerLookup[b],c=0<c?b.substring(c+1,b.length):b,d||(d=this.createElementNSPlus("Layer"),this.writeNode("ows:Title",c,d),this.nestingLayerLookup[b]=d),a.subPaths.shift(),this.writeNode("_Layer",a,d)):(b instanceof OpenLayers.Layer.WMS?
-d=this.writeNode("_WMS",b):b instanceof OpenLayers.Layer.Vector&&(b.protocol instanceof OpenLayers.Protocol.WFS.v1?d=this.writeNode("_WFS",b):b.protocol instanceof OpenLayers.Protocol.HTTP?b.protocol.format instanceof OpenLayers.Format.GML?(b.protocol.format.version="2.1.2",d=this.writeNode("_GML",b)):b.protocol.format instanceof OpenLayers.Format.KML&&(b.protocol.format.version="2.2",d=this.writeNode("_KML",b)):(this.setNamespace("feature",this.featureNS),d=this.writeNode("_InlineGeometry",b))),
-b.options.maxScale&&this.writeNode("sld:MinScaleDenominator",b.options.maxScale,d),b.options.minScale&&this.writeNode("sld:MaxScaleDenominator",b.options.minScale,d),this.nestingLayerLookup[b.name]=d);return d},_WFS:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:a.protocol.featurePrefix+":"+a.protocol.featureType,hidden:a.visibility?"0":"1"}});this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WFS,version:a.protocol.version,
-url:a.protocol.url},b);return b},_InlineGeometry:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:this.featureType,hidden:a.visibility?"0":"1"}});this.writeNode("ows:Title",a.name,b);this.writeNode("InlineGeometry",a,b);return b},_GML:function(a){var b=this.createElementNSPlus("Layer");this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.GML,url:a.protocol.url,version:a.protocol.format.version},b);return b},_KML:function(a){var b=
-this.createElementNSPlus("Layer");this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.KML,version:a.protocol.format.version,url:a.protocol.url},b);return b}},gml:OpenLayers.Util.applyDefaults({boundedBy:function(a){var b=this.createElementNSPlus("gml:boundedBy");this.writeNode("gml:Box",a,b);return b}},OpenLayers.Format.GML.v2.prototype.writers.gml),ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows,sld:OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld,
-feature:OpenLayers.Format.GML.v2.prototype.writers.feature},CLASS_NAME:"OpenLayers.Format.OWSContext.v0_3_1"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:!1,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:!1,fixPadding:function(){"number"==typeof this.padding&&(this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding))},panMapIfOutOfView:!1,
-keepInMap:!1,closeOnMove:!1,map:null,initialize:function(a,b,c,d,e,f){null==a&&(a=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"));this.id=a;this.lonlat=b;this.contentSize=null!=c?c:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);null!=d&&(this.contentHTML=d);this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;
-this.groupDiv=OpenLayers.Util.createDiv(this.id+"_GroupDiv",null,null,null,"relative",null,"hidden");a=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(a,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);e&&this.addCloseBox(f);this.registerEvents()},destroy:function(){this.border=this.opacity=this.backgroundColor=this.contentHTML=this.size=this.lonlat=this.id=
-null;this.closeOnMove&&this.map&&this.map.events.unregister("movestart",this,this.hide);this.events.destroy();this.events=null;this.closeDiv&&(OpenLayers.Event.stopObservingElement(this.closeDiv),this.groupDiv.removeChild(this.closeDiv));this.closeDiv=null;this.div.removeChild(this.groupDiv);this.groupDiv=null;null!=this.map&&this.map.removePopup(this);this.panMapIfOutOfView=this.padding=this.maxSize=this.minSize=this.autoSize=this.div=this.map=null},draw:function(a){null==a&&null!=this.lonlat&&null!=
-this.map&&(a=this.map.getLayerPxFromLonLat(this.lonlat));this.closeOnMove&&this.map.events.register("movestart",this,this.hide);this.disableFirefoxOverflowHack||"firefox"!=OpenLayers.BROWSER_NAME||(this.map.events.register("movestart",this,function(){var a=document.defaultView.getComputedStyle(this.contentDiv,null).getPropertyValue("overflow");"hidden"!=a&&(this.contentDiv._oldOverflow=a,this.contentDiv.style.overflow="hidden")}),this.map.events.register("moveend",this,function(){var a=this.contentDiv._oldOverflow;
-a&&(this.contentDiv.style.overflow=a,this.contentDiv._oldOverflow=null)}));this.moveTo(a);this.autoSize||this.size||this.setSize(this.contentSize);this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();this.panMapIfOutOfView&&this.panIntoView();return this.div},updatePosition:function(){if(this.lonlat&&this.map){var a=this.map.getLayerPxFromLonLat(this.lonlat);a&&this.moveTo(a)}},moveTo:function(a){null!=a&&null!=this.div&&(this.div.style.left=a.x+"px",this.div.style.top=
-a.y+"px")},visible:function(){return OpenLayers.Element.visible(this.div)},toggle:function(){this.visible()?this.hide():this.show()},show:function(){this.div.style.display="";this.panMapIfOutOfView&&this.panIntoView()},hide:function(){this.div.style.display="none"},setSize:function(a){this.size=a.clone();var b=this.getContentDivPadding(),c=b.left+b.right,d=b.top+b.bottom;this.fixPadding();c+=this.padding.left+this.padding.right;d+=this.padding.top+this.padding.bottom;if(this.closeDiv)var e=parseInt(this.closeDiv.style.width),
-c=c+(e+b.right);this.size.w+=c;this.size.h+=d;"msie"==OpenLayers.BROWSER_NAME&&(this.contentSize.w+=b.left+b.right,this.contentSize.h+=b.bottom+b.top);null!=this.div&&(this.div.style.width=this.size.w+"px",this.div.style.height=this.size.h+"px");null!=this.contentDiv&&(this.contentDiv.style.width=a.w+"px",this.contentDiv.style.height=a.h+"px")},updateSize:function(){var a="<div class='"+this.contentDisplayClass+"'>"+this.contentDiv.innerHTML+"</div>",b=this.map?this.map.div:document.body,c=OpenLayers.Util.getRenderedDimensions(a,
-null,{displayClass:this.displayClass,containerElement:b}),d=this.getSafeContentSize(c),e=null;d.equals(c)?e=c:(c={w:d.w<c.w?d.w:null,h:d.h<c.h?d.h:null},c.w&&c.h?e=d:(a=OpenLayers.Util.getRenderedDimensions(a,c,{displayClass:this.contentDisplayClass,containerElement:b}),"hidden"!=OpenLayers.Element.getStyle(this.contentDiv,"overflow")&&a.equals(d)&&(d=OpenLayers.Util.getScrollbarWidth(),c.w?a.h+=d:a.w+=d),e=this.getSafeContentSize(a)));this.setSize(e)},setBackgroundColor:function(a){void 0!=a&&(this.backgroundColor=
-a);null!=this.div&&(this.div.style.backgroundColor=this.backgroundColor)},setOpacity:function(a){void 0!=a&&(this.opacity=a);null!=this.div&&(this.div.style.opacity=this.opacity,this.div.style.filter="alpha(opacity="+100*this.opacity+")")},setBorder:function(a){void 0!=a&&(this.border=a);null!=this.div&&(this.div.style.border=this.border)},setContentHTML:function(a){null!=a&&(this.contentHTML=a);null!=this.contentDiv&&(null!=this.contentHTML&&this.contentHTML!=this.contentDiv.innerHTML)&&(this.contentDiv.innerHTML=
-this.contentHTML,this.autoSize&&(this.registerImageListeners(),this.updateSize()))},registerImageListeners:function(){for(var a=function(){null!==this.popup.id&&(this.popup.updateSize(),this.popup.visible()&&this.popup.panMapIfOutOfView&&this.popup.panIntoView(),OpenLayers.Event.stopObserving(this.img,"load",this.img._onImgLoad))},b=this.contentDiv.getElementsByTagName("img"),c=0,d=b.length;c<d;c++){var e=b[c];if(0==e.width||0==e.height)e._onImgLoad=OpenLayers.Function.bind(a,{popup:this,img:e}),
-OpenLayers.Event.observe(e,"load",e._onImgLoad)}},getSafeContentSize:function(a){a=a.clone();var b=this.getContentDivPadding(),c=b.left+b.right,d=b.top+b.bottom;this.fixPadding();c+=this.padding.left+this.padding.right;d+=this.padding.top+this.padding.bottom;if(this.closeDiv)var e=parseInt(this.closeDiv.style.width),c=c+(e+b.right);this.minSize&&(a.w=Math.max(a.w,this.minSize.w-c),a.h=Math.max(a.h,this.minSize.h-d));this.maxSize&&(a.w=Math.min(a.w,this.maxSize.w-c),a.h=Math.min(a.h,this.maxSize.h-
-d));if(this.map&&this.map.size){e=b=0;if(this.keepInMap&&!this.panMapIfOutOfView)switch(e=this.map.getPixelFromLonLat(this.lonlat),this.relativePosition){case "tr":b=e.x;e=this.map.size.h-e.y;break;case "tl":b=this.map.size.w-e.x;e=this.map.size.h-e.y;break;case "bl":b=this.map.size.w-e.x;e=e.y;break;case "br":b=e.x;e=e.y;break;default:b=e.x,e=this.map.size.h-e.y}d=this.map.size.h-this.map.paddingForPopups.top-this.map.paddingForPopups.bottom-d-e;a.w=Math.min(a.w,this.map.size.w-this.map.paddingForPopups.left-
-this.map.paddingForPopups.right-c-b);a.h=Math.min(a.h,d)}return a},getContentDivPadding:function(){var a=this._contentDivPadding;a||(null==this.div.parentNode&&(this.div.style.display="none",document.body.appendChild(this.div)),this._contentDivPadding=a=new OpenLayers.Bounds(OpenLayers.Element.getStyle(this.contentDiv,"padding-left"),OpenLayers.Element.getStyle(this.contentDiv,"padding-bottom"),OpenLayers.Element.getStyle(this.contentDiv,"padding-right"),OpenLayers.Element.getStyle(this.contentDiv,
-"padding-top")),this.div.parentNode==document.body&&(document.body.removeChild(this.div),this.div.style.display=""));return a},addCloseBox:function(a){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,{w:17,h:17});this.closeDiv.className="olPopupCloseBox";var b=this.getContentDivPadding();this.closeDiv.style.right=b.right+"px";this.closeDiv.style.top=b.top+"px";this.groupDiv.appendChild(this.closeDiv);a=a||function(a){this.hide();OpenLayers.Event.stop(a)};OpenLayers.Event.observe(this.closeDiv,
-"touchend",OpenLayers.Function.bindAsEventListener(a,this));OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(a,this))},panIntoView:function(){var a=this.map.getSize(),b=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top))),c=b.clone();b.x<this.map.paddingForPopups.left?c.x=this.map.paddingForPopups.left:b.x+this.size.w>a.w-this.map.paddingForPopups.right&&(c.x=a.w-this.map.paddingForPopups.right-this.size.w);
-b.y<this.map.paddingForPopups.top?c.y=this.map.paddingForPopups.top:b.y+this.size.h>a.h-this.map.paddingForPopups.bottom&&(c.y=a.h-this.map.paddingForPopups.bottom-this.size.h);this.map.pan(b.x-c.x,b.y-c.y)},registerEvents:function(){this.events=new OpenLayers.Events(this,this.div,null,!0);this.events.on({mousedown:this.onmousedown,mousemove:this.onmousemove,mouseup:this.onmouseup,click:this.onclick,mouseout:this.onmouseout,dblclick:this.ondblclick,touchstart:function(a){OpenLayers.Event.stop(a,!0)},
-scope:this})},onmousedown:function(a){this.mousedown=!0;OpenLayers.Event.stop(a,!0)},onmousemove:function(a){this.mousedown&&OpenLayers.Event.stop(a,!0)},onmouseup:function(a){this.mousedown&&(this.mousedown=!1,OpenLayers.Event.stop(a,!0))},onclick:function(a){OpenLayers.Event.stop(a,!0)},onmouseout:function(a){this.mousedown=!1},ondblclick:function(a){OpenLayers.Event.stop(a,!0)},CLASS_NAME:"OpenLayers.Popup"});OpenLayers.Popup.WIDTH=200;OpenLayers.Popup.HEIGHT=200;OpenLayers.Popup.COLOR="white";
-OpenLayers.Popup.OPACITY=1;OpenLayers.Popup.BORDER="0px";OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,geodesic:!1,draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.eTop||(this.eTop=document.createElement("div"),this.eTop.className=this.displayClass+"Top",this.div.appendChild(this.eTop),this.eTop.style.visibility=""==this.topOutUnits||""==this.topInUnits?"hidden":"visible",this.eBottom=document.createElement("div"),
-this.eBottom.className=this.displayClass+"Bottom",this.div.appendChild(this.eBottom),this.eBottom.style.visibility=""==this.bottomOutUnits||""==this.bottomInUnits?"hidden":"visible");this.map.events.register("moveend",this,this.update);this.update();return this.div},getBarLen:function(a){var b=parseInt(Math.log(a)/Math.log(10)),b=Math.pow(10,b);a=parseInt(a/b);return(5<a?5:2<a?2:1)*b},update:function(){var a=this.map.getResolution();if(a){var b=this.map.getUnits(),c=OpenLayers.INCHES_PER_UNIT,d=this.maxWidth*
-a*c[b],e=1;!0===this.geodesic&&(e=(this.map.getGeodesicPixelSize().w||1E-6)*this.maxWidth/(d/c.km),d*=e);var f,g;1E5<d?(f=this.topOutUnits,g=this.bottomOutUnits):(f=this.topInUnits,g=this.bottomInUnits);var h=d/c[f],k=d/c[g],d=this.getBarLen(h),l=this.getBarLen(k),h=d/c[b]*c[f],k=l/c[b]*c[g],b=h/a/e,a=k/a/e;"visible"==this.eBottom.style.visibility&&(this.eBottom.style.width=Math.round(a)+"px",this.eBottom.innerHTML=l+" "+g);"visible"==this.eTop.style.visibility&&(this.eTop.style.width=Math.round(b)+
-"px",this.eTop.innerHTML=d+" "+f)}},CLASS_NAME:"OpenLayers.Control.ScaleLine"});OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(a,b,c,d){this.url=a;this.size=b||{w:20,h:20};this.offset=c||{x:-(this.size.w/2),y:-(this.size.h/2)};this.calculateOffset=d;a=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(a)},destroy:function(){this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null},clone:function(){return new OpenLayers.Icon(this.url,
-this.size,this.offset,this.calculateOffset)},setSize:function(a){null!=a&&(this.size=a);this.draw()},setUrl:function(a){null!=a&&(this.url=a);this.draw()},draw:function(a){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(a);return this.imageDiv},erase:function(){null!=this.imageDiv&&null!=this.imageDiv.parentNode&&OpenLayers.Element.remove(this.imageDiv)},setOpacity:function(a){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,
-null,null,null,a)},moveTo:function(a){null!=a&&(this.px=a);null!=this.imageDiv&&(null==this.px?this.display(!1):(this.calculateOffset&&(this.offset=this.calculateOffset(this.size)),OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x:this.px.x+this.offset.x,y:this.px.y+this.offset.y})))},display:function(a){this.imageDiv.style.display=a?"":"none"},isDrawn:function(){return this.imageDiv&&this.imageDiv.parentNode&&11!=this.imageDiv.parentNode.nodeType},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(a,b){this.lonlat=a;var c=b?b:OpenLayers.Marker.defaultIcon();null==this.icon?this.icon=c:(this.icon.url=c.url,this.icon.size=c.size,this.icon.offset=c.offset,this.icon.calculateOffset=c.calculateOffset);this.events=new OpenLayers.Events(this,this.icon.imageDiv)},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;null!=this.icon&&(this.icon.destroy(),this.icon=null)},
-draw:function(a){return this.icon.draw(a)},erase:function(){null!=this.icon&&this.icon.erase()},moveTo:function(a){null!=a&&null!=this.icon&&this.icon.moveTo(a);this.lonlat=this.map.getLonLatFromLayerPx(a)},isDrawn:function(){return this.icon&&this.icon.isDrawn()},onScreen:function(){var a=!1;this.map&&(a=this.map.getExtent().containsLonLat(this.lonlat));return a},inflate:function(a){this.icon&&this.icon.setSize({w:this.icon.size.w*a,h:this.icon.size.h*a})},setOpacity:function(a){this.icon.setOpacity(a)},
-setUrl:function(a){this.icon.setUrl(a)},display:function(a){this.icon.display(a)},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25})};OpenLayers.Layer.TileCache=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,format:"image/png",serverResolutions:null,initialize:function(a,b,c,d){this.layername=c;OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,{},d]);this.extension=this.format.split("/")[1].toLowerCase();this.extension="jpg"==this.extension?"jpeg":this.extension},clone:function(a){null==a&&(a=new OpenLayers.Layer.TileCache(this.name,this.url,this.layername,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
-[a])},getURL:function(a){var b=this.getServerResolution(),c=this.maxExtent,d=this.tileSize,e=Math.round((a.left-c.left)/(b*d.w));a=Math.round((a.bottom-c.bottom)/(b*d.h));b=null!=this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,b):this.map.getZoom();e=[this.layername,OpenLayers.Number.zeroPad(b,2),OpenLayers.Number.zeroPad(parseInt(e/1E6),3),OpenLayers.Number.zeroPad(parseInt(e/1E3)%1E3,3),OpenLayers.Number.zeroPad(parseInt(e)%1E3,3),OpenLayers.Number.zeroPad(parseInt(a/1E6),
-3),OpenLayers.Number.zeroPad(parseInt(a/1E3)%1E3,3),OpenLayers.Number.zeroPad(parseInt(a)%1E3,3)+"."+this.extension].join("/");b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(e,b));b="/"==b.charAt(b.length-1)?b:b+"/";return b+e},CLASS_NAME:"OpenLayers.Layer.TileCache"});OpenLayers.Strategy.Paging=OpenLayers.Class(OpenLayers.Strategy,{features:null,length:10,num:null,paging:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a)this.layer.events.on({beforefeaturesadded:this.cacheFeatures,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.clearCache(),this.layer.events.un({beforefeaturesadded:this.cacheFeatures,scope:this}));return a},cacheFeatures:function(a){this.paging||(this.clearCache(),
-this.features=a.features,this.pageNext(a))},clearCache:function(){if(this.features)for(var a=0;a<this.features.length;++a)this.features[a].destroy();this.num=this.features=null},pageCount:function(){return Math.ceil((this.features?this.features.length:0)/this.length)},pageNum:function(){return this.num},pageLength:function(a){a&&0<a&&(this.length=a);return this.length},pageNext:function(a){var b=!1;this.features&&(null===this.num&&(this.num=-1),b=this.page((this.num+1)*this.length,a));return b},pagePrevious:function(){var a=
-!1;this.features&&(null===this.num&&(this.num=this.pageCount()),a=this.page((this.num-1)*this.length));return a},page:function(a,b){var c=!1;if(this.features&&0<=a&&a<this.features.length){var d=Math.floor(a/this.length);d!=this.num&&(this.paging=!0,c=this.features.slice(a,a+this.length),this.layer.removeFeatures(this.layer.features),this.num=d,b&&b.features?b.features=c:this.layer.addFeatures(c),this.paging=!1,c=!0)}return c},CLASS_NAME:"OpenLayers.Strategy.Paging"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(a,b){},onDrag:function(a,b){},onComplete:function(a,b){},onEnter:function(a){},onLeave:function(a){},documentDrag:!1,layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,
-up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks),{documentDrag:this.documentDrag}),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({click:this.clickFeature,clickout:this.clickoutFeature,over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})}},clickFeature:function(a){this.handlers.feature.touch&&(!this.over&&this.overFeature(a))&&(this.handlers.drag.dragstart(this.handlers.feature.evt),this.handlers.drag.stopDown=
-!1)},clickoutFeature:function(a){this.handlers.feature.touch&&this.over&&(this.outFeature(a),this.handlers.drag.stopDown=!0)},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){return this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=!1;this.lastPixel=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,
-this.displayClass+"Over");return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},overFeature:function(a){var b=!1;this.handlers.drag.dragging?this.over=this.feature.id==a.id?!0:!1:(this.feature=a,this.handlers.drag.activate(),this.over=b=!0,OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onEnter(a));return b},downFeature:function(a){this.lastPixel=a;this.onStart(this.feature,a)},moveFeature:function(a){var b=this.map.getResolution();this.feature.geometry.move(b*
-(a.x-this.lastPixel.x),b*(this.lastPixel.y-a.y));this.layer.drawFeature(this.feature);this.lastPixel=a;this.onDrag(this.feature,a)},upFeature:function(a){this.over||this.handlers.drag.deactivate()},doneDragging:function(a){this.onComplete(this.feature,a)},outFeature:function(a){this.handlers.drag.dragging?this.feature.id==a.id&&(this.over=!1):(this.over=!1,this.handlers.drag.deactivate(),OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onLeave(a),this.feature=null)},
-cancel:function(){this.handlers.drag.deactivate();this.over=!1},setMap:function(a){this.handlers.drag.setMap(a);this.handlers.feature.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Control.TransformFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,layer:null,preserveAspectRatio:!1,rotate:!0,feature:null,renderIntent:"temporary",rotationHandleSymbolizer:null,box:null,center:null,scale:1,ratio:1,rotation:0,handles:null,rotationHandles:null,dragControl:null,irregular:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.rotationHandleSymbolizer||(this.rotationHandleSymbolizer={stroke:!1,pointRadius:10,fillOpacity:0,
-cursor:"pointer"});this.createBox();this.createControl()},activate:function(){var a=!1;OpenLayers.Control.prototype.activate.apply(this,arguments)&&(this.dragControl.activate(),this.layer.addFeatures([this.box]),this.rotate&&this.layer.addFeatures(this.rotationHandles),this.layer.addFeatures(this.handles),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Control.prototype.deactivate.apply(this,arguments)&&(this.layer.removeFeatures(this.handles),this.rotate&&this.layer.removeFeatures(this.rotationHandles),
-this.layer.removeFeatures([this.box]),this.dragControl.deactivate(),a=!0);return a},setMap:function(a){this.dragControl.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setFeature:function(a,b){b=OpenLayers.Util.applyDefaults(b,{rotation:0,scale:1,ratio:1});var c=this.rotation,d=this.center;OpenLayers.Util.extend(this,b);if(!1!==this.events.triggerEvent("beforesetfeature",{feature:a})){this.feature=a;this.activate();this._setfeature=!0;var e=this.feature.geometry.getBounds();this.box.move(e.getCenterLonLat());
-this.box.geometry.rotate(-c,d);this._angle=0;this.rotation?(c=a.geometry.clone(),c.rotate(-this.rotation,this.center),c=new OpenLayers.Feature.Vector(c.getBounds().toGeometry()),c.geometry.rotate(this.rotation,this.center),this.box.geometry.rotate(this.rotation,this.center),this.box.move(c.geometry.getBounds().getCenterLonLat()),c=c.geometry.components[0].components[0].getBounds().getCenterLonLat()):c=new OpenLayers.LonLat(e.left,e.bottom);this.handles[0].move(c);delete this._setfeature;this.events.triggerEvent("setfeature",
-{feature:a})}},unsetFeature:function(){this.active?this.deactivate():(this.feature=null,this.rotation=0,this.ratio=this.scale=1)},createBox:function(){var a=this;this.center=new OpenLayers.Geometry.Point(0,0);this.box=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(-1,-1),new OpenLayers.Geometry.Point(0,-1),new OpenLayers.Geometry.Point(1,-1),new OpenLayers.Geometry.Point(1,0),new OpenLayers.Geometry.Point(1,1),new OpenLayers.Geometry.Point(0,1),new OpenLayers.Geometry.Point(-1,
-1),new OpenLayers.Geometry.Point(-1,0),new OpenLayers.Geometry.Point(-1,-1)]),null,"string"==typeof this.renderIntent?null:this.renderIntent);this.box.geometry.move=function(b,c){a._moving=!0;OpenLayers.Geometry.LineString.prototype.move.apply(this,arguments);a.center.move(b,c);delete a._moving};for(var b=function(a,b){OpenLayers.Geometry.Point.prototype.move.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.move(a,b);this._handle.geometry.move(a,b)},c=function(a,b,c){OpenLayers.Geometry.Point.prototype.resize.apply(this,
-arguments);this._rotationHandle&&this._rotationHandle.geometry.resize(a,b,c);this._handle.geometry.resize(a,b,c)},d=function(a,b){OpenLayers.Geometry.Point.prototype.rotate.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.rotate(a,b);this._handle.geometry.rotate(a,b)},e=function(b,c){var d=this.x,e=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,b,c);if(!a._moving){var f=a.dragControl.handlers.drag.evt,g=!(!a._setfeature&&a.preserveAspectRatio)&&!(f&&f.shiftKey),
-h=new OpenLayers.Geometry.Point(d,e),f=a.center;this.rotate(-a.rotation,f);h.rotate(-a.rotation,f);var k=this.x-f.x,l=this.y-f.y,m=k-(this.x-h.x),n=l-(this.y-h.y);a.irregular&&!a._setfeature&&(k-=(this.x-h.x)/2,l-=(this.y-h.y)/2);this.x=d;this.y=e;h=1;g?(l=1E-5>Math.abs(n)?1:l/n,h=(1E-5>Math.abs(m)?1:k/m)/l):(m=Math.sqrt(m*m+n*n),l=Math.sqrt(k*k+l*l)/m);a._moving=!0;a.box.geometry.rotate(-a.rotation,f);delete a._moving;a.box.geometry.resize(l,f,h);a.box.geometry.rotate(a.rotation,f);a.transformFeature({scale:l,
-ratio:h});a.irregular&&!a._setfeature&&(k=f.clone(),k.x+=1E-5>Math.abs(d-f.x)?0:this.x-d,k.y+=1E-5>Math.abs(e-f.y)?0:this.y-e,a.box.geometry.move(this.x-d,this.y-e),a.transformFeature({center:k}))}},f=function(b,c){var d=this.x,e=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,b,c);if(!a._moving){var f=a.dragControl.handlers.drag.evt,f=f&&f.shiftKey?45:1,g=a.center,h=this.x-g.x,k=this.y-g.y;this.x=d;this.y=e;d=Math.atan2(k-c,h-b);d=Math.atan2(k,h)-d;d*=180/Math.PI;a._angle=(a._angle+d)%
-360;d=a.rotation%f;if(Math.abs(a._angle)>=f||0!==d)d=Math.round(a._angle/f)*f-d,a._angle=0,a.box.geometry.rotate(d,g),a.transformFeature({rotation:d})}},g=Array(8),h=Array(4),k,l,m,n="sw s se e ne n nw w".split(" "),p=0;8>p;++p)k=this.box.geometry.components[p],l=new OpenLayers.Feature.Vector(k.clone(),{role:n[p]+"-resize"},"string"==typeof this.renderIntent?null:this.renderIntent),0==p%2&&(m=new OpenLayers.Feature.Vector(k.clone(),{role:n[p]+"-rotate"},"string"==typeof this.rotationHandleSymbolizer?
-null:this.rotationHandleSymbolizer),m.geometry.move=f,k._rotationHandle=m,h[p/2]=m),k.move=b,k.resize=c,k.rotate=d,l.geometry.move=e,k._handle=l,g[p]=l;this.rotationHandles=h;this.handles=g},createControl:function(){var a=this;this.dragControl=new OpenLayers.Control.DragFeature(this.layer,{documentDrag:!0,moveFeature:function(b){this.feature===a.feature&&(this.feature=a.box);OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,arguments)},onDrag:function(b,c){b===a.box&&a.transformFeature({center:a.center})},
-onStart:function(b,c){var d=!a.geometryTypes||-1!==OpenLayers.Util.indexOf(a.geometryTypes,b.geometry.CLASS_NAME),e=OpenLayers.Util.indexOf(a.handles,b),e=e+OpenLayers.Util.indexOf(a.rotationHandles,b);b!==a.feature&&(b!==a.box&&-2==e&&d)&&a.setFeature(b)},onComplete:function(b,c){a.events.triggerEvent("transformcomplete",{feature:a.feature})}})},drawHandles:function(){for(var a=this.layer,b=0;8>b;++b)this.rotate&&0===b%2&&a.drawFeature(this.rotationHandles[b/2],this.rotationHandleSymbolizer),a.drawFeature(this.handles[b],
-this.renderIntent)},transformFeature:function(a){if(!this._setfeature){this.scale*=a.scale||1;this.ratio*=a.ratio||1;var b=this.rotation;this.rotation=(this.rotation+(a.rotation||0))%360;if(!1!==this.events.triggerEvent("beforetransform",a)){var c=this.feature,d=c.geometry,e=this.center;d.rotate(-b,e);a.scale||a.ratio?d.resize(a.scale,e,a.ratio):a.center&&c.move(a.center.getBounds().getCenterLonLat());d.rotate(this.rotation,e);this.layer.drawFeature(c);c.toState(OpenLayers.State.UPDATE);this.events.triggerEvent("transform",
-a)}}this.layer.drawFeature(this.box,this.renderIntent);this.drawHandles()},destroy:function(){for(var a,b=0;8>b;++b)a=this.box.geometry.components[b],a._handle.destroy(),a._handle=null,a._rotationHandle&&a._rotationHandle.destroy(),a._rotationHandle=null;this.rotationHandles=this.rotationHandleSymbolizer=this.handles=this.feature=this.center=null;this.box.destroy();this.layer=this.box=null;this.dragControl.destroy();this.dragControl=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},
-CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(a,b,c){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);this.dragHandler&&(this.dragHandler.destroy(),this.dragHandler=
-null)},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(a){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(a){var b=this.dragHandler.start.x,
-c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.x<b?b-d-f.left:b-f.left)+"px";this.zoomBox.style.top=(a.y<c?c-e-f.top:c-f.top)+"px"},endBox:function(a){var b;if(5<Math.abs(this.dragHandler.start.x-a.x)||5<Math.abs(this.dragHandler.start.y-a.y)){var c=this.dragHandler.start;b=Math.min(c.y,a.y);var d=Math.max(c.y,a.y),e=Math.min(c.x,a.x);a=Math.max(c.x,
-a.x);b=new OpenLayers.Bounds(e,d,a,b)}else b=this.dragHandler.start.clone();this.removeBox();this.callback("done",[b])},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox")},activate:function(){return OpenLayers.Handler.prototype.activate.apply(this,arguments)?(this.dragHandler.activate(),!0):!1},deactivate:function(){return OpenLayers.Handler.prototype.deactivate.apply(this,arguments)?
-(this.dragHandler.deactivate()&&this.zoomBox&&this.removeBox(),!0):!1},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=3==a.clientWidth;document.body.removeChild(a);var a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width")),c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox,
-"border-top-width")),e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:!1===b?a+c:0,height:!1===b?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:!1,keyMask:null,alwaysZoom:!1,zoomOnClick:!0,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b,c=a.getCenterPixel();if(this.out){b=Math.min(this.map.size.h/(a.bottom-a.top),this.map.size.w/(a.right-a.left));var d=this.map.getExtent(),e=this.map.getLonLatFromPixel(c),f=e.lon-d.getWidth()/
-2*b;a=e.lon+d.getWidth()/2*b;var g=e.lat-d.getHeight()/2*b;b=e.lat+d.getHeight()/2*b;b=new OpenLayers.Bounds(f,g,a,b)}else f=this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),a=this.map.getLonLatFromPixel({x:a.right,y:a.top}),b=new OpenLayers.Bounds(f.lon,f.lat,a.lon,a.lat);f=this.map.getZoom();g=this.map.getSize();a=g.w/2;g=g.h/2;b=this.map.getZoomForExtent(b);d=this.map.getResolution();e=this.map.getResolutionForZoom(b);d==e?this.map.setCenter(this.map.getLonLatFromPixel(c)):this.map.zoomTo(b,
-{x:(d*c.x-e*a)/(d-e),y:(d*c.y-e*g)/(d-e)});f==this.map.getZoom()&&!0==this.alwaysZoom&&this.map.zoomTo(f+(this.out?-1:1))}else this.zoomOnClick&&(this.out?this.map.zoomTo(this.map.getZoom()-1,a):this.map.zoomTo(this.map.getZoom()+1,a))},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:!1,interval:0,documentDrag:!1,kinetic:null,enableKinetic:!0,kineticInterval:10,draw:function(){if(this.enableKinetic&&OpenLayers.Kinetic){var a={interval:this.kineticInterval};"object"===typeof this.enableKinetic&&(a=OpenLayers.Util.extend(a,this.enableKinetic));this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart},
-{interval:this.interval,documentDrag:this.documentDrag})},panMapStart:function(){this.kinetic&&this.kinetic.begin()},panMap:function(a){this.kinetic&&this.kinetic.update(a);this.panned=!0;this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!0,animate:!1})},panMapDone:function(a){if(this.panned){var b=null;this.kinetic&&(b=this.kinetic.end(a));this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!!b,animate:!1});if(b){var c=this;this.kinetic.move(b,function(a,b,
-f){c.map.pan(a,b,{dragging:!f,animate:!1})})}this.panned=!1}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:!1,zoomBox:null,zoomBoxEnabled:!0,zoomWheelEnabled:!0,mouseWheelOptions:null,handleRightClicks:!1,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null;
-this.zoomBox&&this.zoomBox.destroy();this.zoomBox=null;this.pinchZoom&&this.pinchZoom.destroy();this.pinchZoom=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.dragPan.activate();this.zoomWheelEnabled&&this.handlers.wheel.activate();this.handlers.click.activate();this.zoomBoxEnabled&&this.zoomBox.activate();this.pinchZoom&&this.pinchZoom.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.pinchZoom&&this.pinchZoom.deactivate();
-this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},draw:function(){this.handleRightClicks&&(this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False);this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.defaultClick,dblclick:this.defaultDblClick,dblrightclick:this.defaultDblRightClick},{"double":!0,stopDouble:!0});this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,
-documentDrag:this.documentDrag},this.dragPanOptions));this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:this.zoomBoxKeyMask});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{up:this.wheelUp,down:this.wheelDown},OpenLayers.Util.extend(this.map.fractionalZoom?{}:{cumulative:!1,interval:50,maxDelta:6},this.mouseWheelOptions));OpenLayers.Control.PinchZoom&&(this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},
-this.pinchZoomOptions)))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&&this.map.zoomOut()},defaultDblClick:function(a){this.map.zoomTo(this.map.zoom+1,a.xy)},defaultDblRightClick:function(a){this.map.zoomTo(this.map.zoom-1,a.xy)},wheelChange:function(a,b){this.map.fractionalZoom||(b=Math.round(b));var c=this.map.getZoom(),d;d=Math.max(c+b,0);d=Math.min(d,this.map.getNumZoomLevels());d!==c&&this.map.zoomTo(d,a.xy)},wheelUp:function(a,b){this.wheelChange(a,b||1)},wheelDown:function(a,
-b){this.wheelChange(a,b||-1)},disableZoomBox:function(){this.zoomBoxEnabled=!1;this.zoomBox.deactivate()},enableZoomBox:function(){this.zoomBoxEnabled=!0;this.active&&this.zoomBox.activate()},disableZoomWheel:function(){this.zoomWheelEnabled=!1;this.handlers.wheel.deactivate()},enableZoomWheel:function(){this.zoomWheelEnabled=!0;this.active&&this.handlers.wheel.activate()},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Control.DrawFeature=OpenLayers.Class(OpenLayers.Control,{layer:null,callbacks:null,multi:!1,featureAdded:function(){},initialize:function(a,b,c){OpenLayers.Control.prototype.initialize.apply(this,[c]);this.callbacks=OpenLayers.Util.extend({done:this.drawFeature,modify:function(a,b){this.layer.events.triggerEvent("sketchmodified",{vertex:a,feature:b})},create:function(a,b){this.layer.events.triggerEvent("sketchstarted",{vertex:a,feature:b})}},this.callbacks);this.layer=a;this.handlerOptions=
-this.handlerOptions||{};this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{renderers:a.renderers,rendererOptions:a.rendererOptions});"multi"in this.handlerOptions||(this.handlerOptions.multi=this.multi);if(a=this.layer.styleMap&&this.layer.styleMap.styles.temporary)this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":a})});this.handler=new b(this,this.callbacks,this.handlerOptions)},
-drawFeature:function(a){a=new OpenLayers.Feature.Vector(a);!1!==this.layer.events.triggerEvent("sketchcomplete",{feature:a})&&(a.state=OpenLayers.State.INSERT,this.layer.addFeatures([a]),this.featureAdded(a),this.events.triggerEvent("featureadded",{feature:a}))},insertXY:function(a,b){this.handler&&this.handler.line&&this.handler.insertXY(a,b)},insertDeltaXY:function(a,b){this.handler&&this.handler.line&&this.handler.insertDeltaXY(a,b)},insertDirectionLength:function(a,b){this.handler&&this.handler.line&&
-this.handler.insertDirectionLength(a,b)},insertDeflectionLength:function(a,b){this.handler&&this.handler.line&&this.handler.insertDeflectionLength(a,b)},undo:function(){return this.handler.undo&&this.handler.undo()},redo:function(){return this.handler.redo&&this.handler.redo()},finishSketch:function(){this.handler.finishGeometry()},cancel:function(){this.handler.cancel()},CLASS_NAME:"OpenLayers.Control.DrawFeature"});OpenLayers.Handler.Polygon=OpenLayers.Class(OpenLayers.Handler.Path,{holeModifier:null,drawingHole:!1,polygon:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LinearRing([this.point.geometry]));this.polygon=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([this.line.geometry]));this.callback("create",[this.point.geometry,
-this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.polygon,this.point],{silent:!0})},addPoint:function(a){if(!this.drawingHole&&this.holeModifier&&this.evt&&this.evt[this.holeModifier])for(var b=this.point.geometry,c=this.control.layer.features,d,e=c.length-1;0<=e;--e)if(d=c[e].geometry,(d instanceof OpenLayers.Geometry.Polygon||d instanceof OpenLayers.Geometry.MultiPolygon)&&d.intersects(b)){b=c[e];this.control.layer.removeFeatures([b],{silent:!0});this.control.layer.events.registerPriority("sketchcomplete",
-this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);b.geometry.addComponent(this.line.geometry);this.polygon=b;this.drawingHole=!0;break}OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments)},getCurrentPointIndex:function(){return this.line.geometry.components.length-2},enforceTopology:function(a){a=a.vertex;var b=this.line.geometry.components;this.polygon.geometry.intersects(a)||(b=b[b.length-3],a.x=b.x,a.y=b.y)},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-
-2]);this.removePoint();this.finalize()},finalizeInteriorRing:function(){var a=this.line.geometry,b=0!==a.getArea();if(b){for(var c=this.polygon.geometry.components,d=c.length-2;0<=d;--d)if(a.intersects(c[d])){b=!1;break}if(b)a:for(d=c.length-2;0<d;--d)for(var e=c[d].components,f=0,g=e.length;f<g;++f)if(a.containsPoint(e[f])){b=!1;break a}}b?this.polygon.state!==OpenLayers.State.INSERT&&(this.polygon.state=OpenLayers.State.UPDATE):this.polygon.geometry.removeComponent(a);this.restoreFeature();return!1},
-cancel:function(){this.drawingHole&&(this.polygon.geometry.removeComponent(this.line.geometry),this.restoreFeature(!0));return OpenLayers.Handler.Path.prototype.cancel.apply(this,arguments)},restoreFeature:function(a){this.control.layer.events.unregister("sketchcomplete",this,this.finalizeInteriorRing);this.control.layer.events.unregister("sketchmodified",this,this.enforceTopology);this.layer.removeFeatures([this.polygon],{silent:!0});this.control.layer.addFeatures([this.polygon],{silent:!0});this.drawingHole=
-!1;a||this.control.layer.events.triggerEvent("sketchcomplete",{feature:this.polygon})},destroyFeature:function(a){OpenLayers.Handler.Path.prototype.destroyFeature.call(this,a);this.polygon=null},drawFeature:function(){this.layer.drawFeature(this.polygon,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.polygon},getGeometry:function(){var a=this.polygon&&this.polygon.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiPolygon([a]));return a},CLASS_NAME:"OpenLayers.Handler.Polygon"});OpenLayers.Control.EditingToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{citeCompliant:!1,initialize:function(a,b){OpenLayers.Control.Panel.prototype.initialize.apply(this,[b]);this.addControls([new OpenLayers.Control.Navigation]);var c=[new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Point,{displayClass:"olControlDrawFeaturePoint",handlerOptions:{citeCompliant:this.citeCompliant}}),new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Path,{displayClass:"olControlDrawFeaturePath",handlerOptions:{citeCompliant:this.citeCompliant}}),
-new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Polygon,{displayClass:"olControlDrawFeaturePolygon",handlerOptions:{citeCompliant:this.citeCompliant}})];this.addControls(c)},draw:function(){var a=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);null===this.defaultControl&&(this.defaultControl=this.controls[0]);return a},CLASS_NAME:"OpenLayers.Control.EditingToolbar"});OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);a&&(this.layer.events.on({moveend:this.update,refresh:this.update,visibilitychanged:this.update,scope:this}),this.update());return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({moveend:this.update,refresh:this.update,visibilitychanged:this.update,
-scope:this});return a},update:function(a){var b=this.getMapBounds();null!==b&&(a&&a.force||this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(b))&&(this.calculateBounds(b),this.resolution=this.layer.map.getResolution(),this.triggerRead(a))},getMapBounds:function(){if(null===this.layer.map)return null;var a=this.layer.map.getExtent();a&&!this.layer.projection.equals(this.layer.map.getProjectionObject())&&(a=a.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection));
-return a},invalidBounds:function(a){a||(a=this.getMapBounds());a=!this.bounds||!this.bounds.containsBounds(a);!a&&this.resFactor&&(a=this.resolution/this.layer.map.getResolution(),a=a>=this.resFactor||a<=1/this.resFactor);return a},calculateBounds:function(a){a||(a=this.getMapBounds());var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio;a=a.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2)},triggerRead:function(a){!this.response||a&&!0===a.noAbort||
-(this.layer.protocol.abort(this.response),this.layer.events.triggerEvent("loadend"));var b={filter:this.createFilter()};this.layer.events.triggerEvent("loadstart",b);this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:b.filter,callback:this.merge,scope:this},a))},createFilter:function(){var a=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});this.layer.filter&&(a=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,
-filters:[this.layer.filter,a]}));return a},merge:function(a){this.layer.destroyFeatures();if(a.success()){var b=a.features;if(b&&0<b.length){var c=this.layer.projection,d=this.layer.map.getProjectionObject();if(!d.equals(c))for(var e,f=0,g=b.length;f<g;++f)(e=b[f].geometry)&&e.transform(c,d);this.layer.addFeatures(b)}}else this.bounds=null;this.response=null;this.layer.events.triggerEvent("loadend",{response:a})},CLASS_NAME:"OpenLayers.Strategy.BBOX"});OpenLayers.Layer.WorldWind=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{},isBaseLayer:!0,lzd:null,zoomLevels:null,initialize:function(a,b,c,d,e,f){this.lzd=c;this.zoomLevels=d;c=[];c.push(a,b,e,f);OpenLayers.Layer.Grid.prototype.initialize.apply(this,c);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS)},getZoom:function(){var a=this.map.getZoom();this.map.getMaxExtent();return a-=Math.log(this.maxResolution/(this.lzd/512))/Math.log(2)},getURL:function(a){a=this.adjustBounds(a);
-var b=this.getZoom(),c=this.map.getMaxExtent(),d=this.lzd/Math.pow(2,this.getZoom()),e=Math.floor((a.left-c.left)/d);a=Math.floor((a.bottom-c.bottom)/d);return this.map.getResolution()<=this.lzd/512&&this.getZoom()<=this.zoomLevels?this.getFullRequestString({L:b,X:e,Y:a}):OpenLayers.Util.getImageLocation("blank.gif")},CLASS_NAME:"OpenLayers.Layer.WorldWind"});OpenLayers.Protocol.CSW=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.CSW.DEFAULTS);var b=OpenLayers.Protocol.CSW["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSW version: "+a.version;return new b(a)};OpenLayers.Protocol.CSW.DEFAULTS={version:"2.0.2"};OpenLayers.Format.WMTSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",yx:{"urn:ogc:def:crs:EPSG::4326":!0},createLayer:function(a,b){if(!("layer"in b))throw Error("Missing property 'layer' in configuration.");for(var c=a.contents,d,e=0,f=c.layers.length;e<f;++e)if(c.layers[e].identifier===b.layer){d=c.layers[e];break}if(!d)throw Error("Layer not found");var g=b.format;!g&&(d.formats&&d.formats.length)&&(g=d.formats[0]);var h;b.matrixSet?h=c.tileMatrixSets[b.matrixSet]:
-1<=d.tileMatrixSetLinks.length&&(h=c.tileMatrixSets[d.tileMatrixSetLinks[0].tileMatrixSet]);if(!h)throw Error("matrixSet not found");for(var k,e=0,f=d.styles.length;e<f&&(k=d.styles[e],!k.isDefault);++e);c=b.requestEncoding;if(!c&&(c="KVP",a.operationsMetadata.GetTile.dcp.http)){var l=a.operationsMetadata.GetTile.dcp.http;l.get[0].constraints&&(l=l.get[0].constraints.GetEncoding.allowedValues,l.KVP||!l.REST&&!l.RESTful||(c="REST"))}var l=[],m=b.params||{};delete b.params;for(var n=0,p=d.dimensions.length;n<
-p;n++){var q=d.dimensions[n];l.push(q.identifier);m.hasOwnProperty(q.identifier)||(m[q.identifier]=q["default"])}var n=b.projection||h.supportedCRS.replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/,"$1:$3"),p=b.units||("EPSG:4326"===n?"degrees":"m"),q=[],r;for(r in h.matrixIds)h.matrixIds.hasOwnProperty(r)&&q.push(2.8E-4*h.matrixIds[r].scaleDenominator/OpenLayers.METERS_PER_INCH/OpenLayers.INCHES_PER_UNIT[p]);if("REST"===c&&d.resourceUrls){r=[];for(var f=0,s=d.resourceUrls.length;f<s;++f)e=d.resourceUrls[f],
-e.format===g&&"tile"===e.resourceType&&r.push(e.template)}else{s=a.operationsMetadata.GetTile.dcp.http.get;r=[];for(var t,e=0,f=s.length;e<f;e++)t=s[e].constraints,(!t||t&&t.GetEncoding.allowedValues[c])&&r.push(s[e].url)}return new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(b,{url:r,requestEncoding:c,name:d.title,style:k.identifier,format:g,matrixIds:h.matrixIds,matrixSet:h.identifier,projection:n,units:p,resolutions:!1===b.isBaseLayer?void 0:q,serverResolutions:q,tileFullExtent:h.bounds,
-dimensions:l,params:m}))},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities"});OpenLayers.Layer.Google.v3={DEFAULTS:{sphericalMercator:!0,projection:"EPSG:900913"},animationEnabled:!0,loadMapObject:function(){this.type||(this.type=google.maps.MapTypeId.ROADMAP);var a,b=OpenLayers.Layer.Google.cache[this.map.id];b?(a=b.mapObject,++b.count):(a=this.map.getCenter(),b=document.createElement("div"),b.className="olForeignContainer",b.style.width="100%",b.style.height="100%",a=new google.maps.Map(b,{center:a?new google.maps.LatLng(a.lat,a.lon):new google.maps.LatLng(0,0),zoom:this.map.getZoom()||
-0,mapTypeId:this.type,disableDefaultUI:!0,keyboardShortcuts:!1,draggable:!1,disableDoubleClickZoom:!0,scrollwheel:!1,streetViewControl:!1}),b=document.createElement("div"),b.style.width="100%",b.style.height="100%",a.controls[google.maps.ControlPosition.TOP_LEFT].push(b),b={googleControl:b,mapObject:a,count:1},OpenLayers.Layer.Google.cache[this.map.id]=b);this.mapObject=a;this.setGMapVisibility(this.visibility)},onMapResize:function(){this.visibility&&google.maps.event.trigger(this.mapObject,"resize")},
-setGMapVisibility:function(a){var b=OpenLayers.Layer.Google.cache[this.map.id],c=this.map;if(b){for(var d=this.type,e=c.layers,f,g=e.length-1;0<=g;--g)if(f=e[g],f instanceof OpenLayers.Layer.Google&&!0===f.visibility&&!0===f.inRange){d=f.type;a=!0;break}e=this.mapObject.getDiv();if(!0===a){if(e.parentNode!==c.div)if(b.rendered)c.div.appendChild(e),b.googleControl.appendChild(c.viewPortDiv),google.maps.event.trigger(this.mapObject,"resize");else{var h=this;google.maps.event.addListenerOnce(this.mapObject,
-"tilesloaded",function(){b.rendered=!0;h.setGMapVisibility(h.getVisibility());h.moveTo(h.map.getCenter())})}this.mapObject.setMapTypeId(d)}else b.googleControl.hasChildNodes()&&(c.div.appendChild(c.viewPortDiv),c.div.removeChild(e))}},getMapContainer:function(){return this.mapObject.getDiv()},getMapObjectBoundsFromOLBounds:function(a){var b=null;null!=a&&(b=this.sphericalMercator?this.inverseMercator(a.bottom,a.left):new OpenLayers.LonLat(a.bottom,a.left),a=this.sphericalMercator?this.inverseMercator(a.top,
-a.right):new OpenLayers.LonLat(a.top,a.right),b=new google.maps.LatLngBounds(new google.maps.LatLng(b.lat,b.lon),new google.maps.LatLng(a.lat,a.lon)));return b},getMapObjectLonLatFromMapObjectPixel:function(a){var b=this.map.getSize(),c=this.getLongitudeFromMapObjectLonLat(this.mapObject.center),d=this.getLatitudeFromMapObjectLonLat(this.mapObject.center),e=this.map.getResolution();a=new OpenLayers.LonLat(c+(a.x-b.w/2)*e,d-(a.y-b.h/2)*e);this.wrapDateLine&&(a=a.wrapDateLine(this.maxExtent));return this.getMapObjectLonLatFromLonLat(a.lon,
-a.lat)},getMapObjectPixelFromMapObjectLonLat:function(a){var b=this.getLongitudeFromMapObjectLonLat(a);a=this.getLatitudeFromMapObjectLonLat(a);var c=this.map.getResolution(),d=this.map.getExtent();return this.getMapObjectPixelFromXY(1/c*(b-d.left),1/c*(d.top-a))},setMapObjectCenter:function(a,b){if(!1===this.animationEnabled&&b!=this.mapObject.zoom){var c=this.getMapContainer();google.maps.event.addListenerOnce(this.mapObject,"idle",function(){c.style.visibility=""});c.style.visibility="hidden"}this.mapObject.setOptions({center:a,
-zoom:b})},getMapObjectZoomFromMapObjectBounds:function(a){return this.mapObject.getBoundsZoomLevel(a)},getMapObjectLonLatFromLonLat:function(a,b){var c;this.sphericalMercator?(c=this.inverseMercator(a,b),c=new google.maps.LatLng(c.lat,c.lon)):c=new google.maps.LatLng(b,a);return c},getMapObjectPixelFromXY:function(a,b){return new google.maps.Point(a,b)}};OpenLayers.Format.WPSDescribeProcess=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{wps:"http://www.opengis.net/wps/1.0.0",ows:"http://www.opengis.net/ows/1.1",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd",defaultPrefix:"wps",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,
-[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{wps:{ProcessDescriptions:function(a,b){b.processDescriptions={};this.readChildNodes(a,b.processDescriptions)},ProcessDescription:function(a,b){var c={processVersion:this.getAttributeNS(a,this.namespaces.wps,"processVersion"),statusSupported:"true"===a.getAttribute("statusSupported"),storeSupported:"true"===a.getAttribute("storeSupported")};this.readChildNodes(a,c);b[c.identifier]=c},DataInputs:function(a,
-b){b.dataInputs=[];this.readChildNodes(a,b.dataInputs)},ProcessOutputs:function(a,b){b.processOutputs=[];this.readChildNodes(a,b.processOutputs)},Output:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},ComplexOutput:function(a,b){b.complexOutput={};this.readChildNodes(a,b.complexOutput)},LiteralOutput:function(a,b){b.literalOutput={};this.readChildNodes(a,b.literalOutput)},Input:function(a,b){var c={maxOccurs:parseInt(a.getAttribute("maxOccurs")),minOccurs:parseInt(a.getAttribute("minOccurs"))};
-this.readChildNodes(a,c);b.push(c)},BoundingBoxData:function(a,b){b.boundingBoxData={};this.readChildNodes(a,b.boundingBoxData)},CRS:function(a,b){b.CRSs||(b.CRSs={});b.CRSs[this.getChildValue(a)]=!0},LiteralData:function(a,b){b.literalData={};this.readChildNodes(a,b.literalData)},ComplexData:function(a,b){b.complexData={};this.readChildNodes(a,b.complexData)},Default:function(a,b){b["default"]={};this.readChildNodes(a,b["default"])},Supported:function(a,b){b.supported={};this.readChildNodes(a,b.supported)},
-Format:function(a,b){var c={};this.readChildNodes(a,c);b.formats||(b.formats={});b.formats[c.mimeType]=!0},MimeType:function(a,b){b.mimeType=this.getChildValue(a)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSDescribeProcess"});OpenLayers.Format.WKT=OpenLayers.Class(OpenLayers.Format,{initialize:function(a){this.regExes={typeStr:/^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,spaces:/\s+/,parenComma:/\)\s*,\s*\(/,doubleParenComma:/\)\s*\)\s*,\s*\(\s*\(/,trimParens:/^\s*\(?(.*?)\)?\s*$/};OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){var b,c;a=a.replace(/[\n\r]/g," ");if(c=this.regExes.typeStr.exec(a))if(a=c[1].toLowerCase(),c=c[2],this.parse[a]&&(b=this.parse[a].apply(this,[c])),this.internalProjection&&this.externalProjection)if(b&&
-"OpenLayers.Feature.Vector"==b.CLASS_NAME)b.geometry.transform(this.externalProjection,this.internalProjection);else if(b&&"geometrycollection"!=a&&"object"==typeof b)for(a=0,c=b.length;a<c;a++)b[a].geometry.transform(this.externalProjection,this.internalProjection);return b},write:function(a){var b,c;a.constructor==Array?c=!0:(a=[a],c=!1);var d=[];c&&d.push("GEOMETRYCOLLECTION(");for(var e=0,f=a.length;e<f;++e)c&&0<e&&d.push(","),b=a[e].geometry,d.push(this.extractGeometry(b));c&&d.push(")");return d.join("")},
-extractGeometry:function(a){var b=a.CLASS_NAME.split(".")[2].toLowerCase();if(!this.extract[b])return null;this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));return("collection"==b?"GEOMETRYCOLLECTION":b.toUpperCase())+"("+this.extract[b].apply(this,[a])+")"},extract:{point:function(a){return a.x+" "+a.y},multipoint:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.point.apply(this,[a.components[c]])+
-")");return b.join(",")},linestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b.join(",")},multilinestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.linestring.apply(this,[a.components[c]])+")");return b.join(",")},polygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.linestring.apply(this,[a.components[c]])+")");return b.join(",")},multipolygon:function(a){for(var b=
-[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.polygon.apply(this,[a.components[c]])+")");return b.join(",")},collection:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extractGeometry.apply(this,[a.components[c]]));return b.join(",")}},parse:{point:function(a){a=OpenLayers.String.trim(a).split(this.regExes.spaces);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a[0],a[1]))},multipoint:function(a){for(var b=OpenLayers.String.trim(a).split(","),
-c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.point.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPoint(c))},linestring:function(a){a=OpenLayers.String.trim(a).split(",");for(var b=[],c=0,d=a.length;c<d;++c)b.push(this.parse.point.apply(this,[a[c]]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(b))},multilinestring:function(a){for(var b=OpenLayers.String.trim(a).split(this.regExes.parenComma),
-c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.linestring.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiLineString(c))},polygon:function(a){var b;a=OpenLayers.String.trim(a).split(this.regExes.parenComma);for(var c=[],d=0,e=a.length;d<e;++d)b=a[d].replace(this.regExes.trimParens,"$1"),b=this.parse.linestring.apply(this,[b]).geometry,b=new OpenLayers.Geometry.LinearRing(b.components),c.push(b);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon(c))},
-multipolygon:function(a){for(var b=OpenLayers.String.trim(a).split(this.regExes.doubleParenComma),c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.polygon.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPolygon(c))},geometrycollection:function(a){a=a.replace(/,\s*([A-Za-z])/g,"|$1");a=OpenLayers.String.trim(a).split("|");for(var b=[],c=0,d=a.length;c<d;++c)b.push(OpenLayers.Format.WKT.prototype.read.apply(this,[a[c]]));
-return b}},CLASS_NAME:"OpenLayers.Format.WKT"});OpenLayers.WPSProcess=OpenLayers.Class({client:null,server:null,identifier:null,description:null,localWPS:"http://geoserver/wps",formats:null,chained:0,executeCallbacks:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.executeCallbacks=[];this.formats={"application/wkt":new OpenLayers.Format.WKT,"application/json":new OpenLayers.Format.GeoJSON}},describe:function(a){a=a||{};if(!this.description)this.client.describeProcess(this.server,this.identifier,function(b){this.description||this.parseDescription(b);
-a.callback&&a.callback.call(a.scope,this.description)},this);else if(a.callback){var b=this.description;window.setTimeout(function(){a.callback.call(a.scope,b)},0)}},configure:function(a){this.describe({callback:function(){var b=this.description,c=a.inputs,d,e,f;e=0;for(f=b.dataInputs.length;e<f;++e)d=b.dataInputs[e],this.setInputData(d,c[d.identifier]);a.callback&&a.callback.call(a.scope)},scope:this});return this},execute:function(a){this.configure({inputs:a.inputs,callback:function(){var b=this,
-c=this.getOutputIndex(b.description.processOutputs,a.output);b.setResponseForm({outputIndex:c});(function e(){OpenLayers.Util.removeItem(b.executeCallbacks,e);0!==b.chained?b.executeCallbacks.push(e):OpenLayers.Request.POST({url:b.client.servers[b.server].url,data:(new OpenLayers.Format.WPSExecute).write(b.description),success:function(e){var g=b.findMimeType(b.description.processOutputs[c].complexOutput.supported.formats);e=b.formats[g].read(e.responseText);e instanceof OpenLayers.Feature.Vector&&
-(e=[e]);a.success&&(g={},g[a.output||"result"]=e,a.success.call(a.scope,g))},scope:b})})()},scope:this})},output:function(a){return new OpenLayers.WPSProcess.ChainLink({process:this,output:a})},parseDescription:function(a){a=this.client.servers[this.server];this.description=(new OpenLayers.Format.WPSDescribeProcess).read(a.processDescription[this.identifier]).processDescriptions[this.identifier]},setInputData:function(a,b){delete a.data;delete a.reference;if(b instanceof OpenLayers.WPSProcess.ChainLink)++this.chained,
-a.reference={method:"POST",href:b.process.server===this.server?this.localWPS:this.client.servers[b.process.server].url},b.process.describe({callback:function(){--this.chained;this.chainProcess(a,b)},scope:this});else{a.data={};var c=a.complexData;c?(c=this.findMimeType(c.supported.formats),a.data.complexData={mimeType:c,value:this.formats[c].write(this.toFeatures(b))}):a.data.literalData={value:b}}},setResponseForm:function(a){a=a||{};var b=this.description.processOutputs[a.outputIndex||0];this.description.responseForm=
-{rawDataOutput:{identifier:b.identifier,mimeType:this.findMimeType(b.complexOutput.supported.formats,a.supportedFormats)}}},getOutputIndex:function(a,b){var c;if(b)for(var d=a.length-1;0<=d;--d){if(a[d].identifier===b){c=d;break}}else c=0;return c},chainProcess:function(a,b){var c=this.getOutputIndex(b.process.description.processOutputs,b.output);a.reference.mimeType=this.findMimeType(a.complexData.supported.formats,b.process.description.processOutputs[c].complexOutput.supported.formats);var d={};
-d[a.reference.mimeType]=!0;b.process.setResponseForm({outputIndex:c,supportedFormats:d});for(a.reference.body=b.process.description;0<this.executeCallbacks.length;)this.executeCallbacks[0]()},toFeatures:function(a){var b=OpenLayers.Util.isArray(a);b||(a=[a]);for(var c=Array(a.length),d,e=0,f=a.length;e<f;++e)d=a[e],c[e]=d instanceof OpenLayers.Feature.Vector?d:new OpenLayers.Feature.Vector(d);return b?c:c[0]},findMimeType:function(a,b){b=b||this.formats;for(var c in a)if(c in b)return c},CLASS_NAME:"OpenLayers.WPSProcess"});
-OpenLayers.WPSProcess.ChainLink=OpenLayers.Class({process:null,output:null,initialize:function(a){OpenLayers.Util.extend(this,a)},CLASS_NAME:"OpenLayers.WPSProcess.ChainLink"});OpenLayers.WPSClient=OpenLayers.Class({servers:null,version:"1.0.0",lazy:!1,events:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this);this.servers={};for(var b in a.servers)this.servers[b]="string"==typeof a.servers[b]?{url:a.servers[b],version:this.version,processDescription:{}}:a.servers[b]},execute:function(a){this.getProcess(a.server,a.process).execute({inputs:a.inputs,success:a.success,scope:a.scope})},getProcess:function(a,b){var c=new OpenLayers.WPSProcess({client:this,
-server:a,identifier:b});this.lazy||c.describe();return c},describeProcess:function(a,b,c,d){var e=this.servers[a];e.processDescription[b]?window.setTimeout(function(){c.call(d,e.processDescription[b])},0):b in e.processDescription?this.events.register("describeprocess",this,function g(a){a.identifier===b&&(this.events.unregister("describeprocess",this,g),c.call(d,a.raw))}):(e.processDescription[b]=null,OpenLayers.Request.GET({url:e.url,params:{SERVICE:"WPS",VERSION:e.version,REQUEST:"DescribeProcess",
-IDENTIFIER:b},success:function(a){e.processDescription[b]=a.responseText;this.events.triggerEvent("describeprocess",{identifier:b,raw:a.responseText})},scope:this}))},destroy:function(){this.events.destroy();this.servers=this.events=null},CLASS_NAME:"OpenLayers.WPSClient"});OpenLayers.Format.CSWGetRecords.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{csw:"http://www.opengis.net/cat/csw/2.0.2",dc:"http://purl.org/dc/elements/1.1/",dct:"http://purl.org/dc/terms/",gmd:"http://www.isotc211.org/2005/gmd",geonet:"http://www.fao.org/geonetwork",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",
-requestId:null,resultType:null,outputFormat:null,outputSchema:null,startPosition:null,maxRecords:null,DistributedSearch:null,ResponseHandler:null,Query:null,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},
-readers:{csw:{GetRecordsResponse:function(a,b){b.records=[];this.readChildNodes(a,b);var c=this.getAttributeNS(a,"","version");""!=c&&(b.version=c)},RequestId:function(a,b){b.RequestId=this.getChildValue(a)},SearchStatus:function(a,b){b.SearchStatus={};var c=this.getAttributeNS(a,"","timestamp");""!=c&&(b.SearchStatus.timestamp=c)},SearchResults:function(a,b){this.readChildNodes(a,b);for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]="numberOfRecordsMatched"==c[e].name||"numberOfRecordsReturned"==
-c[e].name||"nextRecord"==c[e].name?parseInt(c[e].nodeValue):c[e].nodeValue;b.SearchResults=d},SummaryRecord:function(a,b){var c={type:"SummaryRecord"};this.readChildNodes(a,c);b.records.push(c)},BriefRecord:function(a,b){var c={type:"BriefRecord"};this.readChildNodes(a,c);b.records.push(c)},DCMIRecord:function(a,b){var c={type:"DCMIRecord"};this.readChildNodes(a,c);b.records.push(c)},Record:function(a,b){var c={type:"Record"};this.readChildNodes(a,c);b.records.push(c)},"*":function(a,b){var c=a.localName||
-a.nodeName.split(":").pop();b[c]=this.getChildValue(a)}},geonet:{info:function(a,b){var c={};this.readChildNodes(a,c);b.gninfo=c}},dc:{"*":function(a,b){var c=a.localName||a.nodeName.split(":").pop();OpenLayers.Util.isArray(b[c])||(b[c]=[]);for(var d={},e=a.attributes,f=0,g=e.length;f<g;++f)d[e[f].name]=e[f].nodeValue;d.value=this.getChildValue(a);""!=d.value&&b[c].push(d)}},dct:{"*":function(a,b){var c=a.localName||a.nodeName.split(":").pop();OpenLayers.Util.isArray(b[c])||(b[c]=[]);b[c].push(this.getChildValue(a))}},
-ows:OpenLayers.Util.applyDefaults({BoundingBox:function(a,b){b.bounds&&(b.BoundingBox=[{crs:b.projection,value:[b.bounds.left,b.bounds.bottom,b.bounds.right,b.bounds.top]}],delete b.projection,delete b.bounds);OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows.BoundingBox.apply(this,arguments)}},OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows)},write:function(a){a=this.writeNode("csw:GetRecords",a);a.setAttribute("xmlns:gmd",this.namespaces.gmd);return OpenLayers.Format.XML.prototype.write.apply(this,
-[a])},writers:{csw:{GetRecords:function(a){a||(a={});var b=this.createElementNSPlus("csw:GetRecords",{attributes:{service:"CSW",version:this.version,requestId:a.requestId||this.requestId,resultType:a.resultType||this.resultType,outputFormat:a.outputFormat||this.outputFormat,outputSchema:a.outputSchema||this.outputSchema,startPosition:a.startPosition||this.startPosition,maxRecords:a.maxRecords||this.maxRecords}});(a.DistributedSearch||this.DistributedSearch)&&this.writeNode("csw:DistributedSearch",
-a.DistributedSearch||this.DistributedSearch,b);var c=a.ResponseHandler||this.ResponseHandler;if(OpenLayers.Util.isArray(c)&&0<c.length)for(var d=0,e=c.length;d<e;d++)this.writeNode("csw:ResponseHandler",c[d],b);this.writeNode("Query",a.Query||this.Query,b);return b},DistributedSearch:function(a){return this.createElementNSPlus("csw:DistributedSearch",{attributes:{hopCount:a.hopCount}})},ResponseHandler:function(a){return this.createElementNSPlus("csw:ResponseHandler",{value:a.value})},Query:function(a){a||
-(a={});var b=this.createElementNSPlus("csw:Query",{attributes:{typeNames:a.typeNames||"csw:Record"}}),c=a.ElementName;if(OpenLayers.Util.isArray(c)&&0<c.length)for(var d=0,e=c.length;d<e;d++)this.writeNode("csw:ElementName",c[d],b);else this.writeNode("csw:ElementSetName",a.ElementSetName||{value:"summary"},b);a.Constraint&&this.writeNode("csw:Constraint",a.Constraint,b);a.SortBy&&this.writeNode("ogc:SortBy",a.SortBy,b);return b},ElementName:function(a){return this.createElementNSPlus("csw:ElementName",
-{value:a.value})},ElementSetName:function(a){return this.createElementNSPlus("csw:ElementSetName",{attributes:{typeNames:a.typeNames},value:a.value})},Constraint:function(a){var b=this.createElementNSPlus("csw:Constraint",{attributes:{version:a.version}});if(a.Filter){var c=new OpenLayers.Format.Filter({version:a.version});b.appendChild(c.write(a.Filter))}else a.CqlText&&(a=this.createElementNSPlus("CqlText",{value:a.CqlText.value}),b.appendChild(a));return b}},ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc},
-CLASS_NAME:"OpenLayers.Format.CSWGetRecords.v2_0_2"});/*
- Apache 2
-
- Contains portions of Rico <http://openrico.org/>
-
- Copyright 2005 Sabre Airline Solutions
-
- Licensed under the Apache License, Version 2.0 (the "License"); you
- may not use this file except in compliance with the License. You
- may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied. See the License for the specific language governing
- permissions and limitations under the License.
-*/
-OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(a,b,c){this.bounds=a;this.div=OpenLayers.Util.createDiv();this.div.style.overflow="hidden";this.events=new OpenLayers.Events(this,this.div);this.setBorder(b,c)},destroy:function(){this.div=this.bounds=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments)},setBorder:function(a,b){a||(a="red");b||(b=2);this.div.style.border=b+"px solid "+a},draw:function(a,b){OpenLayers.Util.modifyDOMElement(this.div,
-null,a,b);return this.div},onScreen:function(){var a=!1;this.map&&(a=this.map.getExtent().containsBounds(this.bounds,!0,!0));return a},display:function(a){this.div.style.display=a?"":"none"},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Format.Text=OpenLayers.Class(OpenLayers.Format,{defaultStyle:null,extractStyles:!0,initialize:function(a){a=a||{};!1!==a.extractStyles&&(a.defaultStyle={externalGraphic:OpenLayers.Util.getImageLocation("marker.png"),graphicWidth:21,graphicHeight:25,graphicXOffset:-10.5,graphicYOffset:-12.5});OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){a=a.split("\n");for(var b,c=[],d=0;d<a.length-1;d++){var e=a[d].replace(/^\s*/,"").replace(/\s*$/,"");if("#"!=e.charAt(0))if(b){for(var e=
-e.split("\t"),f=new OpenLayers.Geometry.Point(0,0),g={},h=this.defaultStyle?OpenLayers.Util.applyDefaults({},this.defaultStyle):null,k=!1,l=0;l<e.length;l++)if(e[l])if("point"==b[l])k=e[l].split(","),f.y=parseFloat(k[0]),f.x=parseFloat(k[1]),k=!0;else if("lat"==b[l])f.y=parseFloat(e[l]),k=!0;else if("lon"==b[l])f.x=parseFloat(e[l]),k=!0;else if("title"==b[l])g.title=e[l];else if("image"==b[l]||"icon"==b[l]&&h)h.externalGraphic=e[l];else if("iconSize"==b[l]&&h){var m=e[l].split(",");h.graphicWidth=
-parseFloat(m[0]);h.graphicHeight=parseFloat(m[1])}else"iconOffset"==b[l]&&h?(m=e[l].split(","),h.graphicXOffset=parseFloat(m[0]),h.graphicYOffset=parseFloat(m[1])):"description"==b[l]?g.description=e[l]:"overflow"==b[l]?g.overflow=e[l]:g[b[l]]=e[l];k&&(this.internalProjection&&this.externalProjection&&f.transform(this.externalProjection,this.internalProjection),e=new OpenLayers.Feature.Vector(f,g,h),c.push(e))}else b=e.split("\t")}return c},CLASS_NAME:"OpenLayers.Format.Text"});OpenLayers.Layer.Text=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,initialize:function(a,b){OpenLayers.Layer.Markers.prototype.initialize.apply(this,arguments);this.features=[]},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null},loadText:function(){this.loaded||null==this.location||(this.events.triggerEvent("loadstart"),OpenLayers.Request.GET({url:this.location,
-success:this.parseData,failure:function(a){this.events.triggerEvent("loadend")},scope:this}),this.loaded=!0)},moveTo:function(a,b,c){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);this.visibility&&!this.loaded&&this.loadText()},parseData:function(a){a=a.responseText;var b={};OpenLayers.Util.extend(b,this.formatOptions);this.map&&!this.projection.equals(this.map.getProjectionObject())&&(b.externalProjection=this.projection,b.internalProjection=this.map.getProjectionObject());a=(new OpenLayers.Format.Text(b)).read(a);
-for(var b=0,c=a.length;b<c;b++){var d={},e=a[b],f,g,h;f=new OpenLayers.LonLat(e.geometry.x,e.geometry.y);e.style.graphicWidth&&e.style.graphicHeight&&(g=new OpenLayers.Size(e.style.graphicWidth,e.style.graphicHeight));void 0!==e.style.graphicXOffset&&void 0!==e.style.graphicYOffset&&(h=new OpenLayers.Pixel(e.style.graphicXOffset,e.style.graphicYOffset));null!=e.style.externalGraphic?d.icon=new OpenLayers.Icon(e.style.externalGraphic,g,h):(d.icon=OpenLayers.Marker.defaultIcon(),null!=g&&d.icon.setSize(g));
-null!=e.attributes.title&&null!=e.attributes.description&&(d.popupContentHTML="<h2>"+e.attributes.title+"</h2><p>"+e.attributes.description+"</p>");d.overflow=e.attributes.overflow||"auto";d=new OpenLayers.Feature(this,f,d);this.features.push(d);f=d.createMarker();null!=e.attributes.title&&null!=e.attributes.description&&f.events.register("click",d,this.markerClick);this.addMarker(f)}this.events.triggerEvent("loadend")},markerClick:function(a){var b=this==this.layer.selectedFeature;this.layer.selectedFeature=
-b?null:this;for(var c=0,d=this.layer.map.popups.length;c<d;c++)this.layer.map.removePopup(this.layer.map.popups[c]);b||this.layer.map.addPopup(this.createPopup());OpenLayers.Event.stop(a)},clearFeatures:function(){if(null!=this.features)for(;0<this.features.length;){var a=this.features[0];OpenLayers.Util.removeItem(this.features,a);a.destroy()}},CLASS_NAME:"OpenLayers.Layer.Text"});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:"shiftKey",layerOptions:null,persist:!1,irregular:!1,citeCompliant:!1,angle:null,fixedRadius:!1,feature:null,layer:null,origin:null,initialize:function(a,b,c){c&&c.layerOptions&&c.layerOptions.styleMap||(this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{}));OpenLayers.Handler.Drag.prototype.initialize.apply(this,[a,b,c]);this.options=c?c:{}},setOptions:function(a){OpenLayers.Util.extend(this.options,
-a);OpenLayers.Util.extend(this,a)},activate:function(){var a=!1;OpenLayers.Handler.Drag.prototype.activate.apply(this,arguments)&&(a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions),this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a),this.map.addLayer(this.layer),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)&&(this.dragging&&this.cancel(),
-null!=this.layer.map&&(this.layer.destroy(!1),this.feature&&this.feature.destroy()),this.feature=this.layer=null,a=!0);return a},down:function(a){this.fixedRadius=!!this.radius;a=this.layer.getLonLatFromViewPortPx(a.xy);this.origin=new OpenLayers.Geometry.Point(a.lon,a.lat);if(!this.fixedRadius||this.irregular)this.radius=this.map.getResolution();this.persist&&this.clear();this.feature=new OpenLayers.Feature.Vector;this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],
-{silent:!0});this.layer.drawFeature(this.feature,this.style)},move:function(a){var b=this.layer.getLonLatFromViewPortPx(a.xy),b=new OpenLayers.Geometry.Point(b.lon,b.lat);this.irregular?(a=Math.sqrt(2)*Math.abs(b.y-this.origin.y)/2,this.radius=Math.max(this.map.getResolution()/2,a)):this.fixedRadius?this.origin=b:(this.calculateAngle(b,a),this.radius=Math.max(this.map.getResolution()/2,b.distanceTo(this.origin)));this.modifyGeometry();if(this.irregular){a=b.x-this.origin.x;var b=b.y-this.origin.y,
-c;c=0==b?a/(this.radius*Math.sqrt(2)):a/b;this.feature.geometry.resize(1,this.origin,c);this.feature.geometry.move(a/2,b/2)}this.layer.drawFeature(this.feature,this.style)},up:function(a){this.finalize();this.start==this.last&&this.callback("done",[a.xy])},out:function(a){this.finalize()},createGeometry:function(){this.angle=Math.PI*(1/this.sides-0.5);this.snapAngle&&(this.angle+=this.snapAngle*(Math.PI/180));this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,
-this.sides,this.snapAngle)},modifyGeometry:function(){var a,b,c=this.feature.geometry.components[0];c.components.length!=this.sides+1&&(this.createGeometry(),c=this.feature.geometry.components[0]);for(var d=0;d<this.sides;++d)b=c.components[d],a=this.angle+2*d*Math.PI/this.sides,b.x=this.origin.x+this.radius*Math.cos(a),b.y=this.origin.y+this.radius*Math.sin(a),b.clearBounds()},calculateAngle:function(a,b){var c=Math.atan2(a.y-this.origin.y,a.x-this.origin.x);if(this.snapAngle&&this.snapToggle&&!b[this.snapToggle]){var d=
-Math.PI/180*this.snapAngle;this.angle=Math.round(c/d)*d}else this.angle=c},cancel:function(){this.callback("cancel",null);this.finalize()},finalize:function(){this.origin=null;this.radius=this.options.radius},clear:function(){this.layer&&(this.layer.renderer.clear(),this.layer.destroyFeatures())},callback:function(a,b){this.callbacks[a]&&this.callbacks[a].apply(this.control,[this.feature.geometry.clone()]);this.persist||"done"!=a&&"cancel"!=a||this.clear()},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Control.SLDSelect=OpenLayers.Class(OpenLayers.Control,{clearOnDeactivate:!1,layers:null,callbacks:null,selectionSymbolizer:{Polygon:{fillColor:"#FF0000",stroke:!1},Line:{strokeColor:"#FF0000",strokeWidth:2},Point:{graphicName:"square",fillColor:"#FF0000",pointRadius:5}},layerOptions:null,sketchStyle:null,wfsCache:{},layerCache:{},initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.callbacks=OpenLayers.Util.extend({done:this.select,click:this.select},this.callbacks);
-this.handlerOptions=this.handlerOptions||{};this.layerOptions=OpenLayers.Util.applyDefaults(this.layerOptions,{displayInLayerSwitcher:!1,tileOptions:{maxGetUrlLength:2048}});this.sketchStyle&&(this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":this.sketchStyle})}));this.handler=new a(this,this.callbacks,this.handlerOptions)},destroy:function(){for(var a in this.layerCache)delete this.layerCache[a];for(a in this.wfsCache)delete this.wfsCache[a];
-OpenLayers.Control.prototype.destroy.apply(this,arguments)},coupleLayerVisiblity:function(a){this.setVisibility(a.object.getVisibility())},createSelectionLayer:function(a){var b;if(this.layerCache[a.id])b=this.layerCache[a.id];else{b=new OpenLayers.Layer.WMS(a.name,a.url,a.params,OpenLayers.Util.applyDefaults(this.layerOptions,a.getOptions()));this.layerCache[a.id]=b;if(!1===this.layerOptions.displayInLayerSwitcher)a.events.on({visibilitychanged:this.coupleLayerVisiblity,scope:b});this.map.addLayer(b)}return b},
-createSLD:function(a,b,c){for(var d={version:"1.0.0",namedLayers:{}},e=(""+a.params.LAYERS).split(","),f=0,g=e.length;f<g;f++){var h=e[f];d.namedLayers[h]={name:h,userStyles:[]};var k=this.selectionSymbolizer,l=c[f];0<=l.type.indexOf("Polygon")?k={Polygon:this.selectionSymbolizer.Polygon}:0<=l.type.indexOf("LineString")?k={Line:this.selectionSymbolizer.Line}:0<=l.type.indexOf("Point")&&(k={Point:this.selectionSymbolizer.Point});d.namedLayers[h].userStyles.push({name:"default",rules:[new OpenLayers.Rule({symbolizer:k,
-filter:b[f],maxScaleDenominator:a.options.minScale})]})}return(new OpenLayers.Format.SLD({srsName:this.map.getProjection()})).write(d)},parseDescribeLayer:function(a){var b=new OpenLayers.Format.WMSDescribeLayer,c=a.responseXML;c&&c.documentElement||(c=a.responseText);a=b.read(c);for(var b=[],c=null,d=0,e=a.length;d<e;d++)"WFS"==a[d].owsType&&(b.push(a[d].typeName),c=a[d].owsURL);OpenLayers.Request.GET({url:c,params:{SERVICE:"WFS",TYPENAME:b.toString(),REQUEST:"DescribeFeatureType",VERSION:"1.0.0"},
-callback:function(a){var b=new OpenLayers.Format.WFSDescribeFeatureType,c=a.responseXML;c&&c.documentElement||(c=a.responseText);a=b.read(c);this.control.wfsCache[this.layer.id]=a;this.control._queue&&this.control.applySelection()},scope:this})},getGeometryAttributes:function(a){var b=[];a=this.wfsCache[a.id];for(var c=0,d=a.featureTypes.length;c<d;c++)for(var e=a.featureTypes[c].properties,f=0,g=e.length;f<g;f++){var h=e[f],k=h.type;(0<=k.indexOf("LineString")||0<=k.indexOf("GeometryAssociationType")||
-0<=k.indexOf("GeometryPropertyType")||0<=k.indexOf("Point")||0<=k.indexOf("Polygon"))&&b.push(h)}return b},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a)for(var b=0,c=this.layers.length;b<c;b++){var d=this.layers[b];d&&!this.wfsCache[d.id]&&OpenLayers.Request.GET({url:d.url,params:{SERVICE:"WMS",VERSION:d.params.VERSION,LAYERS:d.params.LAYERS,REQUEST:"DescribeLayer"},callback:this.parseDescribeLayer,scope:{layer:d,control:this}})}return a},deactivate:function(){var a=
-OpenLayers.Control.prototype.deactivate.call(this);if(a)for(var b=0,c=this.layers.length;b<c;b++){var d=this.layers[b];if(d&&!0===this.clearOnDeactivate){var e=this.layerCache,f=e[d.id];f&&(d.events.un({visibilitychanged:this.coupleLayerVisiblity,scope:f}),f.destroy(),delete e[d.id])}}return a},setLayers:function(a){this.active?(this.deactivate(),this.layers=a,this.activate()):this.layers=a},createFilter:function(a,b){var c=null;this.handler instanceof OpenLayers.Handler.RegularPolygon?c=!0===this.handler.irregular?
-new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:a.name,value:b.getBounds()}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Polygon?c=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Path?c=0<=a.type.indexOf("Point")?new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,
-property:a.name,distance:0.01*this.map.getExtent().getWidth(),distanceUnits:this.map.getUnits(),value:b}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Click&&(c=0<=a.type.indexOf("Polygon")?new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,property:a.name,distance:0.01*this.map.getExtent().getWidth(),
-distanceUnits:this.map.getUnits(),value:b}));return c},select:function(a){this._queue=function(){for(var b=0,c=this.layers.length;b<c;b++){for(var d=this.layers[b],e=this.getGeometryAttributes(d),f=[],g=0,h=e.length;g<h;g++){var k=e[g];if(null!==k){if(!(a instanceof OpenLayers.Geometry)){var l=this.map.getLonLatFromPixel(a.xy);a=new OpenLayers.Geometry.Point(l.lon,l.lat)}k=this.createFilter(k,a);null!==k&&f.push(k)}}g=this.createSelectionLayer(d);this.events.triggerEvent("selected",{layer:d,filters:f});
-d=this.createSLD(d,f,e);g.mergeNewParams({SLD_BODY:d});delete this._queue}};this.applySelection()},applySelection:function(){for(var a=!0,b=0,c=this.layers.length;b<c;b++)if(!this.wfsCache[this.layers[b].id]){a=!1;break}a&&this._queue.call(this)},CLASS_NAME:"OpenLayers.Control.SLDSelect"});OpenLayers.Control.Scale=OpenLayers.Class(OpenLayers.Control,{element:null,geodesic:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.element=OpenLayers.Util.getElement(a)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||(this.element=document.createElement("div"),this.div.appendChild(this.element));this.map.events.register("moveend",this,this.updateScale);this.updateScale();return this.div},updateScale:function(){var a;
-if(!0===this.geodesic){if(!this.map.getUnits())return;a=OpenLayers.INCHES_PER_UNIT;a=(this.map.getGeodesicPixelSize().w||1E-6)*a.km*OpenLayers.DOTS_PER_INCH}else a=this.map.getScale();a&&(a=9500<=a&&95E4>=a?Math.round(a/1E3)+"K":95E4<=a?Math.round(a/1E6)+"M":Math.round(a),this.element.innerHTML=OpenLayers.i18n("Scale = 1 : ${scaleDenom}",{scaleDenom:a}))},CLASS_NAME:"OpenLayers.Control.Scale"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,useHttpTile:!1,singleTile:!1,useOverlay:!1,useAsyncOverlay:!0,TILE_PARAMS:{operation:"GETTILEIMAGE",version:"1.2.0"},SINGLE_TILE_PARAMS:{operation:"GETMAPIMAGE",format:"PNG",locale:"en",clip:"1",version:"1.0.0"},OVERLAY_PARAMS:{operation:"GETDYNAMICMAPOVERLAYIMAGE",format:"PNG",locale:"en",clip:"1",version:"2.0.0"},FOLDER_PARAMS:{tileColumnsPerFolder:30,tileRowsPerFolder:30,format:"png",querystring:null},defaultSize:new OpenLayers.Size(300,
-300),tileOriginCorner:"tl",initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);if(null==d||null==d.isBaseLayer)this.isBaseLayer="true"!=this.transparent&&!0!=this.transparent;d&&null!=d.useOverlay&&(this.useOverlay=d.useOverlay);this.singleTile?this.useOverlay?(OpenLayers.Util.applyDefaults(this.params,this.OVERLAY_PARAMS),this.useAsyncOverlay||(this.params.version="1.0.0")):OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS):(this.useHttpTile?
-OpenLayers.Util.applyDefaults(this.params,this.FOLDER_PARAMS):OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS),this.setTileSize(this.defaultSize))},clone:function(a){null==a&&(a=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var b;b=a.getCenterLonLat();var c=this.map.getSize();this.singleTile?(a={setdisplaydpi:OpenLayers.DOTS_PER_INCH,setdisplayheight:c.h*this.ratio,setdisplaywidth:c.w*
-this.ratio,setviewcenterx:b.lon,setviewcentery:b.lat,setviewscale:this.map.getScale()},this.useOverlay&&!this.useAsyncOverlay&&(b={},b=OpenLayers.Util.extend(b,a),b.operation="GETVISIBLEMAPEXTENT",b.version="1.0.0",b.session=this.params.session,b.mapName=this.params.mapName,b.format="text/xml",b=this.getFullRequestString(b),OpenLayers.Request.GET({url:b,async:!1})),b=this.getFullRequestString(a)):(c=this.map.getResolution(),b=Math.floor((a.left-this.maxExtent.left)/c),b=Math.round(b/this.tileSize.w),
-a=Math.floor((this.maxExtent.top-a.top)/c),a=Math.round(a/this.tileSize.h),b=this.useHttpTile?this.getImageFilePath({tilecol:b,tilerow:a,scaleindex:this.resolutions.length-this.map.zoom-1}):this.getFullRequestString({tilecol:b,tilerow:a,scaleindex:this.resolutions.length-this.map.zoom-1}));return b},getFullRequestString:function(a,b){var c=null==b?this.url:b;"object"==typeof c&&(c=c[Math.floor(Math.random()*c.length)]);var d=c,e=OpenLayers.Util.extend({},this.params),e=OpenLayers.Util.extend(e,a),
-f=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),g;for(g in e)g.toUpperCase()in f&&delete e[g];e=OpenLayers.Util.getParameterString(e);e=e.replace(/,/g,"+");""!=e&&(f=c.charAt(c.length-1),d="&"==f||"?"==f?d+e:-1==c.indexOf("?")?d+("?"+e):d+("&"+e));return d},getImageFilePath:function(a,b){var c=null==b?this.url:b;"object"==typeof c&&(c=c[Math.floor(Math.random()*c.length)]);var d="",e="";0>a.tilerow&&(d="-");d=0==a.tilerow?d+"0":d+Math.floor(Math.abs(a.tilerow/this.params.tileRowsPerFolder))*
-this.params.tileRowsPerFolder;0>a.tilecol&&(e="-");e=0==a.tilecol?e+"0":e+Math.floor(Math.abs(a.tilecol/this.params.tileColumnsPerFolder))*this.params.tileColumnsPerFolder;d="/S"+Math.floor(a.scaleindex)+"/"+this.params.basemaplayergroupname+"/R"+d+"/C"+e+"/"+a.tilerow%this.params.tileRowsPerFolder+"_"+a.tilecol%this.params.tileColumnsPerFolder+"."+this.params.format;this.params.querystring&&(d+="?"+this.params.querystring);return c+d},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Control.Measure=OpenLayers.Class(OpenLayers.Control,{callbacks:null,displaySystem:"metric",geodesic:!1,displaySystemUnits:{geographic:["dd"],english:["mi","ft","in"],metric:["km","m"]},partialDelay:300,delayedTrigger:null,persist:!1,immediate:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);var c={done:this.measureComplete,point:this.measurePartial};this.immediate&&(c.modify=this.measureImmediate);this.callbacks=OpenLayers.Util.extend(c,this.callbacks);
-this.handlerOptions=OpenLayers.Util.extend({persist:this.persist},this.handlerOptions);this.handler=new a(this,this.callbacks,this.handlerOptions)},deactivate:function(){this.cancelDelay();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},cancel:function(){this.cancelDelay();this.handler.cancel()},setImmediate:function(a){(this.immediate=a)?this.callbacks.modify=this.measureImmediate:delete this.callbacks.modify},updateHandler:function(a,b){var c=this.active;c&&this.deactivate();
-this.handler=new a(this,this.callbacks,b);c&&this.activate()},measureComplete:function(a){this.cancelDelay();this.measure(a,"measure")},measurePartial:function(a,b){this.cancelDelay();b=b.clone();this.handler.freehandMode(this.handler.evt)?this.measure(b,"measurepartial"):this.delayedTrigger=window.setTimeout(OpenLayers.Function.bind(function(){this.delayedTrigger=null;this.measure(b,"measurepartial")},this),this.partialDelay)},measureImmediate:function(a,b,c){c&&!this.handler.freehandMode(this.handler.evt)&&
-(this.cancelDelay(),this.measure(b.geometry,"measurepartial"))},cancelDelay:function(){null!==this.delayedTrigger&&(window.clearTimeout(this.delayedTrigger),this.delayedTrigger=null)},measure:function(a,b){var c,d;-1<a.CLASS_NAME.indexOf("LineString")?(c=this.getBestLength(a),d=1):(c=this.getBestArea(a),d=2);this.events.triggerEvent(b,{measure:c[0],units:c[1],order:d,geometry:a})},getBestArea:function(a){for(var b=this.displaySystemUnits[this.displaySystem],c,d,e=0,f=b.length;e<f&&!(c=b[e],d=this.getArea(a,
-c),1<d);++e);return[d,c]},getArea:function(a,b){var c,d;this.geodesic?(c=a.getGeodesicArea(this.map.getProjectionObject()),d="m"):(c=a.getArea(),d=this.map.getUnits());var e=OpenLayers.INCHES_PER_UNIT[b];e&&(c*=Math.pow(OpenLayers.INCHES_PER_UNIT[d]/e,2));return c},getBestLength:function(a){for(var b=this.displaySystemUnits[this.displaySystem],c,d,e=0,f=b.length;e<f&&!(c=b[e],d=this.getLength(a,c),1<d);++e);return[d,c]},getLength:function(a,b){var c,d;this.geodesic?(c=a.getGeodesicLength(this.map.getProjectionObject()),
-d="m"):(c=a.getLength(),d=this.map.getUnits());var e=OpenLayers.INCHES_PER_UNIT[b];e&&(c*=OpenLayers.INCHES_PER_UNIT[d]/e);return c},CLASS_NAME:"OpenLayers.Control.Measure"});OpenLayers.Format.WMC.v1_0_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd",initialize:function(a){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[a])},read_wmc_SRS:function(a,b){var c=this.getChildValue(b);"object"!=typeof a.projections&&(a.projections={});for(var c=c.split(/ +/),d=0,e=c.length;d<e;d++)a.projections[c[d]]=!0},write_wmc_Layer:function(a){var b=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,
-[a]);if(a.srs){var c=[],d;for(d in a.srs)c.push(d);b.appendChild(this.createElementDefaultNS("SRS",c.join(" ")))}b.appendChild(this.write_wmc_FormatList(a));b.appendChild(this.write_wmc_StyleList(a));a.dimensions&&b.appendChild(this.write_wmc_DimensionList(a));b.appendChild(this.write_wmc_LayerExtension(a))},CLASS_NAME:"OpenLayers.Format.WMC.v1_0_0"});OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,keepInMap:!0,anchor:null,initialize:function(a,b,c,d,e,f,g){OpenLayers.Popup.prototype.initialize.apply(this,[a,b,c,d,f,g]);this.anchor=null!=e?e:{size:new OpenLayers.Size(0,0),offset:new OpenLayers.Pixel(0,0)}},destroy:function(){this.relativePosition=this.anchor=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments)},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments)},
-moveTo:function(a){var b=this.relativePosition;this.relativePosition=this.calculateRelativePosition(a);OpenLayers.Popup.prototype.moveTo.call(this,this.calculateNewPx(a));this.relativePosition!=b&&this.updateRelativePosition()},setSize:function(a){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if(this.lonlat&&this.map){var b=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(b)}},calculateRelativePosition:function(a){a=this.map.getLonLatFromLayerPx(a);a=this.map.getExtent().determineQuadrant(a);
-return OpenLayers.Bounds.oppositeQuadrant(a)},updateRelativePosition:function(){},calculateNewPx:function(a){a=a.offset(this.anchor.offset);var b=this.size||this.contentSize,c="t"==this.relativePosition.charAt(0);a.y+=c?-b.h:this.anchor.size.h;c="l"==this.relativePosition.charAt(1);a.x+=c?-b.w:this.anchor.size.w;return a},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:!1,positionBlocks:null,blocks:null,fixedRelativePosition:!1,initialize:function(a,b,c,d,e,f,g){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);this.fixedRelativePosition&&(this.updateRelativePosition(),this.calculateRelativePosition=function(a){return this.relativePosition});this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;f&&(this.closeDiv.style.zIndex=
-1);this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%"},destroy:function(){this.isAlphaImage=this.imageSize=this.imageSrc=null;this.fixedRelativePosition=!1;this.positionBlocks=null;for(var a=0;a<this.blocks.length;a++){var b=this.blocks[a];b.image&&b.div.removeChild(b.image);b.image=null;b.div&&this.groupDiv.removeChild(b.div);b.div=null}this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,
-arguments)},setBackgroundColor:function(a){},setBorder:function(){},setOpacity:function(a){},setSize:function(a){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks()},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var a=this.getContentDivPadding();this.closeDiv.style.right=a.right+this.padding.right+"px";this.closeDiv.style.top=a.top+this.padding.top+"px"}this.updateBlocks()},calculateNewPx:function(a){var b=
-OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);return b=b.offset(this.positionBlocks[this.relativePosition].offset)},createBlocks:function(){this.blocks=[];var a=null,b;for(b in this.positionBlocks){a=b;break}a=this.positionBlocks[a];for(b=0;b<a.blocks.length;b++){var c={};this.blocks.push(c);c.div=OpenLayers.Util.createDiv(this.id+"_FrameDecorationDiv_"+b,null,null,null,"absolute",null,"hidden",null);c.image=(this.isAlphaImage?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage)(this.id+
-"_FrameDecorationImg_"+b,null,this.imageSize,this.imageSrc,"absolute",null,null,null);c.div.appendChild(c.image);this.groupDiv.appendChild(c.div)}},updateBlocks:function(){this.blocks||this.createBlocks();if(this.size&&this.relativePosition){for(var a=this.positionBlocks[this.relativePosition],b=0;b<a.blocks.length;b++){var c=a.blocks[b],d=this.blocks[b],e=c.anchor.left,f=c.anchor.bottom,g=c.anchor.right,h=c.anchor.top,k=isNaN(c.size.w)?this.size.w-(g+e):c.size.w,l=isNaN(c.size.h)?this.size.h-(f+
-h):c.size.h;d.div.style.width=(0>k?0:k)+"px";d.div.style.height=(0>l?0:l)+"px";d.div.style.left=null!=e?e+"px":"";d.div.style.bottom=null!=f?f+"px":"";d.div.style.right=null!=g?g+"px":"";d.div.style.top=null!=h?h+"px":"";d.image.style.left=c.position.x+"px";d.image.style.top=c.position.y+"px"}this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px"}},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{contentDisplayClass:"olFramedCloudPopupContent",autoSize:!0,panMapIfOutOfView:!0,imageSize:new OpenLayers.Size(1276,736),isAlphaImage:!1,fixedRelativePosition:!1,positionBlocks:{tl:{offset:new OpenLayers.Pixel(44,0),padding:new OpenLayers.Bounds(8,40,8,9),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,
-50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,18),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-632)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-688)}]},tr:{offset:new OpenLayers.Pixel(-45,0),padding:new OpenLayers.Bounds(8,40,8,9),blocks:[{size:new OpenLayers.Size("auto",
-"auto"),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,19),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-631)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(0,
-0,null,null),position:new OpenLayers.Pixel(-215,-687)}]},bl:{offset:new OpenLayers.Pixel(45,0),padding:new OpenLayers.Bounds(8,9,8,40),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,
-21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},br:{offset:new OpenLayers.Pixel(-44,0),padding:new OpenLayers.Bounds(8,9,8,40),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,
-0)},{size:new OpenLayers.Size("auto",21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(1200,660),initialize:function(a,b,c,d,e,f,g){this.imageSrc=OpenLayers.Util.getImageLocation("cloud-popup-relative.png");
-OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className=this.contentDisplayClass},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Tile.Image.IFrame={useIFrame:null,blankImageUrl:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",draw:function(){if(OpenLayers.Tile.Image.prototype.shouldDraw.call(this)){var a=this.layer.getURL(this.bounds),b=this.useIFrame;this.useIFrame=null!==this.maxGetUrlLength&&!this.layer.async&&a.length>this.maxGetUrlLength;a=b&&!this.useIFrame;b=!b&&this.useIFrame;if(a||b)this.imgDiv&&this.imgDiv.parentNode===this.frame&&this.frame.removeChild(this.imgDiv),this.imgDiv=
-null,a&&this.frame.removeChild(this.frame.firstChild)}return OpenLayers.Tile.Image.prototype.draw.apply(this,arguments)},getImage:function(){if(!0===this.useIFrame){if(!this.frame.childNodes.length){var a=document.createElement("div"),b=a.style;b.position="absolute";b.width="100%";b.height="100%";b.zIndex=1;b.backgroundImage="url("+this.blankImageUrl+")";this.frame.appendChild(a)}a=this.id+"_iFrame";9>parseFloat(navigator.appVersion.split("MSIE")[1])?(b=document.createElement('<iframe name="'+a+'">'),
-b.style.backgroundColor="#FFFFFF",b.style.filter="chroma(color=#FFFFFF)"):(b=document.createElement("iframe"),b.style.backgroundColor="transparent",b.name=a);b.scrolling="no";b.marginWidth="0px";b.marginHeight="0px";b.frameBorder="0";b.style.position="absolute";b.style.width="100%";b.style.height="100%";1>this.layer.opacity&&OpenLayers.Util.modifyDOMElement(b,null,null,null,null,null,null,this.layer.opacity);this.frame.appendChild(b);return this.imgDiv=b}return OpenLayers.Tile.Image.prototype.getImage.apply(this,
-arguments)},createRequestForm:function(){var a=document.createElement("form");a.method="POST";var b=this.layer.params._OLSALT,b=(b?b+"_":"")+this.bounds.toBBOX();a.action=OpenLayers.Util.urlAppend(this.layer.url,b);a.target=this.id+"_iFrame";this.layer.getImageSize();var b=OpenLayers.Util.getParameters(this.url),c,d;for(d in b)c=document.createElement("input"),c.type="hidden",c.name=d,c.value=b[d],a.appendChild(c);return a},setImgSrc:function(a){if(!0===this.useIFrame)if(a){var b=this.createRequestForm();
-this.frame.appendChild(b);b.submit();this.frame.removeChild(b)}else this.imgDiv.parentNode===this.frame&&(this.frame.removeChild(this.imgDiv),this.imgDiv=null);else OpenLayers.Tile.Image.prototype.setImgSrc.apply(this,arguments)},onImageLoad:function(){OpenLayers.Tile.Image.prototype.onImageLoad.apply(this,arguments);!0===this.useIFrame&&(this.imgDiv.style.opacity=1,this.frame.style.opacity=this.layer.opacity)},createBackBuffer:function(){var a;!1===this.useIFrame&&(a=OpenLayers.Tile.Image.prototype.createBackBuffer.call(this));
-return a}};OpenLayers.Format.SOSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.SOSCapabilities"});OpenLayers.Format.SOSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.SOSCapabilities,{namespaces:{ows:"http://www.opengis.net/ows/1.1",sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.options=a},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,
-[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{gml:OpenLayers.Util.applyDefaults({name:function(a,b){b.name=this.getChildValue(a)},TimePeriod:function(a,b){b.timePeriod={};this.readChildNodes(a,b.timePeriod)},beginPosition:function(a,b){b.beginPosition=this.getChildValue(a)},endPosition:function(a,b){b.endPosition=this.getChildValue(a)}},OpenLayers.Format.GML.v3.prototype.readers.gml),sos:{Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,
-b){b.contents={};this.readChildNodes(a,b.contents)},ObservationOfferingList:function(a,b){b.offeringList={};this.readChildNodes(a,b.offeringList)},ObservationOffering:function(a,b){var c=this.getAttributeNS(a,this.namespaces.gml,"id");b[c]={procedures:[],observedProperties:[],featureOfInterestIds:[],responseFormats:[],resultModels:[],responseModes:[]};this.readChildNodes(a,b[c])},time:function(a,b){b.time={};this.readChildNodes(a,b.time)},procedure:function(a,b){b.procedures.push(this.getAttributeNS(a,
-this.namespaces.xlink,"href"))},observedProperty:function(a,b){b.observedProperties.push(this.getAttributeNS(a,this.namespaces.xlink,"href"))},featureOfInterest:function(a,b){b.featureOfInterestIds.push(this.getAttributeNS(a,this.namespaces.xlink,"href"))},responseFormat:function(a,b){b.responseFormats.push(this.getChildValue(a))},resultModel:function(a,b){b.resultModels.push(this.getChildValue(a))},responseMode:function(a,b){b.responseModes.push(this.getChildValue(a))}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},
-CLASS_NAME:"OpenLayers.Format.SOSCapabilities.v1_0_0"});OpenLayers.Handler.Pinch=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!1,pinching:!1,last:null,start:null,touchstart:function(a){var b=!0;this.pinching=!1;if(OpenLayers.Event.isMultiTouch(a))this.started=!0,this.last=this.start={distance:this.getDistance(a.touches),delta:0,scale:1},this.callback("start",[a,this.start]),b=!this.stopDown;else{if(this.started)return!1;this.started=!1;this.last=this.start=null}OpenLayers.Event.preventDefault(a);return b},touchmove:function(a){if(this.started&&
-OpenLayers.Event.isMultiTouch(a)){this.pinching=!0;var b=this.getPinchData(a);this.callback("move",[a,b]);this.last=b;OpenLayers.Event.stop(a)}else if(this.started)return!1;return!0},touchend:function(a){return this.started&&!OpenLayers.Event.isMultiTouch(a)?(this.pinching=this.started=!1,this.callback("done",[a,this.start,this.last]),this.last=this.start=null,!1):!0},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.pinching=!1,a=!0);return a},deactivate:function(){var a=
-!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.pinching=this.started=!1,this.last=this.start=null,a=!0);return a},getDistance:function(a){var b=a[0];a=a[1];return Math.sqrt(Math.pow(b.olClientX-a.olClientX,2)+Math.pow(b.olClientY-a.olClientY,2))},getPinchData:function(a){a=this.getDistance(a.touches);return{distance:a,delta:this.last.distance-a,scale:a/this.start.distance}},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Control.NavToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);this.addControls([new OpenLayers.Control.Navigation,new OpenLayers.Control.ZoomBox])},draw:function(){var a=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);null===this.defaultControl&&(this.defaultControl=this.controls[0]);return a},CLASS_NAME:"OpenLayers.Control.NavToolbar"});OpenLayers.Strategy.Refresh=OpenLayers.Class(OpenLayers.Strategy,{force:!1,interval:0,timer:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);a&&(!0===this.layer.visibility&&this.start(),this.layer.events.on({visibilitychanged:this.reset,scope:this}));return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.stop(),this.layer.events.un({visibilitychanged:this.reset,scope:this}));return a},reset:function(){!0===this.layer.visibility?
-this.start():this.stop()},start:function(){this.interval&&("number"===typeof this.interval&&0<this.interval)&&(this.timer=window.setInterval(OpenLayers.Function.bind(this.refresh,this),this.interval))},refresh:function(){this.layer&&(this.layer.refresh&&"function"==typeof this.layer.refresh)&&this.layer.refresh({force:this.force})},stop:function(){null!==this.timer&&(window.clearInterval(this.timer),this.timer=null)},CLASS_NAME:"OpenLayers.Strategy.Refresh"});OpenLayers.Layer.ArcGIS93Rest=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{format:"png"},isBaseLayer:!0,initialize:function(a,b,c,d){var e=[];c=OpenLayers.Util.upperCaseObject(c);e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()&&(null!=d&&d.isBaseLayer||(this.isBaseLayer=!1),"jpg"==this.params.FORMAT&&
-(this.params.FORMAT=OpenLayers.Util.alphaHack()?"gif":"png"))},clone:function(a){null==a&&(a=new OpenLayers.Layer.ArcGIS93Rest(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);var b=this.projection.getCode().split(":"),b=b[b.length-1],c=this.getImageSize();a={BBOX:a.toBBOX(),SIZE:c.w+","+c.h,F:"image",BBOXSR:b,IMAGESR:b};if(this.layerDefs){var b=[],d;for(d in this.layerDefs)this.layerDefs.hasOwnProperty(d)&&
-this.layerDefs[d]&&(b.push(d),b.push(":"),b.push(this.layerDefs[d]),b.push(";"));0<b.length&&(a.LAYERDEFS=b.join(""))}return this.getFullRequestString(a)},setLayerFilter:function(a,b){this.layerDefs||(this.layerDefs={});b?this.layerDefs[a]=b:delete this.layerDefs[a]},clearLayerFilter:function(a){a?delete this.layerDefs[a]:delete this.layerDefs},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},CLASS_NAME:"OpenLayers.Layer.ArcGIS93Rest"});OpenLayers.Handler.Hover=OpenLayers.Class(OpenLayers.Handler,{delay:500,pixelTolerance:null,stopMove:!1,px:null,timerId:null,mousemove:function(a){this.passesTolerance(a.xy)&&(this.clearTimer(),this.callback("move",[a]),this.px=a.xy,a=OpenLayers.Util.extend({},a),this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,a),this.delay));return!this.stopMove},mouseout:function(a){OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)&&(this.clearTimer(),this.callback("move",[a]));return!0},
-passesTolerance:function(a){var b=!0;this.pixelTolerance&&this.px&&Math.sqrt(Math.pow(this.px.x-a.x,2)+Math.pow(this.px.y-a.y,2))<this.pixelTolerance&&(b=!1);return b},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null)},delayedCall:function(a){this.callback("pause",[a])},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.clearTimer(),a=!0);return a},CLASS_NAME:"OpenLayers.Handler.Hover"});OpenLayers.Control.GetFeature=OpenLayers.Class(OpenLayers.Control,{protocol:null,multipleKey:null,toggleKey:null,modifiers:null,multiple:!1,click:!0,single:!0,clickout:!0,toggle:!1,clickTolerance:5,hover:!1,box:!1,maxFeatures:10,features:null,hoverFeature:null,handlers:null,hoverResponse:null,filterType:OpenLayers.Filter.Spatial.BBOX,initialize:function(a){a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.features={};this.handlers={};this.click&&(this.handlers.click=
-new OpenLayers.Handler.Click(this,{click:this.selectClick},this.handlerOptions.click||{}));this.box&&(this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},OpenLayers.Util.extend(this.handlerOptions.box,{boxDivClassName:"olHandlerBoxSelectFeature"})));this.hover&&(this.handlers.hover=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.selectHover},OpenLayers.Util.extend(this.handlerOptions.hover,{delay:250,pixelTolerance:2})))},activate:function(){if(!this.active)for(var a in this.handlers)this.handlers[a].activate();
-return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){if(this.active)for(var a in this.handlers)this.handlers[a].deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},selectClick:function(a){var b=this.pixelToBounds(a.xy);this.setModifiers(a);this.request(b,{single:this.single})},selectBox:function(a){var b;if(a instanceof OpenLayers.Bounds)b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),a=this.map.getLonLatFromPixel({x:a.right,
-y:a.top}),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);else{if(this.click)return;b=this.pixelToBounds(a)}this.setModifiers(this.handlers.box.dragHandler.evt);this.request(b)},selectHover:function(a){a=this.pixelToBounds(a.xy);this.request(a,{single:!0,hover:!0})},cancelHover:function(){this.hoverResponse&&(this.protocol.abort(this.hoverResponse),this.hoverResponse=null,OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"))},request:function(a,b){b=b||{};var c=new OpenLayers.Filter.Spatial({type:this.filterType,
-value:a});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");c=this.protocol.read({maxFeatures:!0==b.single?this.maxFeatures:void 0,filter:c,callback:function(c){c.success()&&(c.features.length?!0==b.single?this.selectBestFeature(c.features,a.getCenterLonLat(),b):this.select(c.features):b.hover?this.hoverSelect():(this.events.triggerEvent("clickout"),this.clickout&&this.unselectAll()));OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait")},scope:this});!0==b.hover&&(this.hoverResponse=
-c)},selectBestFeature:function(a,b,c){c=c||{};if(a.length){b=new OpenLayers.Geometry.Point(b.lon,b.lat);for(var d,e,f,g=Number.MAX_VALUE,h=0;h<a.length&&!(d=a[h],d.geometry&&(f=b.distanceTo(d.geometry,{edge:!1}),f<g&&(g=f,e=d,0==g)));++h);!0==c.hover?this.hoverSelect(e):this.select(e||a)}},setModifiers:function(a){this.modifiers={multiple:this.multiple||this.multipleKey&&a[this.multipleKey],toggle:this.toggle||this.toggleKey&&a[this.toggleKey]}},select:function(a){this.modifiers.multiple||this.modifiers.toggle||
-this.unselectAll();OpenLayers.Util.isArray(a)||(a=[a]);var b=this.events.triggerEvent("beforefeaturesselected",{features:a});if(!1!==b){for(var c=[],d,e=0,f=a.length;e<f;++e)d=a[e],this.features[d.fid||d.id]?this.modifiers.toggle&&this.unselect(this.features[d.fid||d.id]):(b=this.events.triggerEvent("beforefeatureselected",{feature:d}),!1!==b&&(this.features[d.fid||d.id]=d,c.push(d),this.events.triggerEvent("featureselected",{feature:d})));this.events.triggerEvent("featuresselected",{features:c})}},
-hoverSelect:function(a){var b=a?a.fid||a.id:null,c=this.hoverFeature?this.hoverFeature.fid||this.hoverFeature.id:null;c&&c!=b&&(this.events.triggerEvent("outfeature",{feature:this.hoverFeature}),this.hoverFeature=null);b&&b!=c&&(this.events.triggerEvent("hoverfeature",{feature:a}),this.hoverFeature=a)},unselect:function(a){delete this.features[a.fid||a.id];this.events.triggerEvent("featureunselected",{feature:a})},unselectAll:function(){for(var a in this.features)this.unselect(this.features[a])},
-setMap:function(a){for(var b in this.handlers)this.handlers[b].setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},pixelToBounds:function(a){var b=a.add(-this.clickTolerance/2,this.clickTolerance/2);a=a.add(this.clickTolerance/2,-this.clickTolerance/2);b=this.map.getLonLatFromPixel(b);a=this.map.getLonLatFromPixel(a);return new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat)},CLASS_NAME:"OpenLayers.Control.GetFeature"});OpenLayers.Format.QueryStringFilter=function(){function a(a){a=a.replace(/%/g,"\\%");a=a.replace(/\\\\\.(\*)?/g,function(a,b){return b?a:"\\\\_"});a=a.replace(/\\\\\.\*/g,"\\\\%");a=a.replace(/(\\)?\.(\*)?/g,function(a,b,c){return b||c?a:"_"});a=a.replace(/(\\)?\.\*/g,function(a,b){return b?a:"%"});a=a.replace(/\\\./g,".");return a=a.replace(/(\\)?\\\*/g,function(a,b){return b?a:"*"})}var b={};b[OpenLayers.Filter.Comparison.EQUAL_TO]="eq";b[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]="ne";b[OpenLayers.Filter.Comparison.LESS_THAN]=
-"lt";b[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]="lte";b[OpenLayers.Filter.Comparison.GREATER_THAN]="gt";b[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO]="gte";b[OpenLayers.Filter.Comparison.LIKE]="ilike";return OpenLayers.Class(OpenLayers.Format,{wildcarded:!1,srsInBBOX:!1,write:function(c,d){d=d||{};var e=c.CLASS_NAME,e=e.substring(e.lastIndexOf(".")+1);switch(e){case "Spatial":switch(c.type){case OpenLayers.Filter.Spatial.BBOX:d.bbox=c.value.toArray();this.srsInBBOX&&c.projection&&
-d.bbox.push(c.projection.getCode());break;case OpenLayers.Filter.Spatial.DWITHIN:d.tolerance=c.distance;case OpenLayers.Filter.Spatial.WITHIN:d.lon=c.value.x;d.lat=c.value.y;break;default:OpenLayers.Console.warn("Unknown spatial filter type "+c.type)}break;case "Comparison":e=b[c.type];if(void 0!==e){var f=c.value;c.type==OpenLayers.Filter.Comparison.LIKE&&(f=a(f),this.wildcarded&&(f="%"+f+"%"));d[c.property+"__"+e]=f;d.queryable=d.queryable||[];d.queryable.push(c.property)}else OpenLayers.Console.warn("Unknown comparison filter type "+
-c.type);break;case "Logical":if(c.type===OpenLayers.Filter.Logical.AND)for(e=0,f=c.filters.length;e<f;e++)d=this.write(c.filters[e],d);else OpenLayers.Console.warn("Unsupported logical filter type "+c.type);break;default:OpenLayers.Console.warn("Unknown filter type "+e)}return d},CLASS_NAME:"OpenLayers.Format.QueryStringFilter"})}();OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,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(){return 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(),!0):!1},deactivate:function(){return 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="",!0):!1},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||(this.div.left="",this.div.top="",this.element=this.div);return this.div},redraw:function(a){var b;if(null==a)this.reset();else if(null==this.lastXy||Math.abs(a.xy.x-
-this.lastXy.x)>this.granularity||Math.abs(a.xy.y-this.lastXy.y)>this.granularity)this.lastXy=a.xy;else if(b=this.map.getLonLatFromPixel(a.xy))this.displayProjection&&b.transform(this.map.getProjectionObject(),this.displayProjection),this.lastXy=a.xy,a=this.formatOutput(b),a!=this.element.innerHTML&&(this.element.innerHTML=a)},reset:function(a){null!=this.emptyString&&(this.element.innerHTML=this.emptyString)},formatOutput:function(a){var b=parseInt(this.numDigits);return this.prefix+a.lon.toFixed(b)+
-this.separator+a.lat.toFixed(b)+this.suffix},CLASS_NAME:"OpenLayers.Control.MousePosition"});OpenLayers.Control.Geolocate=OpenLayers.Class(OpenLayers.Control,{geolocation:null,available:"geolocation"in navigator,bind:!0,watch:!1,geolocationOptions:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.available&&!this.geolocation&&(this.geolocation=navigator.geolocation);return this.geolocation?OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.watch?this.watchId=this.geolocation.watchPosition(OpenLayers.Function.bind(this.geolocate,
-this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions):this.getCurrentLocation(),!0):!1:(this.events.triggerEvent("locationuncapable"),!1)},deactivate:function(){this.active&&null!==this.watchId&&this.geolocation.clearWatch(this.watchId);return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},geolocate:function(a){var b=(new OpenLayers.LonLat(a.coords.longitude,a.coords.latitude)).transform(new OpenLayers.Projection("EPSG:4326"),this.map.getProjectionObject());this.bind&&
-this.map.setCenter(b);this.events.triggerEvent("locationupdated",{position:a,point:new OpenLayers.Geometry.Point(b.lon,b.lat)})},getCurrentLocation:function(){if(!this.active||this.watch)return!1;this.geolocation.getCurrentPosition(OpenLayers.Function.bind(this.geolocate,this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions);return!0},failure:function(a){this.events.triggerEvent("locationfailed",{error:a})},CLASS_NAME:"OpenLayers.Control.Geolocate"});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 a=OpenLayers.Tile.prototype.draw.apply(this,arguments);if(a)if(this.isLoading?(this.abortLoading(),this.events.triggerEvent("reload")):(this.isLoading=!0,this.events.triggerEvent("loadstart")),this.url=this.layer.getURL(this.bounds),this.layer.useJSONP){var b=new OpenLayers.Protocol.Script({url:this.url,
-callback:function(a){this.isLoading=!1;this.events.triggerEvent("loadend");this.json=a.data},scope:this});b.read();this.request=b}else this.request=OpenLayers.Request.GET({url:this.url,callback:function(a){this.isLoading=!1;this.events.triggerEvent("loadend");200===a.status&&this.parseData(a.responseText)},scope:this});else this.unload();return a},abortLoading:function(){this.request&&(this.request.abort(),delete this.request);this.isLoading=!1},getFeatureInfo:function(a,b){var c=null;if(this.json){var d=
-this.getFeatureId(a,b);null!==d&&(c={id:d,data:this.json.data[d]})}return c},getFeatureId:function(a,b){var c=null;if(this.json){var d=this.utfgridResolution,d=this.json.grid[Math.floor(b/d)].charCodeAt(Math.floor(a/d)),d=this.indexFromCharCode(d),e=this.json.keys;!isNaN(d)&&d in e&&(c=e[d])}return c},indexFromCharCode:function(a){93<=a&&a--;35<=a&&a--;return a-32},parseData:function(a){this.format||(this.format=new OpenLayers.Format.JSON);this.json=this.format.read(a)},clear:function(){this.json=
-null},CLASS_NAME:"OpenLayers.Tile.UTFGrid"});OpenLayers.Protocol.HTTP=OpenLayers.Class(OpenLayers.Protocol,{url:null,headers:null,params:null,callback:null,scope:null,readWithPOST:!1,updateWithPOST:!1,deleteWithPOST:!1,wildcarded:!1,srsInBBOX:!1,initialize:function(a){a=a||{};this.params={};this.headers={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var b=new OpenLayers.Format.QueryStringFilter({wildcarded:this.wildcarded,srsInBBOX:this.srsInBBOX});this.filterToParams=
-function(a,d){return b.write(a,d)}}},destroy:function(){this.headers=this.params=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=a||{};a.params=OpenLayers.Util.applyDefaults(a.params,this.options.params);a=OpenLayers.Util.applyDefaults(a,this.options);a.filter&&this.filterToParams&&(a.params=this.filterToParams(a.filter,a.params));var b=void 0!==a.readWithPOST?a.readWithPOST:this.readWithPOST,c=new OpenLayers.Protocol.Response({requestType:"read"});
-b?(b=a.headers||{},b["Content-Type"]="application/x-www-form-urlencoded",c.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,c,a),data:OpenLayers.Util.getParameterString(a.params),headers:b})):c.priv=OpenLayers.Request.GET({url:a.url,callback:this.createCallback(this.handleRead,c,a),params:a.params,headers:a.headers});return c},handleRead:function(a,b){this.handleResponse(a,b)},create:function(a,b){b=OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({reqFeatures:a,
-requestType:"create"});c.priv=OpenLayers.Request.POST({url:b.url,callback:this.createCallback(this.handleCreate,c,b),headers:b.headers,data:this.format.write(a)});return c},handleCreate:function(a,b){this.handleResponse(a,b)},update:function(a,b){b=b||{};var c=b.url||a.url||this.options.url+"/"+a.fid;b=OpenLayers.Util.applyDefaults(b,this.options);var d=new OpenLayers.Protocol.Response({reqFeatures:a,requestType:"update"});d.priv=OpenLayers.Request[this.updateWithPOST?"POST":"PUT"]({url:c,callback:this.createCallback(this.handleUpdate,
-d,b),headers:b.headers,data:this.format.write(a)});return d},handleUpdate:function(a,b){this.handleResponse(a,b)},"delete":function(a,b){b=b||{};var c=b.url||a.url||this.options.url+"/"+a.fid;b=OpenLayers.Util.applyDefaults(b,this.options);var d=new OpenLayers.Protocol.Response({reqFeatures:a,requestType:"delete"}),e=this.deleteWithPOST?"POST":"DELETE",c={url:c,callback:this.createCallback(this.handleDelete,d,b),headers:b.headers};this.deleteWithPOST&&(c.data=this.format.write(a));d.priv=OpenLayers.Request[e](c);
-return d},handleDelete:function(a,b){this.handleResponse(a,b)},handleResponse:function(a,b){var c=a.priv;b.callback&&(200<=c.status&&300>c.status?("delete"!=a.requestType&&(a.features=this.parseFeatures(c)),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE,b.callback.call(b.scope,a))},parseFeatures:function(a){var b=a.responseXML;b&&b.documentElement||(b=a.responseText);return!b||0>=b.length?null:this.format.read(b)},commit:function(a,b){function c(a){for(var b=
-a.features?a.features.length:0,c=Array(b),e=0;e<b;++e)c[e]=a.features[e].fid;r.insertIds=c;d.apply(this,[a])}function d(a){this.callUserCallback(a,b);q=q&&a.success();f++;f>=p&&b.callback&&(r.code=q?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE,b.callback.apply(b.scope,[r]))}b=OpenLayers.Util.applyDefaults(b,this.options);var e=[],f=0,g={};g[OpenLayers.State.INSERT]=[];g[OpenLayers.State.UPDATE]=[];g[OpenLayers.State.DELETE]=[];for(var h,k,l=[],m=0,n=a.length;m<n;++m)if(h=
-a[m],k=g[h.state])k.push(h),l.push(h);var p=(0<g[OpenLayers.State.INSERT].length?1:0)+g[OpenLayers.State.UPDATE].length+g[OpenLayers.State.DELETE].length,q=!0,r=new OpenLayers.Protocol.Response({reqFeatures:l});h=g[OpenLayers.State.INSERT];0<h.length&&e.push(this.create(h,OpenLayers.Util.applyDefaults({callback:c,scope:this},b.create)));h=g[OpenLayers.State.UPDATE];for(m=h.length-1;0<=m;--m)e.push(this.update(h[m],OpenLayers.Util.applyDefaults({callback:d,scope:this},b.update)));h=g[OpenLayers.State.DELETE];
-for(m=h.length-1;0<=m;--m)e.push(this["delete"](h[m],OpenLayers.Util.applyDefaults({callback:d,scope:this},b["delete"])));return e},abort:function(a){a&&a.priv.abort()},callUserCallback:function(a,b){var c=b[a.requestType];c&&c.callback&&c.callback.call(c.scope,a)},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.Strategy.Cluster=OpenLayers.Class(OpenLayers.Strategy,{distance:20,threshold:null,features:null,clusters:null,clustering:!1,resolution:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a)this.layer.events.on({beforefeaturesadded:this.cacheFeatures,featuresremoved:this.clearCache,moveend:this.cluster,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.clearCache(),this.layer.events.un({beforefeaturesadded:this.cacheFeatures,
-featuresremoved:this.clearCache,moveend:this.cluster,scope:this}));return a},cacheFeatures:function(a){var b=!0;this.clustering||(this.clearCache(),this.features=a.features,this.cluster(),b=!1);return b},clearCache:function(){this.clustering||(this.features=null)},cluster:function(a){if((!a||a.zoomChanged)&&this.features&&(a=this.layer.map.getResolution(),a!=this.resolution||!this.clustersExist())){this.resolution=a;a=[];for(var b,c,d,e=0;e<this.features.length;++e)if(b=this.features[e],b.geometry){c=
-!1;for(var f=a.length-1;0<=f;--f)if(d=a[f],this.shouldCluster(d,b)){this.addToCluster(d,b);c=!0;break}c||a.push(this.createCluster(this.features[e]))}this.clustering=!0;this.layer.removeAllFeatures();this.clustering=!1;if(0<a.length){if(1<this.threshold)for(b=a.slice(),a=[],e=0,d=b.length;e<d;++e)c=b[e],c.attributes.count<this.threshold?Array.prototype.push.apply(a,c.cluster):a.push(c);this.clustering=!0;this.layer.addFeatures(a);this.clustering=!1}this.clusters=a}},clustersExist:function(){var a=
-!1;if(this.clusters&&0<this.clusters.length&&this.clusters.length==this.layer.features.length)for(var a=!0,b=0;b<this.clusters.length;++b)if(this.clusters[b]!=this.layer.features[b]){a=!1;break}return a},shouldCluster:function(a,b){var c=a.geometry.getBounds().getCenterLonLat(),d=b.geometry.getBounds().getCenterLonLat();return Math.sqrt(Math.pow(c.lon-d.lon,2)+Math.pow(c.lat-d.lat,2))/this.resolution<=this.distance},addToCluster:function(a,b){a.cluster.push(b);a.attributes.count+=1},createCluster:function(a){var b=
-a.geometry.getBounds().getCenterLonLat(),b=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(b.lon,b.lat),{count:1});b.cluster=[a];return b},CLASS_NAME:"OpenLayers.Strategy.Cluster"});OpenLayers.Strategy.Filter=OpenLayers.Class(OpenLayers.Strategy,{filter:null,cache:null,caching:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.apply(this,arguments);a&&(this.cache=[],this.layer.events.on({beforefeaturesadded:this.handleAdd,beforefeaturesremoved:this.handleRemove,scope:this}));return a},deactivate:function(){this.cache=null;this.layer&&this.layer.events&&this.layer.events.un({beforefeaturesadded:this.handleAdd,beforefeaturesremoved:this.handleRemove,scope:this});
-return OpenLayers.Strategy.prototype.deactivate.apply(this,arguments)},handleAdd:function(a){if(!this.caching&&this.filter){var b=a.features;a.features=[];for(var c,d=0,e=b.length;d<e;++d)c=b[d],this.filter.evaluate(c)?a.features.push(c):this.cache.push(c)}},handleRemove:function(a){this.caching||(this.cache=[])},setFilter:function(a){this.filter=a;a=this.cache;this.cache=[];this.handleAdd({features:this.layer.features});0<this.cache.length&&(this.caching=!0,this.layer.removeFeatures(this.cache.slice()),
-this.caching=!1);0<a.length&&(a={features:a},this.handleAdd(a),0<a.features.length&&(this.caching=!0,this.layer.addFeatures(a.features),this.caching=!1))},CLASS_NAME:"OpenLayers.Strategy.Filter"});OpenLayers.Protocol.SOS=function(a){a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.SOS.DEFAULTS);var b=OpenLayers.Protocol.SOS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported SOS version: "+a.version;return new b(a)};OpenLayers.Protocol.SOS.DEFAULTS={version:"1.0.0"};OpenLayers.Format.WFSDescribeFeatureType=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g},namespaces:{xsd:"http://www.w3.org/2001/XMLSchema"},readers:{xsd:{schema:function(a,b){var c=[],d={},e,f;this.readChildNodes(a,{complexTypes:c,customTypes:d});var g=a.attributes,h,k;e=0;for(f=g.length;e<f;++e)h=g[e],k=h.name,0===k.indexOf("xmlns")?this.setNamespace(k.split(":")[1]||"",h.value):b[k]=h.value;b.featureTypes=c;b.targetPrefix=this.namespaceAlias[b.targetNamespace];e=0;for(f=
-c.length;e<f;++e)g=c[e],h=d[g.typeName],d[g.typeName]&&(g.typeName=h.name)},complexType:function(a,b){var c={typeName:a.getAttribute("name")};this.readChildNodes(a,c);b.complexTypes.push(c)},complexContent:function(a,b){this.readChildNodes(a,b)},extension:function(a,b){this.readChildNodes(a,b)},sequence:function(a,b){var c={elements:[]};this.readChildNodes(a,c);b.properties=c.elements},element:function(a,b){var c;if(b.elements){var d={};c=a.attributes;for(var e,f=0,g=c.length;f<g;++f)e=c[f],d[e.name]=
-e.value;c=d.type;c||(c={},this.readChildNodes(a,c),d.restriction=c,d.type=c.base);d.localType=(c.base||c).split(":").pop();b.elements.push(d);this.readChildNodes(a,d)}b.complexTypes&&(c=a.getAttribute("type"),d=c.split(":").pop(),b.customTypes[d]={name:a.getAttribute("name"),type:c})},annotation:function(a,b){b.annotation={};this.readChildNodes(a,b.annotation)},appinfo:function(a,b){b.appinfo||(b.appinfo=[]);b.appinfo.push(this.getChildValue(a))},documentation:function(a,b){b.documentation||(b.documentation=
-[]);var c=this.getChildValue(a);b.documentation.push({lang:a.getAttribute("xml:lang"),textContent:c.replace(this.regExes.trimSpace,"")})},simpleType:function(a,b){this.readChildNodes(a,b)},restriction:function(a,b){b.base=a.getAttribute("base");this.readRestriction(a,b)}}},readRestriction:function(a,b){for(var c=a.childNodes,d,e,f=0,g=c.length;f<g;++f)d=c[f],1==d.nodeType&&(e=d.nodeName.split(":").pop(),d=d.getAttribute("value"),b[e]?("string"==typeof b[e]&&(b[e]=[b[e]]),b[e].push(d)):b[e]=d)},read:function(a){"string"==
-typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};if("ExceptionReport"===a.nodeName.split(":").pop()){var c=new OpenLayers.Format.OGCExceptionReport;b.error=c.read(a)}else this.readNode(a,b);return b},CLASS_NAME:"OpenLayers.Format.WFSDescribeFeatureType"});OpenLayers.Format.GeoRSS=OpenLayers.Class(OpenLayers.Format.XML,{rssns:"http://backend.userland.com/rss2",featureNS:"http://mapserver.gis.umn.edu/mapserver",georssns:"http://www.georss.org/georss",geons:"http://www.w3.org/2003/01/geo/wgs84_pos#",featureTitle:"Untitled",featureDescription:"No Description",gmlParser:null,xy:!1,createGeometryFromItem:function(a){var b=this.getElementsByTagNameNS(a,this.georssns,"point"),c=this.getElementsByTagNameNS(a,this.geons,"lat"),d=this.getElementsByTagNameNS(a,
-this.geons,"long"),e=this.getElementsByTagNameNS(a,this.georssns,"line"),f=this.getElementsByTagNameNS(a,this.georssns,"polygon"),g=this.getElementsByTagNameNS(a,this.georssns,"where");a=this.getElementsByTagNameNS(a,this.georssns,"box");if(0<b.length||0<c.length&&0<d.length){0<b.length?(c=OpenLayers.String.trim(b[0].firstChild.nodeValue).split(/\s+/),2!=c.length&&(c=OpenLayers.String.trim(b[0].firstChild.nodeValue).split(/\s*,\s*/))):c=[parseFloat(c[0].firstChild.nodeValue),parseFloat(d[0].firstChild.nodeValue)];
-var h=new OpenLayers.Geometry.Point(c[1],c[0])}else if(0<e.length){c=OpenLayers.String.trim(this.getChildValue(e[0])).split(/\s+/);d=[];e=0;for(f=c.length;e<f;e+=2)b=new OpenLayers.Geometry.Point(c[e+1],c[e]),d.push(b);h=new OpenLayers.Geometry.LineString(d)}else if(0<f.length){c=OpenLayers.String.trim(this.getChildValue(f[0])).split(/\s+/);d=[];e=0;for(f=c.length;e<f;e+=2)b=new OpenLayers.Geometry.Point(c[e+1],c[e]),d.push(b);h=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)])}else 0<
-g.length?(this.gmlParser||(this.gmlParser=new OpenLayers.Format.GML({xy:this.xy})),h=this.gmlParser.parseFeature(g[0]).geometry):0<a.length&&(c=OpenLayers.String.trim(a[0].firstChild.nodeValue).split(/\s+/),d=[],3<c.length&&(b=new OpenLayers.Geometry.Point(c[1],c[0]),d.push(b),b=new OpenLayers.Geometry.Point(c[1],c[2]),d.push(b),b=new OpenLayers.Geometry.Point(c[3],c[2]),d.push(b),b=new OpenLayers.Geometry.Point(c[3],c[0]),d.push(b),b=new OpenLayers.Geometry.Point(c[1],c[0]),d.push(b)),h=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)]));
-h&&(this.internalProjection&&this.externalProjection)&&h.transform(this.externalProjection,this.internalProjection);return h},createFeatureFromItem:function(a){var b=this.createGeometryFromItem(a),c=this._getChildValue(a,"*","title",this.featureTitle),d=this._getChildValue(a,"*","description",this._getChildValue(a,"*","content",this._getChildValue(a,"*","summary",this.featureDescription))),e=this._getChildValue(a,"*","link");if(!e)try{e=this.getElementsByTagNameNS(a,"*","link")[0].getAttribute("href")}catch(f){e=
-null}a=this._getChildValue(a,"*","id",null);b=new OpenLayers.Feature.Vector(b,{title:c,description:d,link:e});b.fid=a;return b},_getChildValue:function(a,b,c,d){return(a=this.getElementsByTagNameNS(a,b,c))&&a[0]&&a[0].firstChild&&a[0].firstChild.nodeValue?this.getChildValue(a[0]):void 0==d?"":d},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=null,b=this.getElementsByTagNameNS(a,"*","item");0==b.length&&(b=this.getElementsByTagNameNS(a,"*","entry"));
-a=b.length;for(var c=Array(a),d=0;d<a;d++)c[d]=this.createFeatureFromItem(b[d]);return c},write:function(a){var b;if(OpenLayers.Util.isArray(a)){b=this.createElementNS(this.rssns,"rss");for(var c=0,d=a.length;c<d;c++)b.appendChild(this.createFeatureXML(a[c]))}else b=this.createFeatureXML(a);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.rssns,"item"),d=this.createElementNS(this.rssns,"title");
-d.appendChild(this.createTextNode(a.attributes.title?a.attributes.title:""));var e=this.createElementNS(this.rssns,"description");e.appendChild(this.createTextNode(a.attributes.description?a.attributes.description:""));c.appendChild(d);c.appendChild(e);a.attributes.link&&(d=this.createElementNS(this.rssns,"link"),d.appendChild(this.createTextNode(a.attributes.link)),c.appendChild(d));for(var f in a.attributes)"link"!=f&&("title"!=f&&"description"!=f)&&(d=this.createTextNode(a.attributes[f]),e=f,-1!=
-f.search(":")&&(e=f.split(":")[1]),e=this.createElementNS(this.featureNS,"feature:"+e),e.appendChild(d),c.appendChild(e));c.appendChild(b);return c},buildGeometryNode:function(a){this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b;if("OpenLayers.Geometry.Polygon"==a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:polygon"),b.appendChild(this.buildCoordinatesNode(a.components[0]));else if("OpenLayers.Geometry.LineString"==
-a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:line"),b.appendChild(this.buildCoordinatesNode(a));else if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:point"),b.appendChild(this.buildCoordinatesNode(a));else throw"Couldn't parse "+a.CLASS_NAME;return b},buildCoordinatesNode:function(a){var b=null;a.components&&(b=a.components);if(b){a=b.length;for(var c=Array(a),d=0;d<a;d++)c[d]=b[d].y+" "+b[d].x;b=c.join(" ")}else b=a.y+" "+a.x;return this.createTextNode(b)},
-CLASS_NAME:"OpenLayers.Format.GeoRSS"});OpenLayers.Format.WPSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.WPSCapabilities"});OpenLayers.Format.WPSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",wps:"http://www.opengis.net/wps/1.0.0",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);
-var b={};this.readNode(a,b);return b},readers:{wps:{Capabilities:function(a,b){this.readChildNodes(a,b)},ProcessOfferings:function(a,b){b.processOfferings={};this.readChildNodes(a,b.processOfferings)},Process:function(a,b){var c={processVersion:this.getAttributeNS(a,this.namespaces.wps,"processVersion")};this.readChildNodes(a,c);b[c.identifier]=c},Languages:function(a,b){b.languages=[];this.readChildNodes(a,b.languages)},Default:function(a,b){var c={isDefault:!0};this.readChildNodes(a,c);b.push(c)},
-Supported:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSCapabilities.v1_0_0"});OpenLayers.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,pinchOrigin:null,currentCenter:null,autoActivate:!0,preserveCenter:!1,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions)},pinchStart:function(a,b){var c=this.preserveCenter?this.map.getPixelFromLonLat(this.map.getCenter()):a.xy;this.currentCenter=
-this.pinchOrigin=c},pinchMove:function(a,b){var c=b.scale,d=this.map.layerContainerOriginPx,e=this.pinchOrigin,f=this.preserveCenter?this.map.getPixelFromLonLat(this.map.getCenter()):a.xy,g=Math.round(d.x+f.x-e.x+(c-1)*(d.x-e.x)),d=Math.round(d.y+f.y-e.y+(c-1)*(d.y-e.y));this.map.applyTransform(g,d,c);this.currentCenter=f},pinchDone:function(a,b,c){this.map.applyTransform();a=this.map.getZoomForResolution(this.map.getResolution()/c.scale,!0);if(a!==this.map.getZoom()||!this.currentCenter.equals(this.pinchOrigin)){b=
-this.map.getResolutionForZoom(a);c=this.map.getLonLatFromPixel(this.pinchOrigin);var d=this.currentCenter,e=this.map.getSize();c.lon+=b*(e.w/2-d.x);c.lat-=b*(e.h/2-d.y);this.map.div.clientWidth=this.map.div.clientWidth;this.map.setCenter(c,a)}},CLASS_NAME:"OpenLayers.Control.PinchZoom"});OpenLayers.Control.TouchNavigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,clickHandlerOptions:null,documentDrag:!1,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null;this.pinchZoom&&(this.pinchZoom.destroy(),delete this.pinchZoom);OpenLayers.Control.prototype.destroy.apply(this,
-arguments)},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.dragPan.activate(),this.handlers.click.activate(),this.pinchZoom.activate(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments)?(this.dragPan.deactivate(),this.handlers.click.deactivate(),this.pinchZoom.deactivate(),!0):!1},draw:function(){var a={click:this.defaultClick,dblclick:this.defaultDblClick},b=OpenLayers.Util.extend({"double":!0,stopDouble:!0,
-pixelTolerance:2},this.clickHandlerOptions);this.handlers.click=new OpenLayers.Handler.Click(this,a,b);this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,documentDrag:this.documentDrag},this.dragPanOptions));this.dragPan.draw();this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&&this.map.zoomOut()},defaultDblClick:function(a){this.map.zoomTo(this.map.zoom+
-1,a.xy)},CLASS_NAME:"OpenLayers.Control.TouchNavigation"});OpenLayers.Console.warn("OpenLayers.Rico is deprecated");OpenLayers.Rico=OpenLayers.Rico||{};
-OpenLayers.Rico.Color=OpenLayers.Class({initialize:function(a,b,c){this.rgb={r:a,g:b,b:c}},setRed:function(a){this.rgb.r=a},setGreen:function(a){this.rgb.g=a},setBlue:function(a){this.rgb.b=a},setHue:function(a){var b=this.asHSB();b.h=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setSaturation:function(a){var b=this.asHSB();b.s=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setBrightness:function(a){var b=this.asHSB();b.b=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},
-darken:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.max(b.b-a,0))},brighten:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.min(b.b+a,1))},blend:function(a){this.rgb.r=Math.floor((this.rgb.r+a.rgb.r)/2);this.rgb.g=Math.floor((this.rgb.g+a.rgb.g)/2);this.rgb.b=Math.floor((this.rgb.b+a.rgb.b)/2)},isBright:function(){this.asHSB();return 0.5<this.asHSB().b},isDark:function(){return!this.isBright()},asRGB:function(){return"rgb("+
-this.rgb.r+","+this.rgb.g+","+this.rgb.b+")"},asHex:function(){return"#"+this.rgb.r.toColorPart()+this.rgb.g.toColorPart()+this.rgb.b.toColorPart()},asHSB:function(){return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r,this.rgb.g,this.rgb.b)},toString:function(){return this.asHex()}});
-OpenLayers.Rico.Color.createFromHex=function(a){if(4==a.length){var b=a;a="#";for(var c=1;4>c;c++)a+=b.charAt(c)+b.charAt(c)}0==a.indexOf("#")&&(a=a.substring(1));b=a.substring(0,2);c=a.substring(2,4);a=a.substring(4,6);return new OpenLayers.Rico.Color(parseInt(b,16),parseInt(c,16),parseInt(a,16))};
-OpenLayers.Rico.Color.createColorFromBackground=function(a){var b=OpenLayers.Element.getStyle(OpenLayers.Util.getElement(a),"backgroundColor");return"transparent"==b&&a.parentNode?OpenLayers.Rico.Color.createColorFromBackground(a.parentNode):null==b?new OpenLayers.Rico.Color(255,255,255):0==b.indexOf("rgb(")?(a=b.substring(4,b.length-1).split(","),new OpenLayers.Rico.Color(parseInt(a[0]),parseInt(a[1]),parseInt(a[2]))):0==b.indexOf("#")?OpenLayers.Rico.Color.createFromHex(b):new OpenLayers.Rico.Color(255,
-255,255)};
-OpenLayers.Rico.Color.HSBtoRGB=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=parseInt(255*c+0.5);else{a=6*(a-Math.floor(a));var g=a-Math.floor(a),h=c*(1-b),k=c*(1-b*g);b=c*(1-b*(1-g));switch(parseInt(a)){case 0:d=255*c+0.5;e=255*b+0.5;f=255*h+0.5;break;case 1:d=255*k+0.5;e=255*c+0.5;f=255*h+0.5;break;case 2:d=255*h+0.5;e=255*c+0.5;f=255*b+0.5;break;case 3:d=255*h+0.5;e=255*k+0.5;f=255*c+0.5;break;case 4:d=255*b+0.5;e=255*h+0.5;f=255*c+0.5;break;case 5:d=255*c+0.5,e=255*h+0.5,f=255*k+0.5}}return{r:parseInt(d),g:parseInt(e),
-b:parseInt(f)}};OpenLayers.Rico.Color.RGBtoHSB=function(a,b,c){var d,e=a>b?a:b;c>e&&(e=c);var f=a<b?a:b;c<f&&(f=c);d=0!=e?(e-f)/e:0;if(0==d)a=0;else{var g=(e-a)/(e-f),h=(e-b)/(e-f);c=(e-c)/(e-f);a=(a==e?c-h:b==e?2+g-c:4+h-g)/6;0>a&&(a+=1)}return{h:a,s:d,b:e/255}};OpenLayers.Style2=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;a<b;a++)this.rules[a].destroy();delete this.rules},clone:function(){var a=OpenLayers.Util.extend({},this);if(this.rules){a.rules=[];for(var b=0,c=this.rules.length;b<c;++b)a.rules.push(this.rules[b].clone())}return new OpenLayers.Style2(a)},
-CLASS_NAME:"OpenLayers.Style2"});OpenLayers.Format.WFS=OpenLayers.Class(OpenLayers.Format.GML,{layer:null,wfsns:"http://www.opengis.net/wfs",ogcns:"http://www.opengis.net/ogc",initialize:function(a,b){OpenLayers.Format.GML.prototype.initialize.apply(this,[a]);this.layer=b;this.layer.featureNS&&(this.featureNS=this.layer.featureNS);this.layer.options.geometry_column&&(this.geometryName=this.layer.options.geometry_column);this.layer.options.typename&&(this.featureName=this.layer.options.typename)},write:function(a){var b=this.createElementNS(this.wfsns,
-"wfs:Transaction");b.setAttribute("version","1.0.0");b.setAttribute("service","WFS");for(var c=0;c<a.length;c++)switch(a[c].state){case OpenLayers.State.INSERT:b.appendChild(this.insert(a[c]));break;case OpenLayers.State.UPDATE:b.appendChild(this.update(a[c]));break;case OpenLayers.State.DELETE:b.appendChild(this.remove(a[c]))}return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.featureNS,"feature:"+
-this.geometryName);c.appendChild(b);b=this.createElementNS(this.featureNS,"feature:"+this.featureName);b.appendChild(c);for(var d in a.attributes){var c=this.createTextNode(a.attributes[d]),e=d;-1!=d.search(":")&&(e=d.split(":")[1]);e=this.createElementNS(this.featureNS,"feature:"+e);e.appendChild(c);b.appendChild(e)}return b},insert:function(a){var b=this.createElementNS(this.wfsns,"wfs:Insert");b.appendChild(this.createFeatureXML(a));return b},update:function(a){a.fid||OpenLayers.Console.userError(OpenLayers.i18n("noFID"));
-var b=this.createElementNS(this.wfsns,"wfs:Update");b.setAttribute("typeName",this.featurePrefix+":"+this.featureName);b.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var c=this.createElementNS(this.wfsns,"wfs:Property"),d=this.createElementNS(this.wfsns,"wfs:Name"),e=this.createTextNode(this.geometryName);d.appendChild(e);c.appendChild(d);d=this.createElementNS(this.wfsns,"wfs:Value");e=this.buildGeometryNode(a.geometry);a.layer&&e.setAttribute("srsName",a.layer.projection.getCode());
-d.appendChild(e);c.appendChild(d);b.appendChild(c);for(var f in a.attributes)c=this.createElementNS(this.wfsns,"wfs:Property"),d=this.createElementNS(this.wfsns,"wfs:Name"),d.appendChild(this.createTextNode(f)),c.appendChild(d),d=this.createElementNS(this.wfsns,"wfs:Value"),d.appendChild(this.createTextNode(a.attributes[f])),c.appendChild(d),b.appendChild(c);c=this.createElementNS(this.ogcns,"ogc:Filter");f=this.createElementNS(this.ogcns,"ogc:FeatureId");f.setAttribute("fid",a.fid);c.appendChild(f);
-b.appendChild(c);return b},remove:function(a){if(!a.fid)return OpenLayers.Console.userError(OpenLayers.i18n("noFID")),!1;var b=this.createElementNS(this.wfsns,"wfs:Delete");b.setAttribute("typeName",this.featurePrefix+":"+this.featureName);b.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var c=this.createElementNS(this.ogcns,"ogc:Filter"),d=this.createElementNS(this.ogcns,"ogc:FeatureId");d.setAttribute("fid",a.fid);c.appendChild(d);b.appendChild(c);return b},destroy:function(){this.layer=
-null},CLASS_NAME:"OpenLayers.Format.WFS"});OpenLayers.Format.SLD.v1_0_0_GeoServer=OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0,{version:"1.0.0",profile:"GeoServer",readers:OpenLayers.Util.applyDefaults({sld:OpenLayers.Util.applyDefaults({Priority:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.priority=c)},VendorOption:function(a,b){b.vendorOptions||(b.vendorOptions={});b.vendorOptions[a.getAttribute("name")]=this.getChildValue(a)},TextSymbolizer:function(a,b){OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld.TextSymbolizer.apply(this,
-arguments);var c=this.multipleSymbolizers?b.symbolizers[b.symbolizers.length-1]:b.symbolizer.Text;void 0===c.graphic&&(c.graphic=!1)}},OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld)},OpenLayers.Format.SLD.v1_0_0.prototype.readers),writers:OpenLayers.Util.applyDefaults({sld:OpenLayers.Util.applyDefaults({Priority:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Priority",a)},VendorOption:function(a){return this.createElementNSPlus("sld:VendorOption",{attributes:{name:a.name},
-value:a.value})},TextSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.TextSymbolizer.apply(this,arguments);!1!==a.graphic&&(a.externalGraphic||a.graphicName)&&this.writeNode("Graphic",a,b);"priority"in a&&this.writeNode("Priority",a.priority,b);return this.addVendorOptions(b,a)},PointSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.PointSymbolizer.apply(this,arguments);return this.addVendorOptions(b,a)},LineSymbolizer:function(a){var b=
-OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.LineSymbolizer.apply(this,arguments);return this.addVendorOptions(b,a)},PolygonSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.PolygonSymbolizer.apply(this,arguments);return this.addVendorOptions(b,a)}},OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld)},OpenLayers.Format.SLD.v1_0_0.prototype.writers),addVendorOptions:function(a,b){if(b.vendorOptions)for(var c in b.vendorOptions)this.writeNode("VendorOption",{name:c,
-value:b.vendorOptions[c]},a);return a},CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0_GeoServer"});OpenLayers.Layer.Boxes=OpenLayers.Class(OpenLayers.Layer.Markers,{drawMarker:function(a){var b=this.map.getLayerPxFromLonLat({lon:a.bounds.left,lat:a.bounds.top}),c=this.map.getLayerPxFromLonLat({lon:a.bounds.right,lat:a.bounds.bottom});null==c||null==b?a.display(!1):(b=a.draw(b,{w:Math.max(1,c.x-b.x),h:Math.max(1,c.y-b.y)}),a.drawn||(this.div.appendChild(b),a.drawn=!0))},removeMarker:function(a){OpenLayers.Util.removeItem(this.markers,a);null!=a.div&&a.div.parentNode==this.div&&this.div.removeChild(a.div)},
-CLASS_NAME:"OpenLayers.Layer.Boxes"});OpenLayers.Format.WFSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{readers:{wfs:OpenLayers.Util.applyDefaults({Service:function(a,b){b.service={};this.readChildNodes(a,b.service)},Fees:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.fees=c)},AccessConstraints:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.accessConstraints=c)},OnlineResource:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.onlineResource=
-c)},Keywords:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.keywords=c.split(", "))},Capability:function(a,b){b.capability={};this.readChildNodes(a,b.capability)},Request:function(a,b){b.request={};this.readChildNodes(a,b.request)},GetFeature:function(a,b){b.getfeature={href:{},formats:[]};this.readChildNodes(a,b.getfeature)},ResultFormat:function(a,b){for(var c=a.childNodes,d,e=0;e<c.length;e++)d=c[e],1==d.nodeType&&b.formats.push(d.nodeName)},DCPType:function(a,b){this.readChildNodes(a,
-b)},HTTP:function(a,b){this.readChildNodes(a,b.href)},Get:function(a,b){b.get=a.getAttribute("onlineResource")},Post:function(a,b){b.post=a.getAttribute("onlineResource")},SRS:function(a,b){var c=this.getChildValue(a);c&&(b.srs=c)}},OpenLayers.Format.WFSCapabilities.v1.prototype.readers.wfs)},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_0_0"});OpenLayers.Format.WMSCapabilities.v1_3=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{wms:OpenLayers.Util.applyDefaults({WMS_Capabilities:function(a,b){this.readChildNodes(a,b)},LayerLimit:function(a,b){b.layerLimit=parseInt(this.getChildValue(a))},MaxWidth:function(a,b){b.maxWidth=parseInt(this.getChildValue(a))},MaxHeight:function(a,b){b.maxHeight=parseInt(this.getChildValue(a))},BoundingBox:function(a,b){var c=OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms.BoundingBox.apply(this,
-[a,b]);c.srs=a.getAttribute("CRS");b.bbox[c.srs]=c},CRS:function(a,b){this.readers.wms.SRS.apply(this,[a,b])},EX_GeographicBoundingBox:function(a,b){b.llbbox=[];this.readChildNodes(a,b.llbbox)},westBoundLongitude:function(a,b){b[0]=this.getChildValue(a)},eastBoundLongitude:function(a,b){b[2]=this.getChildValue(a)},southBoundLatitude:function(a,b){b[1]=this.getChildValue(a)},northBoundLatitude:function(a,b){b[3]=this.getChildValue(a)},MinScaleDenominator:function(a,b){b.maxScale=parseFloat(this.getChildValue(a)).toPrecision(16)},
-MaxScaleDenominator:function(a,b){b.minScale=parseFloat(this.getChildValue(a)).toPrecision(16)},Dimension:function(a,b){var c={name:a.getAttribute("name").toLowerCase(),units:a.getAttribute("units"),unitsymbol:a.getAttribute("unitSymbol"),nearestVal:"1"===a.getAttribute("nearestValue"),multipleVal:"1"===a.getAttribute("multipleValues"),"default":a.getAttribute("default")||"",current:"1"===a.getAttribute("current"),values:this.getChildValue(a).split(",")};b.dimensions[c.name]=c},Keyword:function(a,
-b){var c={value:this.getChildValue(a),vocabulary:a.getAttribute("vocabulary")};b.keywords&&b.keywords.push(c)}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms),sld:{UserDefinedSymbolization:function(a,b){this.readers.wms.UserDefinedSymbolization.apply(this,[a,b]);b.userSymbols.inlineFeature=1==parseInt(a.getAttribute("InlineFeature"));b.userSymbols.remoteWCS=1==parseInt(a.getAttribute("RemoteWCS"))},DescribeLayer:function(a,b){this.readers.wms.DescribeLayer.apply(this,[a,b])},GetLegendGraphic:function(a,
-b){this.readers.wms.GetLegendGraphic.apply(this,[a,b])}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3"});OpenLayers.Layer.Zoomify=OpenLayers.Class(OpenLayers.Layer.Grid,{size:null,isBaseLayer:!0,standardTileSize:256,tileOriginCorner:"tl",numberOfTiers:0,tileCountUpToTier:null,tierSizeInTiles:null,tierImageSize:null,initialize:function(a,b,c,d){this.initializeZoomify(c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,c,{},d])},initializeZoomify:function(a){var b=a.clone();this.size=a.clone();a=new OpenLayers.Size(Math.ceil(b.w/this.standardTileSize),Math.ceil(b.h/this.standardTileSize));this.tierSizeInTiles=
-[a];for(this.tierImageSize=[b];b.w>this.standardTileSize||b.h>this.standardTileSize;)b=new OpenLayers.Size(Math.floor(b.w/2),Math.floor(b.h/2)),a=new OpenLayers.Size(Math.ceil(b.w/this.standardTileSize),Math.ceil(b.h/this.standardTileSize)),this.tierSizeInTiles.push(a),this.tierImageSize.push(b);this.tierSizeInTiles.reverse();this.tierImageSize.reverse();this.numberOfTiers=this.tierSizeInTiles.length;b=[1];this.tileCountUpToTier=[0];for(a=1;a<this.numberOfTiers;a++)b.unshift(Math.pow(2,a)),this.tileCountUpToTier.push(this.tierSizeInTiles[a-
-1].w*this.tierSizeInTiles[a-1].h+this.tileCountUpToTier[a-1]);this.serverResolutions||(this.serverResolutions=b)},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);this.tileCountUpToTier.length=0;this.tierSizeInTiles.length=0;this.tierImageSize.length=0},clone:function(a){null==a&&(a=new OpenLayers.Layer.Zoomify(this.name,this.url,this.size,this.options));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);var b=
-this.getServerResolution(),c=Math.round((a.left-this.tileOrigin.lon)/(b*this.tileSize.w));a=Math.round((this.tileOrigin.lat-a.top)/(b*this.tileSize.h));b=this.getZoomForResolution(b);c="TileGroup"+Math.floor((c+a*this.tierSizeInTiles[b].w+this.tileCountUpToTier[b])/256)+"/"+b+"-"+c+"-"+a+".jpg";b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(c,b));return b+c},getImageSize:function(){if(0<arguments.length){var a=this.adjustBounds(arguments[0]),b=this.getServerResolution(),c=Math.round((a.left-
-this.tileOrigin.lon)/(b*this.tileSize.w)),a=Math.round((this.tileOrigin.lat-a.top)/(b*this.tileSize.h)),b=this.getZoomForResolution(b),d=this.standardTileSize,e=this.standardTileSize;c==this.tierSizeInTiles[b].w-1&&(d=this.tierImageSize[b].w%this.standardTileSize);a==this.tierSizeInTiles[b].h-1&&(e=this.tierImageSize[b].h%this.standardTileSize);return new OpenLayers.Size(d,e)}return this.tileSize},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,
-this.map.maxExtent.top)},CLASS_NAME:"OpenLayers.Layer.Zoomify"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);if(null==d||null==d.isBaseLayer)this.isBaseLayer="true"!=this.params.transparent&&!0!=this.params.transparent},clone:function(a){null==a&&(a=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.getOptions()));
-return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){a=this.adjustBounds(a);a=[a.left,a.bottom,a.right,a.top];var b=this.getImageSize();return this.getFullRequestString({mapext:a,imgext:a,map_size:[b.w,b.h],imgx:b.w/2,imgy:b.h/2,imgxy:[b.w,b.h]})},getFullRequestString:function(a,b){var c=null==b?this.url:b,d=OpenLayers.Util.extend({},this.params),d=OpenLayers.Util.extend(d,a),e=OpenLayers.Util.getParameterString(d);OpenLayers.Util.isArray(c)&&(c=this.selectUrl(e,c));
-var e=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),f;for(f in d)f.toUpperCase()in e&&delete d[f];e=OpenLayers.Util.getParameterString(d);d=c;e=e.replace(/,/g,"+");""!=e&&(f=c.charAt(c.length-1),d="&"==f||"?"==f?d+e:-1==c.indexOf("?")?d+("?"+e):d+("&"+e));return d},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(a){if(this.supported()){if(!document.namespaces.olv){document.namespaces.add("olv",this.xmlns);for(var b=document.createStyleSheet(),c="shape rect oval fill stroke imagedata group textbox".split(" "),d=0,e=c.length;d<e;d++)b.addRule("olv\\:"+c[d],"behavior: url(#default#VML); position: absolute; display: inline-block;")}OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
-arguments)}},supported:function(){return!!document.namespaces},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=a.left/d|0,d=a.top/d-this.size.h|0;b||!this.offset?(this.offset={x:e,y:d},d=e=0):(e-=this.offset.x,d-=this.offset.y);this.root.coordorigin=e-this.xOffset+" "+d;for(var e=[this.root,this.vectorRoot,this.textRoot],f=0,g=e.length;f<g;++f)d=e[f],d.coordsize=this.size.w+" "+this.size.h;this.root.style.flip="y";return c},
-setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);for(var b=[this.rendererRoot,this.root,this.vectorRoot,this.textRoot],c=this.size.w+"px",d=this.size.h+"px",e,f=0,g=b.length;f<g;++f)e=b[f],e.style.width=c,e.style.height=d},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"olv:rect":this.isComplexSymbol(b.graphicName)?"olv:shape":"olv:oval";break;case "OpenLayers.Geometry.Rectangle":c="olv:rect";break;case "OpenLayers.Geometry.LineString":case "OpenLayers.Geometry.LinearRing":case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c=
-"olv:shape"}return c},setStyle:function(a,b,c,d){b=b||a._style;c=c||a._options;var e=b.fillColor,f=b.title||b.graphicTitle;f&&(a.title=f);if("OpenLayers.Geometry.Point"===a._geometryClass)if(b.externalGraphic){c.isFilled=!0;var e=b.graphicWidth||b.graphicHeight,f=b.graphicHeight||b.graphicWidth,e=e?e:2*b.pointRadius,f=f?f:2*b.pointRadius,g=this.getResolution(),h=void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*e),k=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*f);a.style.left=((d.x-this.featureDx)/
-g-this.offset.x+h|0)+"px";a.style.top=(d.y/g-this.offset.y-(k+f)|0)+"px";a.style.width=e+"px";a.style.height=f+"px";a.style.flip="y";e="none";c.isStroked=!1}else this.isComplexSymbol(b.graphicName)?(f=this.importSymbol(b.graphicName),a.path=f.path,a.coordorigin=f.left+","+f.bottom,f=f.size,a.coordsize=f+","+f,this.drawCircle(a,d,b.pointRadius),a.style.flip="y"):this.drawCircle(a,d,b.pointRadius);c.isFilled?a.fillcolor=e:a.filled="false";d=a.getElementsByTagName("fill");d=0==d.length?null:d[0];c.isFilled?
-(d||(d=this.createNode("olv:fill",a.id+"_fill")),d.opacity=b.fillOpacity,"OpenLayers.Geometry.Point"===a._geometryClass&&b.externalGraphic&&(b.graphicOpacity&&(d.opacity=b.graphicOpacity),d.src=b.externalGraphic,d.type="frame",b.graphicWidth&&b.graphicHeight||(d.aspect="atmost")),d.parentNode!=a&&a.appendChild(d)):d&&a.removeChild(d);e=b.rotation;if(void 0!==e||void 0!==a._rotation)a._rotation=e,b.externalGraphic?(this.graphicRotate(a,h,k,b),d.opacity=0):"OpenLayers.Geometry.Point"===a._geometryClass&&
-(a.style.rotation=e||0);h=a.getElementsByTagName("stroke");h=0==h.length?null:h[0];c.isStroked?(h||(h=this.createNode("olv:stroke",a.id+"_stroke"),a.appendChild(h)),h.on=!0,h.color=b.strokeColor,h.weight=b.strokeWidth+"px",h.opacity=b.strokeOpacity,h.endcap="butt"==b.strokeLinecap?"flat":b.strokeLinecap||"round",b.strokeDashstyle&&(h.dashstyle=this.dashStyle(b))):(a.stroked=!1,h&&(h.on=!1));"inherit"!=b.cursor&&null!=b.cursor&&(a.style.cursor=b.cursor);return a},graphicRotate:function(a,b,c,d){d=
-d||a._style;var e=d.rotation||0,f,g;if(d.graphicWidth&&d.graphicHeight){g=Math.max(d.graphicWidth,d.graphicHeight);f=d.graphicWidth/d.graphicHeight;var h=Math.round(d.graphicWidth||g*f),k=Math.round(d.graphicHeight||g);a.style.width=h+"px";a.style.height=k+"px";var l=document.getElementById(a.id+"_image");l||(l=this.createNode("olv:imagedata",a.id+"_image"),a.appendChild(l));l.style.width=h+"px";l.style.height=k+"px";l.src=d.externalGraphic;l.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='', sizingMethod='scale')";
-l=e*Math.PI/180;e=Math.sin(l);l=Math.cos(l);e="progid:DXImageTransform.Microsoft.Matrix(M11="+l+",M12="+-e+",M21="+e+",M22="+l+",SizingMethod='auto expand')\n";(l=d.graphicOpacity||d.fillOpacity)&&1!=l&&(e+="progid:DXImageTransform.Microsoft.BasicImage(opacity="+l+")\n");a.style.filter=e;e=new OpenLayers.Geometry.Point(-b,-c);h=(new OpenLayers.Bounds(0,0,h,k)).toGeometry();h.rotate(d.rotation,e);h=h.getBounds();a.style.left=Math.round(parseInt(a.style.left)+h.left)+"px";a.style.top=Math.round(parseInt(a.style.top)-
-h.bottom)+"px"}else{var m=new Image;m.onreadystatechange=OpenLayers.Function.bind(function(){if("complete"==m.readyState||"interactive"==m.readyState)f=m.width/m.height,g=Math.max(2*d.pointRadius,d.graphicWidth||0,d.graphicHeight||0),b*=f,d.graphicWidth=g*f,d.graphicHeight=g,this.graphicRotate(a,b,c,d)},this);m.src=d.externalGraphic}},postDraw:function(a){a.style.visibility="visible";var b=a._style.fillColor,c=a._style.strokeColor;"none"==b&&a.fillcolor!=b&&(a.fillcolor=b);"none"==c&&a.strokecolor!=
-c&&(a.strokecolor=c)},setNodeDimension:function(a,b){var c=b.getBounds();if(c){var d=this.getResolution(),c=new OpenLayers.Bounds((c.left-this.featureDx)/d-this.offset.x|0,c.bottom/d-this.offset.y|0,(c.right-this.featureDx)/d-this.offset.x|0,c.top/d-this.offset.y|0);a.style.left=c.left+"px";a.style.top=c.top+"px";a.style.width=c.getWidth()+"px";a.style.height=c.getHeight()+"px";a.coordorigin=c.left+" "+c.top;a.coordsize=c.getWidth()+" "+c.getHeight()}},dashStyle:function(a){a=a.strokeDashstyle;switch(a){case "solid":case "dot":case "dash":case "dashdot":case "longdash":case "longdashdot":return a;
-default:return a=a.split(/[ ,]/),2==a.length?1*a[0]>=2*a[1]?"longdash":1==a[0]||1==a[1]?"dot":"dash":4==a.length?1*a[0]>=2*a[1]?"longdashdot":"dashdot":"solid"}},createNode:function(a,b){var c=document.createElement(a);b&&(c.id=b);c.unselectable="on";c.onselectstart=OpenLayers.Function.False;return c},nodeTypeCompare:function(a,b){var c=b,d=c.indexOf(":");-1!=d&&(c=c.substr(d+1));var e=a.nodeName,d=e.indexOf(":");-1!=d&&(e=e.substr(d+1));return c==e},createRenderRoot:function(){return this.nodeFactory(this.container.id+
-"_vmlRoot","div")},createRoot:function(a){return this.nodeFactory(this.container.id+a,"olv:group")},drawPoint:function(a,b){return this.drawCircle(a,b,1)},drawCircle:function(a,b,c){if(!isNaN(b.x)&&!isNaN(b.y)){var d=this.getResolution();a.style.left=((b.x-this.featureDx)/d-this.offset.x|0)-c+"px";a.style.top=(b.y/d-this.offset.y|0)-c+"px";b=2*c;a.style.width=b+"px";a.style.height=b+"px";return a}return!1},drawLineString:function(a,b){return this.drawLine(a,b,!1)},drawLinearRing:function(a,b){return this.drawLine(a,
-b,!0)},drawLine:function(a,b,c){this.setNodeDimension(a,b);for(var d=this.getResolution(),e=b.components.length,f=Array(e),g,h,k=0;k<e;k++)g=b.components[k],h=(g.x-this.featureDx)/d-this.offset.x|0,g=g.y/d-this.offset.y|0,f[k]=" "+h+","+g+" l ";b=c?" x e":" e";a.path="m"+f.join("")+b;return a},drawPolygon:function(a,b){this.setNodeDimension(a,b);var c=this.getResolution(),d=[],e,f,g,h,k,l,m,n,p,q;e=0;for(f=b.components.length;e<f;e++){d.push("m");g=b.components[e].components;h=0===e;l=k=null;m=0;
-for(n=g.length;m<n;m++)p=g[m],q=(p.x-this.featureDx)/c-this.offset.x|0,p=p.y/c-this.offset.y|0,q=" "+q+","+p,d.push(q),0==m&&d.push(" l"),h||(k?k!=q&&(l?l!=q&&(h=!0):l=q):k=q);d.push(h?" x ":" ")}d.push("e");a.path=d.join("");return a},drawRectangle:function(a,b){var c=this.getResolution();a.style.left=((b.x-this.featureDx)/c-this.offset.x|0)+"px";a.style.top=(b.y/c-this.offset.y|0)+"px";a.style.width=(b.width/c|0)+"px";a.style.height=(b.height/c|0)+"px";return a},drawText:function(a,b,c){var d=this.nodeFactory(a+
-this.LABEL_ID_SUFFIX,"olv:rect"),e=this.nodeFactory(a+this.LABEL_ID_SUFFIX+"_textbox","olv:textbox"),f=this.getResolution();d.style.left=((c.x-this.featureDx)/f-this.offset.x|0)+"px";d.style.top=(c.y/f-this.offset.y|0)+"px";d.style.flip="y";e.innerText=b.label;"inherit"!=b.cursor&&null!=b.cursor&&(e.style.cursor=b.cursor);b.fontColor&&(e.style.color=b.fontColor);b.fontOpacity&&(e.style.filter="alpha(opacity="+100*b.fontOpacity+")");b.fontFamily&&(e.style.fontFamily=b.fontFamily);b.fontSize&&(e.style.fontSize=
-b.fontSize);b.fontWeight&&(e.style.fontWeight=b.fontWeight);b.fontStyle&&(e.style.fontStyle=b.fontStyle);!0===b.labelSelect&&(d._featureId=a,e._featureId=a,e._geometry=c,e._geometryClass=c.CLASS_NAME);e.style.whiteSpace="nowrap";e.inset="1px,0px,0px,0px";d.parentNode||(d.appendChild(e),this.textRoot.appendChild(d));b=b.labelAlign||"cm";1==b.length&&(b+="m");a=e.clientWidth*OpenLayers.Renderer.VML.LABEL_SHIFT[b.substr(0,1)];e=e.clientHeight*OpenLayers.Renderer.VML.LABEL_SHIFT[b.substr(1,1)];d.style.left=
-parseInt(d.style.left)-a-1+"px";d.style.top=parseInt(d.style.top)+e+"px"},moveRoot:function(a){var b=this.map.getLayer(a.container.id);b instanceof OpenLayers.Layer.Vector.RootContainer&&(b=this.map.getLayer(this.container.id));b&&b.renderer.clear();OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this,arguments);b&&b.redraw()},importSymbol:function(a){var b=this.container.id+"-"+a,c=this.symbolCache[b];if(c)return c;c=OpenLayers.Renderer.symbol[a];if(!c)throw Error(a+" is not a valid symbol name");
-a=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);for(var d=["m"],e=0;e<c.length;e+=2){var f=c[e],g=c[e+1];a.left=Math.min(a.left,f);a.bottom=Math.min(a.bottom,g);a.right=Math.max(a.right,f);a.top=Math.max(a.top,g);d.push(f);d.push(g);0==e&&d.push("l")}d.push("x e");c=d.join(" ");d=(a.getWidth()-a.getHeight())/2;0<d?(a.bottom-=d,a.top+=d):(a.left+=d,a.right-=d);c={path:c,size:a.getWidth(),left:a.left,bottom:a.bottom};return this.symbolCache[b]=c},CLASS_NAME:"OpenLayers.Renderer.VML"});
-OpenLayers.Renderer.VML.LABEL_SHIFT={l:0,c:0.5,r:1,t:0,m:0.5,b:1};OpenLayers.Control.CacheRead=OpenLayers.Class(OpenLayers.Control,{fetchEvent:"tileloadstart",layers:null,autoActivate:!0,setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);var b,c=this.layers||a.layers;for(b=c.length-1;0<=b;--b)this.addLayer({layer:c[b]});if(!this.layers)a.events.on({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this})},addLayer:function(a){a.layer.events.register(this.fetchEvent,this,this.fetch)},removeLayer:function(a){a.layer.events.unregister(this.fetchEvent,
-this,this.fetch)},fetch:function(a){if(this.active&&window.localStorage&&a.tile instanceof OpenLayers.Tile.Image){var b=a.tile,c=b.url;!b.layer.crossOriginKeyword&&(OpenLayers.ProxyHost&&0===c.indexOf(OpenLayers.ProxyHost))&&(c=OpenLayers.Control.CacheWrite.urlMap[c]);if(c=window.localStorage.getItem("olCache_"+c))b.url=c,"tileerror"===a.type&&b.setImgSrc(c)}},destroy:function(){if(this.layers||this.map){var a,b=this.layers||this.map.layers;for(a=b.length-1;0<=a;--a)this.removeLayer({layer:b[a]})}this.map&&
-this.map.events.un({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.CacheRead"});OpenLayers.Protocol.WFS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.0.0",CLASS_NAME:"OpenLayers.Protocol.WFS.v1_0_0"});OpenLayers.Format.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Format.XML,{layerIdentifier:"_layer",featureIdentifier:"_feature",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},gmlFormat:null,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=a.documentElement;if(b){var c=this["read_"+b.nodeName];a=c?c.call(this,b):(new OpenLayers.Format.GML(this.options?this.options:{})).read(a)}return a},read_msGMLOutput:function(a){var b=
-[];if(a=this.getSiblingNodesByTagCriteria(a,this.layerIdentifier))for(var c=0,d=a.length;c<d;++c){var e=a[c],f=e.nodeName;e.prefix&&(f=f.split(":")[1]);f=f.replace(this.layerIdentifier,"");if(e=this.getSiblingNodesByTagCriteria(e,this.featureIdentifier))for(var g=0;g<e.length;g++){var h=e[g],k=this.parseGeometry(h),h=this.parseAttributes(h),h=new OpenLayers.Feature.Vector(k.geometry,h,null);h.bounds=k.bounds;h.type=f;b.push(h)}}return b},read_FeatureInfoResponse:function(a){var b=[];a=this.getElementsByTagNameNS(a,
-"*","FIELDS");for(var c=0,d=a.length;c<d;c++){var e=a[c],f={},g,h=e.attributes.length;if(0<h)for(g=0;g<h;g++){var k=e.attributes[g];f[k.nodeName]=k.nodeValue}else for(e=e.childNodes,g=0,h=e.length;g<h;++g)k=e[g],3!=k.nodeType&&(f[k.getAttribute("name")]=k.getAttribute("value"));b.push(new OpenLayers.Feature.Vector(null,f,null))}return b},getSiblingNodesByTagCriteria:function(a,b){var c=[],d,e,f,g;if(a&&a.hasChildNodes()){d=a.childNodes;f=d.length;for(var h=0;h<f;h++){for(g=d[h];g&&1!=g.nodeType;)g=
-g.nextSibling,h++;e=g?g.nodeName:"";0<e.length&&-1<e.indexOf(b)?c.push(g):(e=this.getSiblingNodesByTagCriteria(g,b),0<e.length&&(0==c.length?c=e:c.push(e)))}}return c},parseAttributes:function(a){var b={};if(1==a.nodeType){a=a.childNodes;for(var c=a.length,d=0;d<c;++d){var e=a[d];if(1==e.nodeType){var f=e.childNodes,e=e.prefix?e.nodeName.split(":")[1]:e.nodeName;0==f.length?b[e]=null:1==f.length&&(f=f[0],3==f.nodeType||4==f.nodeType)&&(f=f.nodeValue.replace(this.regExes.trimSpace,""),b[e]=f)}}}return b},
-parseGeometry:function(a){this.gmlFormat||(this.gmlFormat=new OpenLayers.Format.GML);a=this.gmlFormat.parseFeature(a);var b,c=null;a&&(b=a.geometry&&a.geometry.clone(),c=a.bounds&&a.bounds.clone(),a.destroy());return{geometry:b,bounds:c}},CLASS_NAME:"OpenLayers.Format.WMSGetFeatureInfo"});OpenLayers.Control.WMTSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:!1,requestEncoding:"KVP",drillDown:!1,maxFeatures:10,clickCallback:"click",layers:null,queryVisible:!0,infoFormat:"text/html",vendorParams:{},format:null,formatOptions:null,handler:null,hoverRequest:null,pending:0,initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.format||(this.format=new OpenLayers.Format.WMSGetFeatureInfo(a.formatOptions));
-!0===this.drillDown&&(this.hover=!1);this.hover?this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250})):(a={},a[this.clickCallback]=this.getInfoForClick,this.handler=new OpenLayers.Handler.Click(this,a,this.handlerOptions.click||{}))},getInfoForClick:function(a){this.request(a.xy,{})},getInfoForHover:function(a){this.request(a.xy,{hover:!0})},cancelHover:function(){this.hoverRequest&&(--this.pending,
-0>=this.pending&&(OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"),this.pending=0),this.hoverRequest.abort(),this.hoverRequest=null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d=a.length-1;0<=d&&(c=a[d],!(c instanceof OpenLayers.Layer.WMTS)||(c.requestEncoding!==this.requestEncoding||this.queryVisible&&!c.getVisibility())||(b.push(c),this.drillDown&&!this.hover));--d);return b},buildRequestOptions:function(a,b){var c=this.map.getLonLatFromPixel(b),d=a.getURL(new OpenLayers.Bounds(c.lon,
-c.lat,c.lon,c.lat)),d=OpenLayers.Util.getParameters(d),c=a.getTileInfo(c);OpenLayers.Util.extend(d,{service:"WMTS",version:a.version,request:"GetFeatureInfo",infoFormat:this.infoFormat,i:c.i,j:c.j});OpenLayers.Util.applyDefaults(d,this.vendorParams);return{url:OpenLayers.Util.isArray(a.url)?a.url[0]:a.url,params:OpenLayers.Util.upperCaseObject(d),callback:function(c){this.handleResponse(b,c,a)},scope:this}},request:function(a,b){b=b||{};var c=this.findLayers();if(0<c.length){for(var d,e,f=0,g=c.length;f<
-g;f++)e=c[f],d=this.events.triggerEvent("beforegetfeatureinfo",{xy:a,layer:e}),!1!==d&&(++this.pending,d=this.buildRequestOptions(e,a),d=OpenLayers.Request.GET(d),!0===b.hover&&(this.hoverRequest=d));0<this.pending&&OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait")}},handleResponse:function(a,b,c){--this.pending;0>=this.pending&&(OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"),this.pending=0);if(b.status&&(200>b.status||300<=b.status))this.events.triggerEvent("exception",
-{xy:a,request:b,layer:c});else{var d=b.responseXML;d&&d.documentElement||(d=b.responseText);var e,f;try{e=this.format.read(d)}catch(g){f=!0,this.events.triggerEvent("exception",{xy:a,request:b,error:g,layer:c})}f||this.events.triggerEvent("getfeatureinfo",{text:b.responseText,features:e,request:b,xy:a,layer:c})}},CLASS_NAME:"OpenLayers.Control.WMTSGetFeatureInfo"});OpenLayers.Protocol.CSW.v2_0_2=OpenLayers.Class(OpenLayers.Protocol,{formatOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({},this.formatOptions)))},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,
-this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.format.write(a.params||a);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},handleRead:function(a,b){if(b.callback){var c=a.priv;200<=c.status&&300>c.status?(a.data=this.parseData(c),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseData:function(a){var b=
-a.responseXML;b&&b.documentElement||(b=a.responseText);return!b||0>=b.length?null:this.format.read(b)},CLASS_NAME:"OpenLayers.Protocol.CSW.v2_0_2"});OpenLayers.Format.WCSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WCSCapabilities.v1,{namespaces:{wcs:"http://www.opengis.net/wcs/1.1",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows/1.1"},errorProperty:"operationsMetadata",readers:{wcs:OpenLayers.Util.applyDefaults({Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,b){b.contentMetadata=[];this.readChildNodes(a,b.contentMetadata)},CoverageSummary:function(a,
-b){var c={};this.readChildNodes(a,c);b.push(c)},Identifier:function(a,b){b.identifier=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},SupportedCRS:function(a,b){var c=this.getChildValue(a);c&&(b.supportedCRS||(b.supportedCRS=[]),b.supportedCRS.push(c))},SupportedFormat:function(a,b){var c=this.getChildValue(a);c&&(b.supportedFormat||(b.supportedFormat=[]),b.supportedFormat.push(c))}},OpenLayers.Format.WCSCapabilities.v1.prototype.readers.wcs),
-ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WCSCapabilities.v1_1_0"});OpenLayers.Control.Graticule=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,intervals:[45,30,20,10,5,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.002,0.001],displayInLayerSwitcher:!0,visible:!0,numPoints:50,targetSize:200,layerName:null,labelled:!0,labelFormat:"dm",lineSymbolizer:{strokeColor:"#333",strokeWidth:1,strokeOpacity:0.5},labelSymbolizer:{},gratLayer:null,initialize:function(a){a=a||{};a.layerName=a.layerName||OpenLayers.i18n("Graticule");OpenLayers.Control.prototype.initialize.apply(this,[a]);
-this.labelSymbolizer.stroke=!1;this.labelSymbolizer.fill=!1;this.labelSymbolizer.label="${label}";this.labelSymbolizer.labelAlign="${labelAlign}";this.labelSymbolizer.labelXOffset="${xOffset}";this.labelSymbolizer.labelYOffset="${yOffset}"},destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);this.gratLayer&&(this.gratLayer.destroy(),this.gratLayer=null)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.gratLayer){var a=new OpenLayers.Style({},
-{rules:[new OpenLayers.Rule({symbolizer:{Point:this.labelSymbolizer,Line:this.lineSymbolizer}})]});this.gratLayer=new OpenLayers.Layer.Vector(this.layerName,{styleMap:new OpenLayers.StyleMap({"default":a}),visibility:this.visible,displayInLayerSwitcher:this.displayInLayerSwitcher})}return this.div},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.map.addLayer(this.gratLayer),this.map.events.register("moveend",this,this.update),this.update(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,
-arguments)?(this.map.events.unregister("moveend",this,this.update),this.map.removeLayer(this.gratLayer),!0):!1},update:function(){var a=this.map.getExtent();if(a){this.gratLayer.destroyFeatures();var b=new OpenLayers.Projection("EPSG:4326"),c=this.map.getProjectionObject(),d=this.map.getResolution();c.proj&&"longlat"==c.proj.projName&&(this.numPoints=1);var e=this.map.getCenter(),f=new OpenLayers.Pixel(e.lon,e.lat);OpenLayers.Projection.transform(f,c,b);for(var e=this.targetSize*d,e=e*e,g,d=0;d<this.intervals.length;++d){g=
-this.intervals[d];var h=g/2,k=f.offset({x:-h,y:-h}),h=f.offset({x:h,y:h});OpenLayers.Projection.transform(k,b,c);OpenLayers.Projection.transform(h,b,c);if((k.x-h.x)*(k.x-h.x)+(k.y-h.y)*(k.y-h.y)<=e)break}f.x=Math.floor(f.x/g)*g;f.y=Math.floor(f.y/g)*g;var d=0,e=[f.clone()],h=f.clone(),l;do h=h.offset({x:0,y:g}),l=OpenLayers.Projection.transform(h.clone(),b,c),e.unshift(h);while(a.containsPixel(l)&&1E3>++d);h=f.clone();do h=h.offset({x:0,y:-g}),l=OpenLayers.Projection.transform(h.clone(),b,c),e.push(h);
-while(a.containsPixel(l)&&1E3>++d);d=0;k=[f.clone()];h=f.clone();do h=h.offset({x:-g,y:0}),l=OpenLayers.Projection.transform(h.clone(),b,c),k.unshift(h);while(a.containsPixel(l)&&1E3>++d);h=f.clone();do h=h.offset({x:g,y:0}),l=OpenLayers.Projection.transform(h.clone(),b,c),k.push(h);while(a.containsPixel(l)&&1E3>++d);g=[];for(d=0;d<k.length;++d){l=k[d].x;for(var f=[],m=null,n=Math.min(e[0].y,90),h=Math.max(e[e.length-1].y,-90),p=(n-h)/this.numPoints,n=h,h=0;h<=this.numPoints;++h){var q=new OpenLayers.Geometry.Point(l,
-n);q.transform(b,c);f.push(q);n+=p;q.y>=a.bottom&&!m&&(m=q)}this.labelled&&(m=new OpenLayers.Geometry.Point(m.x,a.bottom),l={value:l,label:this.labelled?OpenLayers.Util.getFormattedLonLat(l,"lon",this.labelFormat):"",labelAlign:"cb",xOffset:0,yOffset:2},this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(m,l)));f=new OpenLayers.Geometry.LineString(f);g.push(new OpenLayers.Feature.Vector(f))}for(h=0;h<e.length;++h)if(n=e[h].y,!(-90>n||90<n)){f=[];d=k[0].x;p=(k[k.length-1].x-d)/this.numPoints;
-l=d;m=null;for(d=0;d<=this.numPoints;++d)q=new OpenLayers.Geometry.Point(l,n),q.transform(b,c),f.push(q),l+=p,q.x<a.right&&(m=q);this.labelled&&(m=new OpenLayers.Geometry.Point(a.right,m.y),l={value:n,label:this.labelled?OpenLayers.Util.getFormattedLonLat(n,"lat",this.labelFormat):"",labelAlign:"rb",xOffset:-2,yOffset:2},this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(m,l)));f=new OpenLayers.Geometry.LineString(f);g.push(new OpenLayers.Feature.Vector(f))}this.gratLayer.addFeatures(g)}},CLASS_NAME:"OpenLayers.Control.Graticule"});OpenLayers.Console.warn("OpenLayers.Rico is deprecated");OpenLayers.Rico=OpenLayers.Rico||{};
-OpenLayers.Rico.Corner={round:function(a,b){a=OpenLayers.Util.getElement(a);this._setOptions(b);var c=this.options.color;"fromElement"==this.options.color&&(c=this._background(a));var d=this.options.bgColor;"fromParent"==this.options.bgColor&&(d=this._background(a.offsetParent));this._roundCornersImpl(a,c,d)},changeColor:function(a,b){a.style.backgroundColor=b;for(var c=a.parentNode.getElementsByTagName("span"),d=0;d<c.length;d++)c[d].style.backgroundColor=b},changeOpacity:function(a,b){var c="alpha(opacity="+
-100*b+")";a.style.opacity=b;a.style.filter=c;for(var d=a.parentNode.getElementsByTagName("span"),e=0;e<d.length;e++)d[e].style.opacity=b,d[e].style.filter=c},reRound:function(a,b){var c=a.parentNode.childNodes[2];a.parentNode.removeChild(a.parentNode.childNodes[0]);a.parentNode.removeChild(c);this.round(a.parentNode,b)},_roundCornersImpl:function(a,b,c){this.options.border&&this._renderBorder(a,c);this._isTopRounded()&&this._roundTopCorners(a,b,c);this._isBottomRounded()&&this._roundBottomCorners(a,
-b,c)},_renderBorder:function(a,b){var c="1px solid "+this._borderColor(b);a.innerHTML="<div "+("style='border-left: "+c+";"+("border-right: "+c)+"'")+">"+a.innerHTML+"</div>"},_roundTopCorners:function(a,b,c){for(var d=this._createCorner(c),e=0;e<this.options.numSlices;e++)d.appendChild(this._createCornerSlice(b,c,e,"top"));a.style.paddingTop=0;a.insertBefore(d,a.firstChild)},_roundBottomCorners:function(a,b,c){for(var d=this._createCorner(c),e=this.options.numSlices-1;0<=e;e--)d.appendChild(this._createCornerSlice(b,
-c,e,"bottom"));a.style.paddingBottom=0;a.appendChild(d)},_createCorner:function(a){var b=document.createElement("div");b.style.backgroundColor=this._isTransparent()?"transparent":a;return b},_createCornerSlice:function(a,b,c,d){var e=document.createElement("span"),f=e.style;f.backgroundColor=a;f.display="block";f.height="1px";f.overflow="hidden";f.fontSize="1px";a=this._borderColor(a,b);this.options.border&&0==c?(f.borderTopStyle="solid",f.borderTopWidth="1px",f.borderLeftWidth="0px",f.borderRightWidth=
-"0px",f.borderBottomWidth="0px",f.height="0px",f.borderColor=a):a&&(f.borderColor=a,f.borderStyle="solid",f.borderWidth="0px 1px");this.options.compact||c!=this.options.numSlices-1||(f.height="2px");this._setMargin(e,c,d);this._setBorder(e,c,d);return e},_setOptions:function(a){this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:!0,border:!1,compact:!1};OpenLayers.Util.extend(this.options,a||{});this.options.numSlices=this.options.compact?2:4;this._isTransparent()&&(this.options.blend=
-!1)},_whichSideTop:function(){return this._hasString(this.options.corners,"all","top")||0<=this.options.corners.indexOf("tl")&&0<=this.options.corners.indexOf("tr")?"":0<=this.options.corners.indexOf("tl")?"left":0<=this.options.corners.indexOf("tr")?"right":""},_whichSideBottom:function(){return this._hasString(this.options.corners,"all","bottom")||0<=this.options.corners.indexOf("bl")&&0<=this.options.corners.indexOf("br")?"":0<=this.options.corners.indexOf("bl")?"left":0<=this.options.corners.indexOf("br")?
-"right":""},_borderColor:function(a,b){return"transparent"==a?b:this.options.border?this.options.border:this.options.blend?this._blend(b,a):""},_setMargin:function(a,b,c){b=this._marginSize(b);c="top"==c?this._whichSideTop():this._whichSideBottom();"left"==c?(a.style.marginLeft=b+"px",a.style.marginRight="0px"):"right"==c?(a.style.marginRight=b+"px",a.style.marginLeft="0px"):(a.style.marginLeft=b+"px",a.style.marginRight=b+"px")},_setBorder:function(a,b,c){b=this._borderSize(b);c="top"==c?this._whichSideTop():
-this._whichSideBottom();"left"==c?(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth="0px"):"right"==c?(a.style.borderRightWidth=b+"px",a.style.borderLeftWidth="0px"):(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px");!1!=this.options.border&&(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px")},_marginSize:function(a){if(this._isTransparent())return 0;var b=[5,3,2,1],c=[3,2,1,0],d=[2,1],e=[1,0];return this.options.compact&&this.options.blend?e[a]:this.options.compact?
-d[a]:this.options.blend?c[a]:b[a]},_borderSize:function(a){var b=[5,3,2,1],c=[2,1,1,1],d=[1,0],e=[0,2,0,0];return this.options.compact&&(this.options.blend||this._isTransparent())?1:this.options.compact?d[a]:this.options.blend?c[a]:this.options.border?e[a]:this._isTransparent()?b[a]:0},_hasString:function(a){for(var b=1;b<arguments.length;b++)if(0<=a.indexOf(arguments[b]))return!0;return!1},_blend:function(a,b){var c=OpenLayers.Rico.Color.createFromHex(a);c.blend(OpenLayers.Rico.Color.createFromHex(b));
-return c},_background:function(a){try{return OpenLayers.Rico.Color.createColorFromBackground(a).asHex()}catch(b){return"#ffffff"}},_isTransparent:function(){return"transparent"==this.options.color},_isTopRounded:function(){return this._hasString(this.options.corners,"all","top","tl","tr")},_isBottomRounded:function(){return this._hasString(this.options.corners,"all","bottom","bl","br")},_hasSingleTextChild:function(a){return 1==a.childNodes.length&&3==a.childNodes[0].nodeType}};OpenLayers.Control.NavigationHistory=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOGGLE,previous:null,previousOptions:null,next:null,nextOptions:null,limit:50,autoActivate:!0,clearOnDeactivate:!1,registry:null,nextStack:null,previousStack:null,listeners:null,restoring:!1,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.registry=OpenLayers.Util.extend({moveend:this.getState},this.registry);a={trigger:OpenLayers.Function.bind(this.previousTrigger,
-this),displayClass:this.displayClass+" "+this.displayClass+"Previous"};OpenLayers.Util.extend(a,this.previousOptions);this.previous=new OpenLayers.Control.Button(a);a={trigger:OpenLayers.Function.bind(this.nextTrigger,this),displayClass:this.displayClass+" "+this.displayClass+"Next"};OpenLayers.Util.extend(a,this.nextOptions);this.next=new OpenLayers.Control.Button(a);this.clear()},onPreviousChange:function(a,b){a&&!this.previous.active?this.previous.activate():!a&&this.previous.active&&this.previous.deactivate()},
-onNextChange:function(a,b){a&&!this.next.active?this.next.activate():!a&&this.next.active&&this.next.deactivate()},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this);this.previous.destroy();this.next.destroy();this.deactivate();for(var a in this)this[a]=null},setMap:function(a){this.map=a;this.next.setMap(a);this.previous.setMap(a)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.next.draw();this.previous.draw()},previousTrigger:function(){var a=this.previousStack.shift(),
-b=this.previousStack.shift();void 0!=b?(this.nextStack.unshift(a),this.previousStack.unshift(b),this.restoring=!0,this.restore(b),this.restoring=!1,this.onNextChange(this.nextStack[0],this.nextStack.length),this.onPreviousChange(this.previousStack[1],this.previousStack.length-1)):this.previousStack.unshift(a);return b},nextTrigger:function(){var a=this.nextStack.shift();void 0!=a&&(this.previousStack.unshift(a),this.restoring=!0,this.restore(a),this.restoring=!1,this.onNextChange(this.nextStack[0],
-this.nextStack.length),this.onPreviousChange(this.previousStack[1],this.previousStack.length-1));return a},clear:function(){this.previousStack=[];this.previous.deactivate();this.nextStack=[];this.next.deactivate()},getState:function(){return{center:this.map.getCenter(),resolution:this.map.getResolution(),projection:this.map.getProjectionObject(),units:this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units}},restore:function(a){var b,c;if(this.map.getProjectionObject()==
-a.projection)c=this.map.getZoomForResolution(a.resolution),b=a.center;else{b=a.center.clone();b.transform(a.projection,this.map.getProjectionObject());c=a.units;var d=this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units;c=this.map.getZoomForResolution((c&&d?OpenLayers.INCHES_PER_UNIT[c]/OpenLayers.INCHES_PER_UNIT[d]:1)*a.resolution)}this.map.setCenter(b,c)},setListeners:function(){this.listeners={};for(var a in this.registry)this.listeners[a]=OpenLayers.Function.bind(function(){if(!this.restoring){var b=
-this.registry[a].apply(this,arguments);this.previousStack.unshift(b);if(1<this.previousStack.length)this.onPreviousChange(this.previousStack[1],this.previousStack.length-1);this.previousStack.length>this.limit+1&&this.previousStack.pop();0<this.nextStack.length&&(this.nextStack=[],this.onNextChange(null,0))}return!0},this)},activate:function(){var a=!1;if(this.map&&OpenLayers.Control.prototype.activate.apply(this)){null==this.listeners&&this.setListeners();for(var b in this.listeners)this.map.events.register(b,
-this,this.listeners[b]);a=!0;0==this.previousStack.length&&this.initStack()}return a},initStack:function(){this.map.getCenter()&&this.listeners.moveend()},deactivate:function(){var a=!1;if(this.map&&OpenLayers.Control.prototype.deactivate.apply(this)){for(var b in this.listeners)this.map.events.unregister(b,this,this.listeners[b]);this.clearOnDeactivate&&this.clear();a=!0}return a},CLASS_NAME:"OpenLayers.Control.NavigationHistory"});OpenLayers.Layer.UTFGrid=OpenLayers.Class(OpenLayers.Layer.XYZ,{isBaseLayer:!1,projection:new OpenLayers.Projection("EPSG:900913"),useJSONP:!1,tileClass:OpenLayers.Tile.UTFGrid,initialize:function(a){OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a.name,a.url,{},a]);this.tileOptions=OpenLayers.Util.extend({utfgridResolution:this.utfgridResolution},this.tileOptions)},createBackBuffer:function(){},clone:function(a){null==a&&(a=new OpenLayers.Layer.UTFGrid(this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
-[a])},getFeatureInfo:function(a){var b=null;(a=this.getTileData(a))&&a.tile&&(b=a.tile.getFeatureInfo(a.i,a.j));return b},getFeatureId:function(a){var b=null;a=this.getTileData(a);a.tile&&(b=a.tile.getFeatureId(a.i,a.j));return b},CLASS_NAME:"OpenLayers.Layer.UTFGrid"});OpenLayers.TileManager=OpenLayers.Class({cacheSize:256,tilesPerFrame:2,frameDelay:16,moveDelay:100,zoomDelay:200,maps:null,tileQueueId:null,tileQueue:null,tileCache:null,tileCacheIndex:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.maps=[];this.tileQueueId={};this.tileQueue={};this.tileCache={};this.tileCacheIndex=[]},addMap:function(a){if(!this._destroyed&&OpenLayers.Layer.Grid){this.maps.push(a);this.tileQueue[a.id]=[];for(var b=0,c=a.layers.length;b<c;++b)this.addLayer({layer:a.layers[b]});
-a.events.on({move:this.move,zoomend:this.zoomEnd,changelayer:this.changeLayer,addlayer:this.addLayer,preremovelayer:this.removeLayer,scope:this})}},removeMap:function(a){if(!this._destroyed&&OpenLayers.Layer.Grid){window.clearTimeout(this.tileQueueId[a.id]);if(a.layers)for(var b=0,c=a.layers.length;b<c;++b)this.removeLayer({layer:a.layers[b]});a.events&&a.events.un({move:this.move,zoomend:this.zoomEnd,changelayer:this.changeLayer,addlayer:this.addLayer,preremovelayer:this.removeLayer,scope:this});
-delete this.tileQueue[a.id];delete this.tileQueueId[a.id];OpenLayers.Util.removeItem(this.maps,a)}},move:function(a){this.updateTimeout(a.object,this.moveDelay,!0)},zoomEnd:function(a){this.updateTimeout(a.object,this.zoomDelay)},changeLayer:function(a){"visibility"!==a.property&&"params"!==a.property||this.updateTimeout(a.object,0)},addLayer:function(a){a=a.layer;if(a instanceof OpenLayers.Layer.Grid){a.events.on({addtile:this.addTile,retile:this.clearTileQueue,scope:this});var b,c,d;for(b=a.grid.length-
-1;0<=b;--b)for(c=a.grid[b].length-1;0<=c;--c)d=a.grid[b][c],this.addTile({tile:d}),d.url&&!d.imgDiv&&this.manageTileCache({object:d})}},removeLayer:function(a){a=a.layer;if(a instanceof OpenLayers.Layer.Grid&&(this.clearTileQueue({object:a}),a.events&&a.events.un({addtile:this.addTile,retile:this.clearTileQueue,scope:this}),a.grid)){var b,c,d;for(b=a.grid.length-1;0<=b;--b)for(c=a.grid[b].length-1;0<=c;--c)d=a.grid[b][c],this.unloadTile({object:d})}},updateTimeout:function(a,b,c){window.clearTimeout(this.tileQueueId[a.id]);
-var d=this.tileQueue[a.id];if(!c||d.length)this.tileQueueId[a.id]=window.setTimeout(OpenLayers.Function.bind(function(){this.drawTilesFromQueue(a);d.length&&this.updateTimeout(a,this.frameDelay)},this),b)},addTile:function(a){if(a.tile instanceof OpenLayers.Tile.Image)a.tile.events.on({beforedraw:this.queueTileDraw,beforeload:this.manageTileCache,loadend:this.addToCache,unload:this.unloadTile,scope:this});else this.removeLayer({layer:a.tile.layer})},unloadTile:function(a){a=a.object;a.events.un({beforedraw:this.queueTileDraw,
-beforeload:this.manageTileCache,loadend:this.addToCache,unload:this.unloadTile,scope:this});OpenLayers.Util.removeItem(this.tileQueue[a.layer.map.id],a)},queueTileDraw:function(a){a=a.object;var b=!1,c=a.layer,d=c.getURL(a.bounds),e=this.tileCache[d];e&&"olTileImage"!==e.className&&(delete this.tileCache[d],OpenLayers.Util.removeItem(this.tileCacheIndex,d),e=null);!c.url||!c.async&&e||(b=this.tileQueue[c.map.id],~OpenLayers.Util.indexOf(b,a)||b.push(a),b=!0);return!b},drawTilesFromQueue:function(a){var b=
-this.tileQueue[a.id],c=this.tilesPerFrame;for(a=a.zoomTween&&a.zoomTween.playing;!a&&b.length&&c;)b.shift().draw(!0),--c},manageTileCache:function(a){a=a.object;var b=this.tileCache[a.url];b&&(b.parentNode&&OpenLayers.Element.hasClass(b.parentNode,"olBackBuffer")&&(b.parentNode.removeChild(b),b.id=null),b.parentNode||(b.style.visibility="hidden",b.style.opacity=0,a.setImage(b),OpenLayers.Util.removeItem(this.tileCacheIndex,a.url),this.tileCacheIndex.push(a.url)))},addToCache:function(a){a=a.object;
-this.tileCache[a.url]||OpenLayers.Element.hasClass(a.imgDiv,"olImageLoadError")||(this.tileCacheIndex.length>=this.cacheSize&&(delete this.tileCache[this.tileCacheIndex[0]],this.tileCacheIndex.shift()),this.tileCache[a.url]=a.imgDiv,this.tileCacheIndex.push(a.url))},clearTileQueue:function(a){a=a.object;for(var b=this.tileQueue[a.map.id],c=b.length-1;0<=c;--c)b[c].layer===a&&b.splice(c,1)},destroy:function(){for(var a=this.maps.length-1;0<=a;--a)this.removeMap(this.maps[a]);this.tileCacheIndex=this.tileCache=
-this.tileQueueId=this.tileQueue=this.maps=null;this._destroyed=!0}});OpenLayers.Layer.ArcGISCache=OpenLayers.Class(OpenLayers.Layer.XYZ,{url:null,tileOrigin:null,tileSize:new OpenLayers.Size(256,256),useArcGISServer:!0,type:"png",useScales:!1,overrideDPI:!1,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.resolutions&&(this.serverResolutions=this.resolutions,this.maxExtent=this.getMaxExtentForResolution(this.resolutions[0]));if(this.layerInfo){var d=this.layerInfo,e=new OpenLayers.Bounds(d.fullExtent.xmin,d.fullExtent.ymin,
-d.fullExtent.xmax,d.fullExtent.ymax);this.projection="EPSG:"+d.spatialReference.wkid;this.sphericalMercator=102100==d.spatialReference.wkid;this.units="esriFeet"==d.units?"ft":"m";if(d.tileInfo){this.tileSize=new OpenLayers.Size(d.tileInfo.width||d.tileInfo.cols,d.tileInfo.height||d.tileInfo.rows);this.tileOrigin=new OpenLayers.LonLat(d.tileInfo.origin.x,d.tileInfo.origin.y);var f=new OpenLayers.Geometry.Point(e.left,e.top),e=new OpenLayers.Geometry.Point(e.right,e.bottom);this.useScales?this.scales=
-[]:this.resolutions=[];this.lods=[];for(var g in d.tileInfo.lods)if(d.tileInfo.lods.hasOwnProperty(g)){var h=d.tileInfo.lods[g];this.useScales?this.scales.push(h.scale):this.resolutions.push(h.resolution);var k=this.getContainingTileCoords(f,h.resolution);h.startTileCol=k.x;h.startTileRow=k.y;k=this.getContainingTileCoords(e,h.resolution);h.endTileCol=k.x;h.endTileRow=k.y;this.lods.push(h)}this.maxExtent=this.calculateMaxExtentWithLOD(this.lods[0]);this.serverResolutions=this.resolutions;this.overrideDPI&&
-d.tileInfo.dpi&&(OpenLayers.DOTS_PER_INCH=d.tileInfo.dpi)}}},getContainingTileCoords:function(a,b){return new OpenLayers.Pixel(Math.max(Math.floor((a.x-this.tileOrigin.lon)/(this.tileSize.w*b)),0),Math.max(Math.floor((this.tileOrigin.lat-a.y)/(this.tileSize.h*b)),0))},calculateMaxExtentWithLOD:function(a){var b=this.tileOrigin.lon+a.startTileCol*this.tileSize.w*a.resolution,c=this.tileOrigin.lat-a.startTileRow*this.tileSize.h*a.resolution;return new OpenLayers.Bounds(b,c-(a.endTileRow-a.startTileRow+
-1)*this.tileSize.h*a.resolution,b+(a.endTileCol-a.startTileCol+1)*this.tileSize.w*a.resolution,c)},calculateMaxExtentWithExtent:function(a,b){var c=new OpenLayers.Geometry.Point(a.left,a.top),d=new OpenLayers.Geometry.Point(a.right,a.bottom),c=this.getContainingTileCoords(c,b),d=this.getContainingTileCoords(d,b);return this.calculateMaxExtentWithLOD({resolution:b,startTileCol:c.x,startTileRow:c.y,endTileCol:d.x,endTileRow:d.y})},getUpperLeftTileCoord:function(a){var b=new OpenLayers.Geometry.Point(this.maxExtent.left,
-this.maxExtent.top);return this.getContainingTileCoords(b,a)},getLowerRightTileCoord:function(a){var b=new OpenLayers.Geometry.Point(this.maxExtent.right,this.maxExtent.bottom);return this.getContainingTileCoords(b,a)},getMaxExtentForResolution:function(a){var b=this.getUpperLeftTileCoord(a),c=this.getLowerRightTileCoord(a),d=this.tileOrigin.lon+b.x*this.tileSize.w*a,e=this.tileOrigin.lat-b.y*this.tileSize.h*a;return new OpenLayers.Bounds(d,e-(c.y-b.y+1)*this.tileSize.h*a,d+(c.x-b.x+1)*this.tileSize.w*
-a,e)},clone:function(a){null==a&&(a=new OpenLayers.Layer.ArcGISCache(this.name,this.url,this.options));return OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},initGriddedTiles:function(a){delete this._tileOrigin;OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this,arguments)},getMaxExtent:function(){var a=this.map.getResolution();return this.maxExtent=this.getMaxExtentForResolution(a)},getTileOrigin:function(){if(!this._tileOrigin){var a=this.getMaxExtent();this._tileOrigin=new OpenLayers.LonLat(a.left,
-a.bottom)}return this._tileOrigin},getURL:function(a){var b=this.getResolution(),c=this.tileOrigin.lon+b*this.tileSize.w/2,d=this.tileOrigin.lat-b*this.tileSize.h/2;a=a.getCenterLonLat();c=Math.round(Math.abs((a.lon-c)/(b*this.tileSize.w)));d=Math.round(Math.abs((d-a.lat)/(b*this.tileSize.h)));a=this.map.getZoom();if(this.lods){if(b=this.lods[this.map.getZoom()],c<b.startTileCol||c>b.endTileCol||d<b.startTileRow||d>b.endTileRow)return null}else{var e=this.getUpperLeftTileCoord(b),b=this.getLowerRightTileCoord(b);
-if(c<e.x||c>=b.x||d<e.y||d>=b.y)return null}b=this.url;e=""+c+d+a;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(e,b));this.useArcGISServer?b+="/tile/${z}/${y}/${x}":(c="C"+OpenLayers.Number.zeroPad(c,8,16),d="R"+OpenLayers.Number.zeroPad(d,8,16),a="L"+OpenLayers.Number.zeroPad(a,2,10),b=b+"/${z}/${y}/${x}."+this.type);b=OpenLayers.String.format(b,{x:c,y:d,z:a});return OpenLayers.Util.urlAppend(b,OpenLayers.Util.getParameterString(this.params))},CLASS_NAME:"OpenLayers.Layer.ArcGISCache"});OpenLayers.Control.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:!1,drillDown:!1,maxFeatures:10,clickCallback:"click",output:"features",layers:null,queryVisible:!1,url:null,layerUrls:null,infoFormat:"text/html",vendorParams:{},format:null,formatOptions:null,handler:null,hoverRequest:null,initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.format||(this.format=new OpenLayers.Format.WMSGetFeatureInfo(a.formatOptions));
-!0===this.drillDown&&(this.hover=!1);this.hover?this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250})):(a={},a[this.clickCallback]=this.getInfoForClick,this.handler=new OpenLayers.Handler.Click(this,a,this.handlerOptions.click||{}))},getInfoForClick:function(a){this.events.triggerEvent("beforegetfeatureinfo",{xy:a.xy});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");this.request(a.xy,
-{})},getInfoForHover:function(a){this.events.triggerEvent("beforegetfeatureinfo",{xy:a.xy});this.request(a.xy,{hover:!0})},cancelHover:function(){this.hoverRequest&&(this.hoverRequest.abort(),this.hoverRequest=null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d,e=a.length-1;0<=e;--e)c=a[e],c instanceof OpenLayers.Layer.WMS&&(!this.queryVisible||c.getVisibility())&&(d=OpenLayers.Util.isArray(c.url)?c.url[0]:c.url,!1!==this.drillDown||this.url||(this.url=d),(!0===this.drillDown||
-this.urlMatches(d))&&b.push(c));return b},urlMatches:function(a){var b=OpenLayers.Util.isEquivalentUrl(this.url,a);if(!b&&this.layerUrls)for(var c=0,d=this.layerUrls.length;c<d;++c)if(OpenLayers.Util.isEquivalentUrl(this.layerUrls[c],a)){b=!0;break}return b},buildWMSOptions:function(a,b,c,d){for(var e=[],f=[],g=0,h=b.length;g<h;g++)null!=b[g].params.LAYERS&&(e=e.concat(b[g].params.LAYERS),f=f.concat(this.getStyleNames(b[g])));b=b[0];g=this.map.getProjection();(h=b.projection)&&h.equals(this.map.getProjectionObject())&&
-(g=h.getCode());d=OpenLayers.Util.extend({service:"WMS",version:b.params.VERSION,request:"GetFeatureInfo",exceptions:b.params.EXCEPTIONS,bbox:this.map.getExtent().toBBOX(null,b.reverseAxisOrder()),feature_count:this.maxFeatures,height:this.map.getSize().h,width:this.map.getSize().w,format:d,info_format:b.params.INFO_FORMAT||this.infoFormat},1.3<=parseFloat(b.params.VERSION)?{crs:g,i:parseInt(c.x),j:parseInt(c.y)}:{srs:g,x:parseInt(c.x),y:parseInt(c.y)});0!=e.length&&(d=OpenLayers.Util.extend({layers:e,
-query_layers:e,styles:f},d));OpenLayers.Util.applyDefaults(d,this.vendorParams);return{url:a,params:OpenLayers.Util.upperCaseObject(d),callback:function(b){this.handleResponse(c,b,a)},scope:this}},getStyleNames:function(a){return a.params.STYLES?a.params.STYLES:OpenLayers.Util.isArray(a.params.LAYERS)?Array(a.params.LAYERS.length):a.params.LAYERS.replace(/[^,]/g,"")},request:function(a,b){var c=this.findLayers();if(0==c.length)this.events.triggerEvent("nogetfeatureinfo"),OpenLayers.Element.removeClass(this.map.viewPortDiv,
-"olCursorWait");else if(b=b||{},!1===this.drillDown){var c=this.buildWMSOptions(this.url,c,a,c[0].params.FORMAT),d=OpenLayers.Request.GET(c);!0===b.hover&&(this.hoverRequest=d)}else{this._numRequests=this._requestCount=0;this.features=[];for(var d={},e,f=0,g=c.length;f<g;f++){var h=c[f];e=OpenLayers.Util.isArray(h.url)?h.url[0]:h.url;e in d?d[e].push(h):(this._numRequests++,d[e]=[h])}for(e in d)c=d[e],c=this.buildWMSOptions(e,c,a,c[0].params.FORMAT),OpenLayers.Request.GET(c)}},triggerGetFeatureInfo:function(a,
-b,c){this.events.triggerEvent("getfeatureinfo",{text:a.responseText,features:c,request:a,xy:b});OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait")},handleResponse:function(a,b,c){var d=b.responseXML;d&&d.documentElement||(d=b.responseText);d=this.format.read(d);!1===this.drillDown?this.triggerGetFeatureInfo(b,a,d):(this._requestCount++,this._features="object"===this.output?(this._features||[]).concat({url:c,features:d}):(this._features||[]).concat(d),this._requestCount===this._numRequests&&
-(this.triggerGetFeatureInfo(b,a,this._features.concat()),delete this._features,delete this._requestCount,delete this._numRequests))},CLASS_NAME:"OpenLayers.Control.WMSGetFeatureInfo"});OpenLayers.Format.WMSCapabilities.v1_3_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3,{version:"1.3.0",CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3_0"});OpenLayers.Format.SOSGetFeatureOfInterest=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",sa:"http://www.opengis.net/sampling/1.0",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd",defaultPrefix:"sos",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a){"string"==
-typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={features:[]};this.readNode(a,b);a=[];for(var c=0,d=b.features.length;c<d;c++){var e=b.features[c];this.internalProjection&&(this.externalProjection&&e.components[0])&&e.components[0].transform(this.externalProjection,this.internalProjection);e=new OpenLayers.Feature.Vector(e.components[0],e.attributes);a.push(e)}return a},readers:{sa:{SamplingPoint:function(a,b){if(!b.attributes){var c=
-{attributes:{}};b.features.push(c);b=c}b.attributes.id=this.getAttributeNS(a,this.namespaces.gml,"id");this.readChildNodes(a,b)},position:function(a,b){this.readChildNodes(a,b)}},gml:OpenLayers.Util.applyDefaults({FeatureCollection:function(a,b){this.readChildNodes(a,b)},featureMember:function(a,b){var c={attributes:{}};b.features.push(c);this.readChildNodes(a,c)},name:function(a,b){b.attributes.name=this.getChildValue(a)},pos:function(a,b){this.externalProjection||(this.externalProjection=new OpenLayers.Projection(a.getAttribute("srsName")));
-OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[a,b])}},OpenLayers.Format.GML.v3.prototype.readers.gml)},writers:{sos:{GetFeatureOfInterest:function(a){for(var b=this.createElementNSPlus("GetFeatureOfInterest",{attributes:{version:this.VERSION,service:"SOS","xsi:schemaLocation":this.schemaLocation}}),c=0,d=a.fois.length;c<d;c++)this.writeNode("FeatureOfInterestId",{foi:a.fois[c]},b);return b},FeatureOfInterestId:function(a){return this.createElementNSPlus("FeatureOfInterestId",{value:a.foi})}}},
-CLASS_NAME:"OpenLayers.Format.SOSGetFeatureOfInterest"});OpenLayers.Format.SOSGetObservation=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows",gml:"http://www.opengis.net/gml",sos:"http://www.opengis.net/sos/1.0",ogc:"http://www.opengis.net/ogc",om:"http://www.opengis.net/om/1.0",sa:"http://www.opengis.net/sampling/1.0",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd",
-defaultPrefix:"sos",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={measurements:[],observations:[]};this.readNode(a,b);return b},write:function(a){a=this.writeNode("sos:GetObservation",a);a.setAttribute("xmlns:om",this.namespaces.om);a.setAttribute("xmlns:ogc",this.namespaces.ogc);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,
-[a])},readers:{om:{ObservationCollection:function(a,b){b.id=this.getAttributeNS(a,this.namespaces.gml,"id");this.readChildNodes(a,b)},member:function(a,b){this.readChildNodes(a,b)},Measurement:function(a,b){var c={};b.measurements.push(c);this.readChildNodes(a,c)},Observation:function(a,b){var c={};b.observations.push(c);this.readChildNodes(a,c)},samplingTime:function(a,b){var c={};b.samplingTime=c;this.readChildNodes(a,c)},observedProperty:function(a,b){b.observedProperty=this.getAttributeNS(a,this.namespaces.xlink,
-"href");this.readChildNodes(a,b)},procedure:function(a,b){b.procedure=this.getAttributeNS(a,this.namespaces.xlink,"href");this.readChildNodes(a,b)},featureOfInterest:function(a,b){var c={features:[]};b.fois=[];b.fois.push(c);this.readChildNodes(a,c);for(var d=[],e=0,f=c.features.length;e<f;e++){var g=c.features[e];d.push(new OpenLayers.Feature.Vector(g.components[0],g.attributes))}c.features=d},result:function(a,b){var c={};b.result=c;""!==this.getChildValue(a)?(c.value=this.getChildValue(a),c.uom=
-a.getAttribute("uom")):this.readChildNodes(a,c)}},sa:OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa,gml:OpenLayers.Util.applyDefaults({TimeInstant:function(a,b){var c={};b.timeInstant=c;this.readChildNodes(a,c)},timePosition:function(a,b){b.timePosition=this.getChildValue(a)}},OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml)},writers:{sos:{GetObservation:function(a){var b=this.createElementNSPlus("GetObservation",{attributes:{version:this.VERSION,service:"SOS"}});this.writeNode("offering",
-a,b);a.eventTime&&this.writeNode("eventTime",a,b);for(var c in a.procedures)this.writeNode("procedure",a.procedures[c],b);for(var d in a.observedProperties)this.writeNode("observedProperty",a.observedProperties[d],b);a.foi&&this.writeNode("featureOfInterest",a.foi,b);this.writeNode("responseFormat",a,b);a.resultModel&&this.writeNode("resultModel",a,b);a.responseMode&&this.writeNode("responseMode",a,b);return b},featureOfInterest:function(a){var b=this.createElementNSPlus("featureOfInterest");this.writeNode("ObjectID",
-a.objectId,b);return b},ObjectID:function(a){return this.createElementNSPlus("ObjectID",{value:a})},responseFormat:function(a){return this.createElementNSPlus("responseFormat",{value:a.responseFormat})},procedure:function(a){return this.createElementNSPlus("procedure",{value:a})},offering:function(a){return this.createElementNSPlus("offering",{value:a.offering})},observedProperty:function(a){return this.createElementNSPlus("observedProperty",{value:a})},eventTime:function(a){var b=this.createElementNSPlus("eventTime");
-"latest"===a.eventTime&&this.writeNode("ogc:TM_Equals",a,b);return b},resultModel:function(a){return this.createElementNSPlus("resultModel",{value:a.resultModel})},responseMode:function(a){return this.createElementNSPlus("responseMode",{value:a.responseMode})}},ogc:{TM_Equals:function(a){var b=this.createElementNSPlus("ogc:TM_Equals");this.writeNode("ogc:PropertyName",{property:"urn:ogc:data:time:iso8601"},b);"latest"===a.eventTime&&this.writeNode("gml:TimeInstant",{value:"latest"},b);return b},PropertyName:function(a){return this.createElementNSPlus("ogc:PropertyName",
-{value:a.property})}},gml:{TimeInstant:function(a){var b=this.createElementNSPlus("gml:TimeInstant");this.writeNode("gml:timePosition",a,b);return b},timePosition:function(a){return this.createElementNSPlus("gml:timePosition",{value:a.value})}}},CLASS_NAME:"OpenLayers.Format.SOSGetObservation"});OpenLayers.Control.UTFGrid=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,layers:null,defaultHandlerOptions:{delay:300,pixelTolerance:4,stopMove:!1,single:!0,"double":!1,stopSingle:!1,stopDouble:!1},handlerMode:"click",setHandler:function(a){this.handlerMode=a;this.resetHandler()},resetHandler:function(){this.handler&&(this.handler.deactivate(),this.handler.destroy(),this.handler=null);"hover"==this.handlerMode?this.handler=new OpenLayers.Handler.Hover(this,{pause:this.handleEvent,move:this.reset},
-this.handlerOptions):"click"==this.handlerMode?this.handler=new OpenLayers.Handler.Click(this,{click:this.handleEvent},this.handlerOptions):"move"==this.handlerMode&&(this.handler=new OpenLayers.Handler.Hover(this,{pause:this.handleEvent,move:this.handleEvent},this.handlerOptions));return this.handler?!0:!1},initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||this.defaultHandlerOptions;OpenLayers.Control.prototype.initialize.apply(this,[a]);this.resetHandler()},handleEvent:function(a){if(null==
-a)this.reset();else{var b=this.map.getLonLatFromPixel(a.xy);if(b){var c=this.findLayers();if(0<c.length){for(var d={},e,f,g=0,h=c.length;g<h;g++)e=c[g],f=OpenLayers.Util.indexOf(this.map.layers,e),d[f]=e.getFeatureInfo(b);this.callback(d,b,a.xy)}}}},callback:function(a){},reset:function(a){this.callback(null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d=a.length-1;0<=d;--d)c=a[d],c instanceof OpenLayers.Layer.UTFGrid&&b.push(c);return b},CLASS_NAME:"OpenLayers.Control.UTFGrid"});OpenLayers.Format.CQL=function(){function a(a){function b(){var a=e.pop();switch(a.type){case "LOGICAL":var c=b(),g=b();return new OpenLayers.Filter.Logical({filters:[g,c],type:f[a.text.toUpperCase()]});case "NOT":return a=b(),new OpenLayers.Filter.Logical({filters:[a],type:OpenLayers.Filter.Logical.NOT});case "BETWEEN":return e.pop(),g=b(),a=b(),c=b(),new OpenLayers.Filter.Comparison({property:c,lowerBoundary:a,upperBoundary:g,type:OpenLayers.Filter.Comparison.BETWEEN});case "COMPARISON":return g=
-b(),c=b(),new OpenLayers.Filter.Comparison({property:c,value:g,type:d[a.text.toUpperCase()]});case "IS_NULL":return c=b(),new OpenLayers.Filter.Comparison({property:c,type:d[a.text.toUpperCase()]});case "VALUE":return(c=a.text.match(/^'(.*)'$/))?c[1].replace(/''/g,"'"):Number(a.text);case "SPATIAL":switch(a.text.toUpperCase()){case "BBOX":var a=b(),c=b(),g=b(),h=b(),k=b();return new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:k,value:OpenLayers.Bounds.fromArray([h,g,c,
-a])});case "INTERSECTS":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:c,value:g});case "WITHIN":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.WITHIN,property:c,value:g});case "CONTAINS":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.CONTAINS,property:c,value:g});case "DWITHIN":return a=b(),g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,value:g,
-property:c,distance:Number(a)})}case "GEOMETRY":return OpenLayers.Geometry.fromWKT(a.text);default:return a.text}}for(var c=[],e=[];a.length;){var g=a.shift();switch(g.type){case "PROPERTY":case "GEOMETRY":case "VALUE":e.push(g);break;case "COMPARISON":case "BETWEEN":case "IS_NULL":case "LOGICAL":for(var k=h[g.type];0<c.length&&h[c[c.length-1].type]<=k;)e.push(c.pop());c.push(g);break;case "SPATIAL":case "NOT":case "LPAREN":c.push(g);break;case "RPAREN":for(;0<c.length&&"LPAREN"!=c[c.length-1].type;)e.push(c.pop());
-c.pop();0<c.length&&"SPATIAL"==c[c.length-1].type&&e.push(c.pop());case "COMMA":case "END":break;default:throw Error("Unknown token type "+g.type);}}for(;0<c.length;)e.push(c.pop());a=b();if(0<e.length){a="Remaining tokens after building AST: \n";for(c=e.length-1;0<=c;c--)a+=e[c].type+": "+e[c].text+"\n";throw Error(a);}return a}var b={PROPERTY:/^[_a-zA-Z]\w*/,COMPARISON:/^(=|<>|<=|<|>=|>|LIKE)/i,IS_NULL:/^IS NULL/i,COMMA:/^,/,LOGICAL:/^(AND|OR)/i,VALUE:/^('([^']|'')*'|\d+(\.\d*)?|\.\d+)/,LPAREN:/^\(/,
-RPAREN:/^\)/,SPATIAL:/^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i,NOT:/^NOT/i,BETWEEN:/^BETWEEN/i,GEOMETRY:function(a){var b=/^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(a);if(b){var c=a.length,b=a.indexOf("(",b[0].length);if(-1<b)for(var d=1;b<c&&0<d;)switch(b++,a.charAt(b)){case "(":d++;break;case ")":d--}return[a.substr(0,b+1)]}},END:/^$/},c={LPAREN:["GEOMETRY","SPATIAL","PROPERTY","VALUE","LPAREN"],RPAREN:["NOT","LOGICAL","END","RPAREN"],PROPERTY:["COMPARISON",
-"BETWEEN","COMMA","IS_NULL"],BETWEEN:["VALUE"],IS_NULL:["END"],COMPARISON:["VALUE"],COMMA:["GEOMETRY","VALUE","PROPERTY"],VALUE:["LOGICAL","COMMA","RPAREN","END"],SPATIAL:["LPAREN"],LOGICAL:["NOT","VALUE","SPATIAL","PROPERTY","LPAREN"],NOT:["PROPERTY","LPAREN"],GEOMETRY:["COMMA","RPAREN"]},d={"=":OpenLayers.Filter.Comparison.EQUAL_TO,"<>":OpenLayers.Filter.Comparison.NOT_EQUAL_TO,"<":OpenLayers.Filter.Comparison.LESS_THAN,"<=":OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO,">":OpenLayers.Filter.Comparison.GREATER_THAN,
-">=":OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO,LIKE:OpenLayers.Filter.Comparison.LIKE,BETWEEN:OpenLayers.Filter.Comparison.BETWEEN,"IS NULL":OpenLayers.Filter.Comparison.IS_NULL},e={},f={AND:OpenLayers.Filter.Logical.AND,OR:OpenLayers.Filter.Logical.OR},g={},h={RPAREN:3,LOGICAL:2,COMPARISON:1},k;for(k in d)d.hasOwnProperty(k)&&(e[d[k]]=k);for(k in f)f.hasOwnProperty(k)&&(g[f[k]]=k);return OpenLayers.Class(OpenLayers.Format,{read:function(d){var e=d;d=[];var f,g=["NOT","GEOMETRY","SPATIAL",
-"PROPERTY","LPAREN"];do{a:{f=g;for(var h=void 0,g=void 0,k=f.length,h=0;h<k;h++){var g=f[h],s=b[g]instanceof RegExp?b[g].exec(e):(0,b[g])(e);if(s){f=s[0];e=e.substr(f.length).replace(/^\s*/,"");f={type:g,text:f,remainder:e};break a}}d="ERROR: In parsing: ["+e+"], expected one of: ";for(h=0;h<k;h++)g=f[h],d+="\n "+g+": "+b[g];throw Error(d);}e=f.remainder;g=c[f.type];if("END"!=f.type&&!g)throw Error("No follows list for "+f.type);d.push(f)}while("END"!=f.type);d=a(d);this.keepData&&(this.data=d);
-return d},write:function(a){if(a instanceof OpenLayers.Geometry)return a.toString();switch(a.CLASS_NAME){case "OpenLayers.Filter.Spatial":switch(a.type){case OpenLayers.Filter.Spatial.BBOX:return"BBOX("+a.property+","+a.value.toBBOX()+")";case OpenLayers.Filter.Spatial.DWITHIN:return"DWITHIN("+a.property+", "+this.write(a.value)+", "+a.distance+")";case OpenLayers.Filter.Spatial.WITHIN:return"WITHIN("+a.property+", "+this.write(a.value)+")";case OpenLayers.Filter.Spatial.INTERSECTS:return"INTERSECTS("+
-a.property+", "+this.write(a.value)+")";case OpenLayers.Filter.Spatial.CONTAINS:return"CONTAINS("+a.property+", "+this.write(a.value)+")";default:throw Error("Unknown spatial filter type: "+a.type);}case "OpenLayers.Filter.Logical":if(a.type==OpenLayers.Filter.Logical.NOT)return"NOT ("+this.write(a.filters[0])+")";for(var b="(",c=!0,d=0;d<a.filters.length;d++)c?c=!1:b+=") "+g[a.type]+" (",b+=this.write(a.filters[d]);return b+")";case "OpenLayers.Filter.Comparison":return a.type==OpenLayers.Filter.Comparison.BETWEEN?
-a.property+" BETWEEN "+this.write(a.lowerBoundary)+" AND "+this.write(a.upperBoundary):null!==a.value?a.property+" "+e[a.type]+" "+this.write(a.value):a.property+" "+e[a.type];case void 0:if("string"===typeof a)return"'"+a.replace(/'/g,"''")+"'";if("number"===typeof a)return String(a);default:throw Error("Can't encode: "+a.CLASS_NAME+" "+a);}},CLASS_NAME:"OpenLayers.Format.CQL"})}();OpenLayers.Control.Split=OpenLayers.Class(OpenLayers.Control,{layer:null,source:null,sourceOptions:null,tolerance:null,edge:!0,deferDelete:!1,mutual:!0,targetFilter:null,sourceFilter:null,handler:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.options=a||{};this.options.source&&this.setSource(this.options.source)},setSource:function(a){this.active?(this.deactivate(),this.handler&&(this.handler.destroy(),delete this.handler),this.source=a,this.activate()):this.source=
-a},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a)if(!this.source)this.handler||(this.handler=new OpenLayers.Handler.Path(this,{done:function(a){this.onSketchComplete({feature:new OpenLayers.Feature.Vector(a)})}},{layerOptions:this.sourceOptions})),this.handler.activate();else if(this.source.events)this.source.events.on({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.call(this);
-a&&this.source&&this.source.events&&this.source.events.un({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});return a},onSketchComplete:function(a){this.feature=null;return!this.considerSplit(a.feature)},afterFeatureModified:function(a){a.modified&&"function"===typeof a.feature.geometry.split&&(this.feature=a.feature,this.considerSplit(a.feature))},removeByGeometry:function(a,b){for(var c=0,d=a.length;c<d;++c)if(a[c].geometry===b){a.splice(c,1);break}},
-isEligible:function(a){return a.geometry?a.state!==OpenLayers.State.DELETE&&"function"===typeof a.geometry.split&&this.feature!==a&&(!this.targetFilter||this.targetFilter.evaluate(a.attributes)):!1},considerSplit:function(a){var b=!1,c=!1;if(!this.sourceFilter||this.sourceFilter.evaluate(a.attributes)){for(var d=this.layer&&this.layer.features||[],e,f,g=[],h=[],k=this.layer===this.source&&this.mutual,l={edge:this.edge,tolerance:this.tolerance,mutual:k},m=[a.geometry],n,p,q,r=0,s=d.length;r<s;++r)if(n=
-d[r],this.isEligible(n)){p=[n.geometry];for(var t=0;t<m.length;++t){q=m[t];for(var u=0;u<p.length;++u)if(e=p[u],q.getBounds().intersectsBounds(e.getBounds())&&(e=q.split(e,l)))f=this.events.triggerEvent("beforesplit",{source:a,target:n}),!1!==f&&(k&&(f=e[0],1<f.length&&(f.unshift(t,1),Array.prototype.splice.apply(m,f),t+=f.length-3),e=e[1]),1<e.length&&(e.unshift(u,1),Array.prototype.splice.apply(p,e),u+=e.length-3))}p&&1<p.length&&(this.geomsToFeatures(n,p),this.events.triggerEvent("split",{original:n,
-features:p}),Array.prototype.push.apply(g,p),h.push(n),c=!0)}m&&1<m.length&&(this.geomsToFeatures(a,m),this.events.triggerEvent("split",{original:a,features:m}),Array.prototype.push.apply(g,m),h.push(a),b=!0);if(b||c){if(this.deferDelete){d=[];r=0;for(s=h.length;r<s;++r)c=h[r],c.state===OpenLayers.State.INSERT?d.push(c):(c.state=OpenLayers.State.DELETE,this.layer.drawFeature(c));this.layer.destroyFeatures(d,{silent:!0});r=0;for(s=g.length;r<s;++r)g[r].state=OpenLayers.State.INSERT}else this.layer.destroyFeatures(h,
-{silent:!0});this.layer.addFeatures(g,{silent:!0});this.events.triggerEvent("aftersplit",{source:a,features:g})}}return b},geomsToFeatures:function(a,b){var c=a.clone();delete c.geometry;for(var d,e=0,f=b.length;e<f;++e)d=c.clone(),d.geometry=b[e],d.state=OpenLayers.State.INSERT,b[e]=d},destroy:function(){this.active&&this.deactivate();OpenLayers.Control.prototype.destroy.call(this)},CLASS_NAME:"OpenLayers.Control.Split"});OpenLayers.Layer.WMTS=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,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(a){var b=
-{url:!0,layer:!0,style:!0,matrixSet:!0},c;for(c in b)if(!(c in a))throw Error("Missing property '"+c+"' in layer configuration.");a.params=OpenLayers.Util.upperCaseObject(a.params);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a.name,a.url,a.params,a]);this.formatSuffix||(this.formatSuffix=this.formatSuffixMap[this.format]||this.format.split("/").pop());if(this.matrixIds&&(a=this.matrixIds.length)&&"string"===typeof this.matrixIds[0])for(b=this.matrixIds,this.matrixIds=Array(a),c=0;c<a;++c)this.matrixIds[c]=
-{identifier:b[c]}},setMap:function(){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments)},updateMatrixProperties:function(){if(this.matrix=this.getMatrix())this.matrix.topLeftCorner&&(this.tileOrigin=this.matrix.topLeftCorner),this.matrix.tileWidth&&this.matrix.tileHeight&&(this.tileSize=new OpenLayers.Size(this.matrix.tileWidth,this.matrix.tileHeight)),this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.top)),this.tileFullExtent||(this.tileFullExtent=
-this.maxExtent)},moveTo:function(a,b,c){!b&&this.matrix||this.updateMatrixProperties();return OpenLayers.Layer.Grid.prototype.moveTo.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMTS(this.options));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getIdentifier:function(){return this.getServerZoom()},getMatrix:function(){var a;if(this.matrixIds&&0!==this.matrixIds.length)if("scaleDenominator"in this.matrixIds[0])for(var b=OpenLayers.METERS_PER_INCH*OpenLayers.INCHES_PER_UNIT[this.units]*
-this.getServerResolution()/2.8E-4,c=Number.POSITIVE_INFINITY,d,e=0,f=this.matrixIds.length;e<f;++e)d=Math.abs(1-this.matrixIds[e].scaleDenominator/b),d<c&&(c=d,a=this.matrixIds[e]);else a=this.matrixIds[this.getIdentifier()];else a={identifier:this.getIdentifier()};return a},getTileInfo:function(a){var b=this.getServerResolution(),c=(a.lon-this.tileOrigin.lon)/(b*this.tileSize.w);a=(this.tileOrigin.lat-a.lat)/(b*this.tileSize.h);var b=Math.floor(c),d=Math.floor(a);return{col:b,row:d,i:Math.floor((c-
-b)*this.tileSize.w),j:Math.floor((a-d)*this.tileSize.h)}},getURL:function(a){a=this.adjustBounds(a);var b="";if(!this.tileFullExtent||this.tileFullExtent.intersectsBounds(a)){a=a.getCenterLonLat();var c=this.getTileInfo(a);a=this.dimensions;var d,b=OpenLayers.Util.isArray(this.url)?this.selectUrl([this.version,this.style,this.matrixSet,this.matrix.identifier,c.row,c.col].join(),this.url):this.url;if("REST"===this.requestEncoding.toUpperCase())if(d=this.params,-1!==b.indexOf("{")){b=b.replace(/\{/g,
-"${");c={style:this.style,Style:this.style,TileMatrixSet:this.matrixSet,TileMatrix:this.matrix.identifier,TileRow:c.row,TileCol:c.col};if(a){var e,f;for(f=a.length-1;0<=f;--f)e=a[f],c[e]=d[e.toUpperCase()]}b=OpenLayers.String.format(b,c)}else{e=this.version+"/"+this.layer+"/"+this.style+"/";if(a)for(f=0;f<a.length;f++)d[a[f]]&&(e=e+d[a[f]]+"/");e=e+this.matrixSet+"/"+this.matrix.identifier+"/"+c.row+"/"+c.col+"."+this.formatSuffix;b.match(/\/$/)||(b+="/");b+=e}else"KVP"===this.requestEncoding.toUpperCase()&&
-(d={SERVICE:"WMTS",REQUEST:"GetTile",VERSION:this.version,LAYER:this.layer,STYLE:this.style,TILEMATRIXSET:this.matrixSet,TILEMATRIX:this.matrix.identifier,TILEROW:c.row,TILECOL:c.col,FORMAT:this.format},b=OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,[d]))}return b},mergeNewParams:function(a){if("KVP"===this.requestEncoding.toUpperCase())return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,[OpenLayers.Util.upperCaseObject(a)])},CLASS_NAME:"OpenLayers.Layer.WMTS"});OpenLayers.Protocol.SOS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol,{fois:null,formatOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions))},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||
-{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.format,c=OpenLayers.Format.XML.prototype.write.apply(c,[c.writeNode("sos:GetFeatureOfInterest",{fois:this.fois})]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),data:c});return b},handleRead:function(a,b){if(b.callback){var c=a.priv;200<=c.status&&300>c.status?(a.features=this.parseFeatures(c),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE;
-b.callback.call(b.scope,a)}},parseFeatures:function(a){var b=a.responseXML;b&&b.documentElement||(b=a.responseText);return!b||0>=b.length?null:this.format.read(b)},CLASS_NAME:"OpenLayers.Protocol.SOS.v1_0_0"});OpenLayers.Layer.KaMapCache=OpenLayers.Class(OpenLayers.Layer.KaMap,{IMAGE_EXTENSIONS:{jpeg:"jpg",gif:"gif",png:"png",png8:"png",png24:"png",dithered:"png"},DEFAULT_FORMAT:"jpeg",initialize:function(a,b,c,d){OpenLayers.Layer.KaMap.prototype.initialize.apply(this,arguments);this.extension=this.IMAGE_EXTENSIONS[this.params.i.toLowerCase()||this.DEFAULT_FORMAT]},getURL:function(a){a=this.adjustBounds(a);var b=this.map.getResolution(),c=Math.round(1E4*this.map.getScale())/1E4,d=Math.round(a.left/b);a=
--Math.round(a.top/b);var b=Math.floor(d/this.tileSize.w/this.params.metaTileSize.w)*this.tileSize.w*this.params.metaTileSize.w,e=Math.floor(a/this.tileSize.h/this.params.metaTileSize.h)*this.tileSize.h*this.params.metaTileSize.h,c=["/",this.params.map,"/",c,"/",this.params.g.replace(/\s/g,"_"),"/def/t",e,"/l",b,"/t",a,"l",d,".",this.extension],d=this.url;OpenLayers.Util.isArray(d)&&(d=this.selectUrl(c.join(""),d));return d+c.join("")},CLASS_NAME:"OpenLayers.Layer.KaMapCache"});OpenLayers.Protocol.WFS.v1_1_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.1.0",initialize:function(a){OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this,arguments);this.outputFormat&&!this.readFormat&&("gml2"==this.outputFormat.toLowerCase()?this.readFormat=new OpenLayers.Format.GML.v2({featureType:this.featureType,featureNS:this.featureNS,geometryName:this.geometryName}):"json"==this.outputFormat.toLowerCase()&&(this.readFormat=new OpenLayers.Format.GeoJSON))},CLASS_NAME:"OpenLayers.Protocol.WFS.v1_1_0"});OpenLayers.Format.WMSCapabilities.v1_1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.1",readers:{wms:OpenLayers.Util.applyDefaults({SRS:function(a,b){b.srs[this.getChildValue(a)]=!0}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1"});OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1,{version:"1.1.1",profile:"WMSC",readers:{wms:OpenLayers.Util.applyDefaults({VendorSpecificCapabilities:function(a,b){b.vendorSpecific={tileSets:[]};this.readChildNodes(a,b.vendorSpecific)},TileSet:function(a,b){var c={srs:{},bbox:{},resolutions:[]};this.readChildNodes(a,c);b.tileSets.push(c)},Resolutions:function(a,b){for(var c=this.getChildValue(a).split(" "),d=0,e=c.length;d<e;d++)""!=c[d]&&b.resolutions.push(parseFloat(c[d]))},
-Width:function(a,b){b.width=parseInt(this.getChildValue(a))},Height:function(a,b){b.height=parseInt(this.getChildValue(a))},Layers:function(a,b){b.layers=this.getChildValue(a)},Styles:function(a,b){b.styles=this.getChildValue(a)}},OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC"});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:!0,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[]},destroy:function(){this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({buttonclick:this.onButtonClick,addlayer:this.redraw,changelayer:this.redraw,
-removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.outsideViewport?(this.events.attachToElement(this.div),this.events.register("buttonclick",this,this.onButtonClick)):
-this.map.events.register("buttonclick",this,this.onButtonClick)},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();this.outsideViewport||this.minimizeControl();this.redraw();return this.div},onButtonClick:function(a){a=a.buttonElement;a===this.minimizeDiv?this.minimizeControl():a===this.maximizeDiv?this.maximizeControl():a._layerSwitcher===this.id&&(a["for"]&&(a=document.getElementById(a["for"])),a.disabled||("radio"==a.type?(a.checked=!0,this.map.setBaseLayer(this.map.getLayer(a._layer))):
-(a.checked=!a.checked,this.updateMap())))},clearLayersArray:function(a){this[a+"LayersDiv"].innerHTML="";this[a+"Layers"]=[]},checkRedraw:function(){if(!this.layerStates.length||this.map.layers.length!=this.layerStates.length)return!0;for(var a=0,b=this.layerStates.length;a<b;a++){var c=this.layerStates[a],d=this.map.layers[a];if(c.name!=d.name||c.inRange!=d.inRange||c.id!=d.id||c.visibility!=d.visibility)return!0}return!1},redraw:function(){if(!this.checkRedraw())return this.div;this.clearLayersArray("base");
-this.clearLayersArray("data");var a=!1,b=!1,c=this.map.layers.length;this.layerStates=Array(c);for(var d=0;d<c;d++){var e=this.map.layers[d];this.layerStates[d]={name:e.name,visibility:e.visibility,inRange:e.inRange,id:e.id}}var f=this.map.layers.slice();this.ascending||f.reverse();d=0;for(c=f.length;d<c;d++){var e=f[d],g=e.isBaseLayer;if(e.displayInLayerSwitcher){g?b=!0:a=!0;var h=g?e==this.map.baseLayer:e.getVisibility(),k=document.createElement("input"),l=OpenLayers.Util.createUniqueID(this.id+
-"_input_");k.id=l;k.name=g?this.id+"_baseLayers":e.name;k.type=g?"radio":"checkbox";k.value=e.name;k.checked=h;k.defaultChecked=h;k.className="olButton";k._layer=e.id;k._layerSwitcher=this.id;g||e.inRange||(k.disabled=!0);h=document.createElement("label");h["for"]=k.id;OpenLayers.Element.addClass(h,"labelSpan olButton");h._layer=e.id;h._layerSwitcher=this.id;g||e.inRange||(h.style.color="gray");h.innerHTML=e.name;h.style.verticalAlign=g?"bottom":"baseline";l=document.createElement("br");(g?this.baseLayers:
-this.dataLayers).push({layer:e,inputElem:k,labelSpan:h});e=g?this.baseLayersDiv:this.dataLayersDiv;e.appendChild(k);e.appendChild(h);e.appendChild(l)}}this.dataLbl.style.display=a?"":"none";this.baseLbl.style.display=b?"":"none";return this.div},updateMap:function(){for(var a=0,b=this.baseLayers.length;a<b;a++){var c=this.baseLayers[a];c.inputElem.checked&&this.map.setBaseLayer(c.layer,!1)}a=0;for(b=this.dataLayers.length;a<b;a++)c=this.dataLayers[a],c.layer.setVisibility(c.inputElem.checked)},maximizeControl:function(a){this.div.style.width=
-"";this.div.style.height="";this.showControls(!1);null!=a&&OpenLayers.Event.stop(a)},minimizeControl:function(a){this.div.style.width="0px";this.div.style.height="0px";this.showControls(!0);null!=a&&OpenLayers.Event.stop(a)},showControls:function(a){this.maximizeDiv.style.display=a?"":"none";this.minimizeDiv.style.display=a?"none":"";this.layersDiv.style.display=a?"none":""},loadContents:function(){this.layersDiv=document.createElement("div");this.layersDiv.id=this.id+"_layersDiv";OpenLayers.Element.addClass(this.layersDiv,
-"layersDiv");this.baseLbl=document.createElement("div");this.baseLbl.innerHTML=OpenLayers.i18n("Base Layer");OpenLayers.Element.addClass(this.baseLbl,"baseLbl");this.baseLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.baseLayersDiv,"baseLayersDiv");this.dataLbl=document.createElement("div");this.dataLbl.innerHTML=OpenLayers.i18n("Overlays");OpenLayers.Element.addClass(this.dataLbl,"dataLbl");this.dataLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.dataLayersDiv,
-"dataLayersDiv");this.ascending?(this.layersDiv.appendChild(this.baseLbl),this.layersDiv.appendChild(this.baseLayersDiv),this.layersDiv.appendChild(this.dataLbl),this.layersDiv.appendChild(this.dataLayersDiv)):(this.layersDiv.appendChild(this.dataLbl),this.layersDiv.appendChild(this.dataLayersDiv),this.layersDiv.appendChild(this.baseLbl),this.layersDiv.appendChild(this.baseLayersDiv));this.div.appendChild(this.layersDiv);var a=OpenLayers.Util.getImageLocation("layer-switcher-maximize.png");this.maximizeDiv=
-OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv",null,null,a,"absolute");OpenLayers.Element.addClass(this.maximizeDiv,"maximizeDiv olButton");this.maximizeDiv.style.display="none";this.div.appendChild(this.maximizeDiv);a=OpenLayers.Util.getImageLocation("layer-switcher-minimize.png");this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv",null,null,a,"absolute");OpenLayers.Element.addClass(this.minimizeDiv,"minimizeDiv olButton");this.minimizeDiv.style.display=
-"none";this.div.appendChild(this.minimizeDiv)},CLASS_NAME:"OpenLayers.Control.LayerSwitcher"});OpenLayers.Format.Atom=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{atom:"http://www.w3.org/2005/Atom",georss:"http://www.georss.org/georss"},feedTitle:"untitled",defaultEntryTitle:"untitled",gmlParser:null,xy:!1,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));return this.parseFeatures(a)},write:function(a){var b;if(OpenLayers.Util.isArray(a)){b=this.createElementNSPlus("atom:feed");b.appendChild(this.createElementNSPlus("atom:title",{value:this.feedTitle}));
-for(var c=0,d=a.length;c<d;c++)b.appendChild(this.buildEntryNode(a[c]))}else b=this.buildEntryNode(a);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},buildContentNode:function(a){var b=this.createElementNSPlus("atom:content",{attributes:{type:a.type||null}});if(a.src)b.setAttribute("src",a.src);else if("text"==a.type||null==a.type)b.appendChild(this.createTextNode(a.value));else if("html"==a.type){if("string"!=typeof a.value)throw"HTML content must be in form of an escaped string";b.appendChild(this.createTextNode(a.value))}else"xhtml"==
-a.type?b.appendChild(a.value):"xhtml"==a.type||a.type.match(/(\+|\/)xml$/)?b.appendChild(a.value):b.appendChild(this.createTextNode(a.value));return b},buildEntryNode:function(a){var b=a.attributes,c=b.atom||{},d=this.createElementNSPlus("atom:entry");if(c.authors)for(var e=OpenLayers.Util.isArray(c.authors)?c.authors:[c.authors],f=0,g=e.length;f<g;f++)d.appendChild(this.buildPersonConstructNode("author",e[f]));if(c.categories)for(var e=OpenLayers.Util.isArray(c.categories)?c.categories:[c.categories],
-h,f=0,g=e.length;f<g;f++)h=e[f],d.appendChild(this.createElementNSPlus("atom:category",{attributes:{term:h.term,scheme:h.scheme||null,label:h.label||null}}));c.content&&d.appendChild(this.buildContentNode(c.content));if(c.contributors)for(e=OpenLayers.Util.isArray(c.contributors)?c.contributors:[c.contributors],f=0,g=e.length;f<g;f++)d.appendChild(this.buildPersonConstructNode("contributor",e[f]));a.fid&&d.appendChild(this.createElementNSPlus("atom:id",{value:a.fid}));if(c.links)for(e=OpenLayers.Util.isArray(c.links)?
-c.links:[c.links],f=0,g=e.length;f<g;f++)h=e[f],d.appendChild(this.createElementNSPlus("atom:link",{attributes:{href:h.href,rel:h.rel||null,type:h.type||null,hreflang:h.hreflang||null,title:h.title||null,length:h.length||null}}));c.published&&d.appendChild(this.createElementNSPlus("atom:published",{value:c.published}));c.rights&&d.appendChild(this.createElementNSPlus("atom:rights",{value:c.rights}));(c.summary||b.description)&&d.appendChild(this.createElementNSPlus("atom:summary",{value:c.summary||
-b.description}));d.appendChild(this.createElementNSPlus("atom:title",{value:c.title||b.title||this.defaultEntryTitle}));c.updated&&d.appendChild(this.createElementNSPlus("atom:updated",{value:c.updated}));a.geometry&&(b=this.createElementNSPlus("georss:where"),b.appendChild(this.buildGeometryNode(a.geometry)),d.appendChild(b));return d},initGmlParser:function(){this.gmlParser=new OpenLayers.Format.GML.v3({xy:this.xy,featureNS:"http://example.com#feature",internalProjection:this.internalProjection,
-externalProjection:this.externalProjection})},buildGeometryNode:function(a){this.gmlParser||this.initGmlParser();return this.gmlParser.writeNode("feature:_geometry",a).firstChild},buildPersonConstructNode:function(a,b){var c=["uri","email"],d=this.createElementNSPlus("atom:"+a);d.appendChild(this.createElementNSPlus("atom:name",{value:b.name}));for(var e=0,f=c.length;e<f;e++)b[c[e]]&&d.appendChild(this.createElementNSPlus("atom:"+c[e],{value:b[c[e]]}));return d},getFirstChildValue:function(a,b,c,
-d){return(a=this.getElementsByTagNameNS(a,b,c))&&0<a.length?this.getChildValue(a[0],d):d},parseFeature:function(a){var b={},c=null,d=null,e=null,f=this.namespaces.atom;this.parsePersonConstructs(a,"author",b);d=this.getElementsByTagNameNS(a,f,"category");0<d.length&&(b.categories=[]);for(var g=0,h=d.length;g<h;g++){c={};c.term=d[g].getAttribute("term");if(e=d[g].getAttribute("scheme"))c.scheme=e;if(e=d[g].getAttribute("label"))c.label=e;b.categories.push(c)}d=this.getElementsByTagNameNS(a,f,"content");
-if(0<d.length){c={};if(e=d[0].getAttribute("type"))c.type=e;(e=d[0].getAttribute("src"))?c.src=e:("text"==c.type||"html"==c.type||null==c.type?c.value=this.getFirstChildValue(a,f,"content",null):"xhtml"==c.type||c.type.match(/(\+|\/)xml$/)?c.value=this.getChildEl(d[0]):c.value=this.getFirstChildValue(a,f,"content",null),b.content=c)}this.parsePersonConstructs(a,"contributor",b);b.id=this.getFirstChildValue(a,f,"id",null);d=this.getElementsByTagNameNS(a,f,"link");0<d.length&&(b.links=Array(d.length));
-for(var k=["rel","type","hreflang","title","length"],g=0,h=d.length;g<h;g++){c={};c.href=d[g].getAttribute("href");for(var l=0,m=k.length;l<m;l++)(e=d[g].getAttribute(k[l]))&&(c[k[l]]=e);b.links[g]=c}if(c=this.getFirstChildValue(a,f,"published",null))b.published=c;if(c=this.getFirstChildValue(a,f,"rights",null))b.rights=c;if(c=this.getFirstChildValue(a,f,"summary",null))b.summary=c;b.title=this.getFirstChildValue(a,f,"title",null);b.updated=this.getFirstChildValue(a,f,"updated",null);c={title:b.title,
-description:b.summary,atom:b};a=this.parseLocations(a)[0];a=new OpenLayers.Feature.Vector(a,c);a.fid=b.id;return a},parseFeatures:function(a){var b=[],c=this.getElementsByTagNameNS(a,this.namespaces.atom,"entry");0==c.length&&(c=[a]);a=0;for(var d=c.length;a<d;a++)b.push(this.parseFeature(c[a]));return b},parseLocations:function(a){var b=this.namespaces.georss,c={components:[]},d=this.getElementsByTagNameNS(a,b,"where");if(d&&0<d.length){this.gmlParser||this.initGmlParser();for(var e=0,f=d.length;e<
-f;e++)this.gmlParser.readChildNodes(d[e],c)}c=c.components;if((d=this.getElementsByTagNameNS(a,b,"point"))&&0<d.length)for(e=0,f=d.length;e<f;e++){var g=OpenLayers.String.trim(d[e].firstChild.nodeValue).split(/\s+/);2!=g.length&&(g=OpenLayers.String.trim(d[e].firstChild.nodeValue).split(/\s*,\s*/));c.push(new OpenLayers.Geometry.Point(g[1],g[0]))}var h=this.getElementsByTagNameNS(a,b,"line");if(h&&0<h.length)for(var k,e=0,f=h.length;e<f;e++){d=OpenLayers.String.trim(h[e].firstChild.nodeValue).split(/\s+/);
-k=[];for(var l=0,m=d.length;l<m;l+=2)g=new OpenLayers.Geometry.Point(d[l+1],d[l]),k.push(g);c.push(new OpenLayers.Geometry.LineString(k))}if((a=this.getElementsByTagNameNS(a,b,"polygon"))&&0<a.length)for(e=0,f=a.length;e<f;e++){d=OpenLayers.String.trim(a[e].firstChild.nodeValue).split(/\s+/);k=[];l=0;for(m=d.length;l<m;l+=2)g=new OpenLayers.Geometry.Point(d[l+1],d[l]),k.push(g);c.push(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(k)]))}if(this.internalProjection&&this.externalProjection)for(e=
-0,f=c.length;e<f;e++)c[e]&&c[e].transform(this.externalProjection,this.internalProjection);return c},parsePersonConstructs:function(a,b,c){var d=[],e=this.namespaces.atom;a=this.getElementsByTagNameNS(a,e,b);for(var f=["uri","email"],g=0,h=a.length;g<h;g++){var k={};k.name=this.getFirstChildValue(a[g],e,"name",null);for(var l=0,m=f.length;l<m;l++){var n=this.getFirstChildValue(a[g],e,f[l],null);n&&(k[f[l]]=n)}d.push(k)}0<d.length&&(c[b+"s"]=d)},CLASS_NAME:"OpenLayers.Format.Atom"});OpenLayers.Control.KeyboardDefaults=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,slideFactor:75,observeElement:null,draw:function(){this.handler=new OpenLayers.Handler.Keyboard(this,{keydown:this.defaultKeyPress},{observeElement:this.observeElement||document})},defaultKeyPress:function(a){var b,c=!0;b=OpenLayers.Event.element(a);if(!b||"INPUT"!=b.tagName&&"TEXTAREA"!=b.tagName&&"SELECT"!=b.tagName){switch(a.keyCode){case OpenLayers.Event.KEY_LEFT:this.map.pan(-this.slideFactor,0);break;case OpenLayers.Event.KEY_RIGHT:this.map.pan(this.slideFactor,
-0);break;case OpenLayers.Event.KEY_UP:this.map.pan(0,-this.slideFactor);break;case OpenLayers.Event.KEY_DOWN:this.map.pan(0,this.slideFactor);break;case 33:b=this.map.getSize();this.map.pan(0,-0.75*b.h);break;case 34:b=this.map.getSize();this.map.pan(0,0.75*b.h);break;case 35:b=this.map.getSize();this.map.pan(0.75*b.w,0);break;case 36:b=this.map.getSize();this.map.pan(-0.75*b.w,0);break;case 43:case 61:case 187:case 107:this.map.zoomIn();break;case 45:case 109:case 189:case 95:this.map.zoomOut();
-break;default:c=!1}c&&OpenLayers.Event.stop(a)}},CLASS_NAME:"OpenLayers.Control.KeyboardDefaults"});OpenLayers.Format.WMTSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0,{version:"1.0.0",namespaces:{ows:"http://www.opengis.net/ows/1.1",wmts:"http://www.opengis.net/wmts/1.0",xlink:"http://www.w3.org/1999/xlink"},yx:null,defaultPrefix:"wmts",initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.options=a;a=OpenLayers.Util.extend({},OpenLayers.Format.WMTSCapabilities.prototype.yx);this.yx=OpenLayers.Util.extend(a,this.yx)},read:function(a){"string"==
-typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);b.version=this.version;return b},readers:{wmts:{Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,b){b.contents={};b.contents.layers=[];b.contents.tileMatrixSets={};this.readChildNodes(a,b.contents)},Layer:function(a,b){var c={styles:[],formats:[],dimensions:[],tileMatrixSetLinks:[],layers:[]};this.readChildNodes(a,c);b.layers.push(c)},Style:function(a,
-b){var c={};c.isDefault="true"===a.getAttribute("isDefault");this.readChildNodes(a,c);b.styles.push(c)},Format:function(a,b){b.formats.push(this.getChildValue(a))},TileMatrixSetLink:function(a,b){var c={};this.readChildNodes(a,c);b.tileMatrixSetLinks.push(c)},TileMatrixSet:function(a,b){if(b.layers){var c={matrixIds:[]};this.readChildNodes(a,c);b.tileMatrixSets[c.identifier]=c}else b.tileMatrixSet=this.getChildValue(a)},TileMatrix:function(a,b){var c={supportedCRS:b.supportedCRS};this.readChildNodes(a,
-c);b.matrixIds.push(c)},ScaleDenominator:function(a,b){b.scaleDenominator=parseFloat(this.getChildValue(a))},TopLeftCorner:function(a,b){var c=this.getChildValue(a).split(" "),d;b.supportedCRS&&(d=b.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/,"urn:ogc:def:crs:$1::$2"),d=!!this.yx[d]);b.topLeftCorner=d?new OpenLayers.LonLat(c[1],c[0]):new OpenLayers.LonLat(c[0],c[1])},TileWidth:function(a,b){b.tileWidth=parseInt(this.getChildValue(a))},TileHeight:function(a,b){b.tileHeight=parseInt(this.getChildValue(a))},
-MatrixWidth:function(a,b){b.matrixWidth=parseInt(this.getChildValue(a))},MatrixHeight:function(a,b){b.matrixHeight=parseInt(this.getChildValue(a))},ResourceURL:function(a,b){b.resourceUrl=b.resourceUrl||{};var c=a.getAttribute("resourceType");b.resourceUrls||(b.resourceUrls=[]);c=b.resourceUrl[c]={format:a.getAttribute("format"),template:a.getAttribute("template"),resourceType:c};b.resourceUrls.push(c)},WSDL:function(a,b){b.wsdl={};b.wsdl.href=a.getAttribute("xlink:href")},ServiceMetadataURL:function(a,
-b){b.serviceMetadataUrl={};b.serviceMetadataUrl.href=a.getAttribute("xlink:href")},LegendURL:function(a,b){b.legend={};b.legend.href=a.getAttribute("xlink:href");b.legend.format=a.getAttribute("format")},Dimension:function(a,b){var c={values:[]};this.readChildNodes(a,c);b.dimensions.push(c)},Default:function(a,b){b["default"]=this.getChildValue(a)},Value:function(a,b){b.values.push(this.getChildValue(a))}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities.v1_0_0"});
diff --git a/chimere/static/openlayers/OpenLayers.mobile.js b/chimere/static/openlayers/OpenLayers.mobile.js
deleted file mode 100644
index cf5d025..0000000
--- a/chimere/static/openlayers/OpenLayers.mobile.js
+++ /dev/null
@@ -1,1654 +0,0 @@
-/*
-
- OpenLayers.js -- OpenLayers Map Viewer Library
-
- Copyright (c) 2006-2013 by OpenLayers Contributors
- Published under the 2-clause BSD license.
- See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
-
- Includes compressed code under the following licenses:
-
- (For uncompressed versions of the code used, please see the
- OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
-
-*/
-
-/**
- * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
- * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- */
-
-/**
- * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
- * Copyright (c) 2006, Yahoo! Inc.
- * All rights reserved.
- *
- * Redistribution and use of this software in source and binary forms, with or
- * without modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission of Yahoo! Inc.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-var OpenLayers={VERSION_NUMBER:"Release 2.13.1",singleFile:true,_getScriptLocation:(function(){var r=new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),s=document.getElementsByTagName('script'),src,m,l="";for(var i=0,len=s.length;i<len;i++){src=s[i].getAttribute('src');if(src){m=src.match(r);if(m){l=m[1];break;}}}
-return(function(){return l;});})(),ImgPath:''};OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s\s*/,'').replace(/\s\s*$/,'');},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1,len=oStringList.length;i<len;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
-return camelizedString;},format:function(template,context,args){if(!context){context=window;}
-var replacer=function(str,match){var replacement;var subs=match.split(/\.+/);for(var i=0;i<subs.length;i++){if(i==0){replacement=context;}
-if(replacement===undefined){break;}
-replacement=replacement[subs[i]];}
-if(typeof replacement=="function"){replacement=args?replacement.apply(null,args):replacement();}
-if(typeof replacement=='undefined'){return'undefined';}else{return replacement;}};return template.replace(OpenLayers.String.tokenRegEx,replacer);},tokenRegEx:/\$\{([\w.]+?)\}/g,numberRegEx:/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,isNumeric:function(value){return OpenLayers.String.numberRegEx.test(value);},numericIf:function(value,trimWhitespace){var originalValue=value;if(trimWhitespace===true&&value!=null&&value.replace){value=value.replace(/^\s*|\s*$/g,"");}
-return OpenLayers.String.isNumeric(value)?parseFloat(value):originalValue;}};OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(num,sig){var fig=0;if(sig>0){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.length<len){str="0"+str;}
-return str;}};OpenLayers.Function={bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},bindAsEventListener:function(func,object){return function(event){return func.call(object,event||window.event);};},False:function(){return false;},True:function(){return true;},Void:function(){}};OpenLayers.Array={filter:function(array,callback,caller){var selected=[];if(Array.prototype.filter){selected=array.filter(callback,caller);}else{var len=array.length;if(typeof callback!="function"){throw new TypeError();}
-for(var i=0;i<len;i++){if(i in array){var val=array[i];if(callback.call(caller,val,i,array)){selected.push(val);}}}}
-return selected;}};OpenLayers.Class=function(){var len=arguments.length;var P=arguments[0];var F=arguments[len-1];var C=typeof F.initialize=="function"?F.initialize:function(){P.prototype.initialize.apply(this,arguments);};if(len>1){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;i<l;i++){o=arguments[i];if(typeof o==="function"){o=o.prototype;}
-OpenLayers.Util.extend(C.prototype,o);}};OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.extend=function(destination,source){destination=destination||{};if(source){for(var property in source){var value=source[property];if(value!==undefined){destination[property]=value;}}
-var sourceIsEvt=typeof window.Event=="function"&&source instanceof window.Event;if(!sourceIsEvt&&source.hasOwnProperty&&source.hasOwnProperty("toString")){destination.toString=source.toString;}}
-return destination;};OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,centerLonLat:null,initialize:function(left,bottom,right,top){if(OpenLayers.Util.isArray(left)){top=left[3];right=left[2];bottom=left[1];left=left[0];}
-if(left!=null){this.left=OpenLayers.Util.toFloat(left);}
-if(bottom!=null){this.bottom=OpenLayers.Util.toFloat(bottom);}
-if(right!=null){this.right=OpenLayers.Util.toFloat(right);}
-if(top!=null){this.top=OpenLayers.Util.toFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},equals:function(bounds){var equals=false;if(bounds!=null){equals=((this.left==bounds.left)&&(this.right==bounds.right)&&(this.top==bounds.top)&&(this.bottom==bounds.bottom));}
-return equals;},toString:function(){return[this.left,this.bottom,this.right,this.top].join(",");},toArray:function(reverseAxisOrder){if(reverseAxisOrder===true){return[this.bottom,this.left,this.top,this.right];}else{return[this.left,this.bottom,this.right,this.top];}},toBBOX:function(decimal,reverseAxisOrder){if(decimal==null){decimal=6;}
-var mult=Math.pow(10,decimal);var xmin=Math.round(this.left*mult)/mult;var ymin=Math.round(this.bottom*mult)/mult;var xmax=Math.round(this.right*mult)/mult;var ymax=Math.round(this.top*mult)/mult;if(reverseAxisOrder===true){return ymin+","+xmin+","+ymax+","+xmax;}else{return xmin+","+ymin+","+xmax+","+ymax;}},toGeometry:function(){return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(this.left,this.bottom),new OpenLayers.Geometry.Point(this.right,this.bottom),new OpenLayers.Geometry.Point(this.right,this.top),new OpenLayers.Geometry.Point(this.left,this.top)])]);},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){if(!this.centerLonLat){this.centerLonLat=new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);}
-return this.centerLonLat;},scale:function(ratio,origin){if(origin==null){origin=this.getCenterLonLat();}
-var origx,origy;if(origin.CLASS_NAME=="OpenLayers.LonLat"){origx=origin.lon;origy=origin.lat;}else{origx=origin.x;origy=origin.y;}
-var left=(this.left-origx)*ratio+origx;var bottom=(this.bottom-origy)*ratio+origy;var right=(this.right-origx)*ratio+origx;var top=(this.top-origy)*ratio+origy;return new OpenLayers.Bounds(left,bottom,right,top);},add:function(x,y){if((x==null)||(y==null)){throw new TypeError('Bounds.add cannot receive null values');}
-return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){if(object){switch(object.CLASS_NAME){case"OpenLayers.LonLat":this.extendXY(object.lon,object.lat);break;case"OpenLayers.Geometry.Point":this.extendXY(object.x,object.y);break;case"OpenLayers.Bounds":this.centerLonLat=null;if((this.left==null)||(object.left<this.left)){this.left=object.left;}
-if((this.bottom==null)||(object.bottom<this.bottom)){this.bottom=object.bottom;}
-if((this.right==null)||(object.right>this.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)||(x<this.left)){this.left=x;}
-if((this.bottom==null)||(y<this.bottom)){this.bottom=y;}
-if((this.right==null)||(x>this.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)&&(x<this.right)&&(y>this.bottom)&&(y<this.top));}
-return contains;},intersectsBounds:function(bounds,options){if(typeof options==="boolean"){options={inclusive:options};}
-options=options||{};if(options.worldBounds){var self=this.wrapDateLine(options.worldBounds);bounds=bounds.wrapDateLine(options.worldBounds);}else{self=this;}
-if(options.inclusive==null){options.inclusive=true;}
-var intersects=false;var mightTouch=(self.left==bounds.right||self.right==bounds.left||self.top==bounds.bottom||self.bottom==bounds.top);if(options.inclusive||!mightTouch){var inBottom=(((bounds.bottom>=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<bounds.top)));var inLeft=(((bounds.left>=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<center.lat)?"b":"t";quadrant+=(lonlat.lon<center.lon)?"l":"r";return quadrant;},transform:function(source,dest){this.centerLonLat=null;var ll=OpenLayers.Projection.transform({'x':this.left,'y':this.bottom},source,dest);var lr=OpenLayers.Projection.transform({'x':this.right,'y':this.bottom},source,dest);var ul=OpenLayers.Projection.transform({'x':this.left,'y':this.top},source,dest);var ur=OpenLayers.Projection.transform({'x':this.right,'y':this.top},source,dest);this.left=Math.min(ll.x,ul.x);this.bottom=Math.min(ll.y,lr.y);this.right=Math.max(lr.x,ur.x);this.top=Math.max(ul.y,ur.y);return this;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){var width=maxExtent.getWidth();while(newBounds.left<maxExtent.left&&newBounds.right-rightTolerance<=maxExtent.left){newBounds=newBounds.add(width,0);}
-while(newBounds.left+leftTolerance>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-width,0);}
-var newLeft=newBounds.left+leftTolerance;if(newLeft<maxExtent.right&&newLeft>maxExtent.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.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0,len=arguments.length;i<len;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'none':'';element.style.display=display;}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},hasClass:function(element,name){var names=element.className;return(!!names&&new RegExp("(^|\\s)"+name+"(\\s|$)").test(names));},addClass:function(element,name){if(!OpenLayers.Element.hasClass(element,name)){element.className+=(element.className?" ":"")+name;}
-return element;},removeClass:function(element,name){var names=element.className;if(names){element.className=OpenLayers.String.trim(names.replace(new RegExp("(^|\\s+)"+name+"(\\s+|$)")," "));}
-return element;},toggleClass:function(element,name){if(OpenLayers.Element.hasClass(element,name)){OpenLayers.Element.removeClass(element,name);}else{OpenLayers.Element.addClass(element,name);}
-return element;},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=null;if(element&&element.style){value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
-var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}}
-return value=='auto'?null:value;}};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.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
-while(newLonLat.lon>maxExtent.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.Pixel=OpenLayers.Class({x:0.0,y:0.0,initialize:function(x,y){this.x=parseFloat(x);this.y=parseFloat(y);},toString:function(){return("x="+this.x+",y="+this.y);},clone:function(){return new OpenLayers.Pixel(this.x,this.y);},equals:function(px){var equals=false;if(px!=null){equals=((this.x==px.x&&this.y==px.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(px.x)&&isNaN(px.y)));}
-return equals;},distanceTo:function(px){return Math.sqrt(Math.pow(this.x-px.x,2)+
-Math.pow(this.y-px.y,2));},add:function(x,y){if((x==null)||(y==null)){throw new TypeError('Pixel.add cannot receive null values');}
-return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);}
-return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},equals:function(sz){var equals=false;if(sz!=null){equals=((this.w==sz.w&&this.h==sz.h)||(isNaN(this.w)&&isNaN(this.h)&&isNaN(sz.w)&&isNaN(sz.h)));}
-return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(error){alert(error);},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){if(console){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();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.Util=OpenLayers.Util||{};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0,len=arguments.length;i<len;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
-if(arguments.length==1){return element;}
-elements.push(element);}
-return elements;};OpenLayers.Util.isElement=function(o){return!!(o&&o.nodeType===1);};OpenLayers.Util.isArray=function(a){return(Object.prototype.toString.call(a)==='[object Array]');};OpenLayers.Util.removeItem=function(array,item){for(var i=array.length-1;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<len;i++){if(array[i]==obj){return i;}}
-return-1;}};OpenLayers.Util.dotless=/\./g;OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id.replace(OpenLayers.Util.dotless,"_");}
-if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
-if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
-if(position){element.style.position=position;}
-if(border){element.style.border=border;}
-if(overflow){element.style.overflow=overflow;}
-if(parseFloat(opacity)>=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;itemIndex<len;itemIndex++){item=value[itemIndex];encodedItemArray.push(encodeURIComponent((item===null||item===undefined)?"":item));}
-encodedValue=encodedItemArray.join(",");}
-else{encodedValue=encodeURIComponent(value);}
-paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
-return paramsArray.join("&");};OpenLayers.Util.urlAppend=function(url,paramStr){var newUrl=url;if(paramStr){var parts=(url+" ").split(/[?&]/);newUrl+=(parts.pop()===" "?paramStr:parts.length?"&"+paramStr:"?"+paramStr);}
-return newUrl;};OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.getImageLocation=function(image){return OpenLayers.Util.getImagesLocation()+image;};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0,len=arguments.length;i<len;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
-return returnValue;};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val){val=node.textContent;}
-if(!val){val=node.firstChild.nodeValue;}},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
-return(target!=div);};OpenLayers.Util.DEFAULT_PRECISION=14;OpenLayers.Util.toFloat=function(number,precision){if(precision==null){precision=OpenLayers.Util.DEFAULT_PRECISION;}
-if(typeof number!=="number"){number=parseFloat(number);}
-return precision===0?number:parseFloat(number.toPrecision(precision));};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.deg=function(x){return x*180/Math.PI;};OpenLayers.Util.VincentyConstants={a:6378137,b:6356752.3142,f:1/298.257223563};OpenLayers.Util.distVincenty=function(p1,p2){var ct=OpenLayers.Util.VincentyConstants;var a=ct.a,b=ct.b,f=ct.f;var L=OpenLayers.Util.rad(p2.lon-p1.lon);var U1=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p1.lat)));var U2=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p2.lat)));var sinU1=Math.sin(U1),cosU1=Math.cos(U1);var sinU2=Math.sin(U2),cosU2=Math.cos(U2);var lambda=L,lambdaP=2*Math.PI;var iterLimit=20;while(Math.abs(lambda-lambdaP)>1e-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;i<len;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=keyValue[0];try{key=decodeURIComponent(key);}catch(err){key=unescape(key);}
-var value=(keyValue[1]||'').replace(/\+/g," ");try{value=decodeURIComponent(value);}catch(err){value=unescape(value);}
-if(options.splitArgs!==false){value=value.split(",");}
-if(value.length==1){value=value[0];}
-parameters[key]=value;}}
-return parameters;};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}else{prefix=prefix.replace(OpenLayers.Util.dotless,"_");}
-OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.37,'km':39370,'dd':4374754,'yd':36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT["nmi"]=1852*OpenLayers.INCHES_PER_UNIT.m;OpenLayers.METERS_PER_INCH=0.02540005080010160020;OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{"Inch":OpenLayers.INCHES_PER_UNIT.inches,"Meter":1.0/OpenLayers.METERS_PER_INCH,"Foot":0.30480060960121920243/OpenLayers.METERS_PER_INCH,"IFoot":0.30480000000000000000/OpenLayers.METERS_PER_INCH,"ClarkeFoot":0.3047972651151/OpenLayers.METERS_PER_INCH,"SearsFoot":0.30479947153867624624/OpenLayers.METERS_PER_INCH,"GoldCoastFoot":0.30479971018150881758/OpenLayers.METERS_PER_INCH,"IInch":0.02540000000000000000/OpenLayers.METERS_PER_INCH,"MicroInch":0.00002540000000000000/OpenLayers.METERS_PER_INCH,"Mil":0.00000002540000000000/OpenLayers.METERS_PER_INCH,"Centimeter":0.01000000000000000000/OpenLayers.METERS_PER_INCH,"Kilometer":1000.00000000000000000000/OpenLayers.METERS_PER_INCH,"Yard":0.91440182880365760731/OpenLayers.METERS_PER_INCH,"SearsYard":0.914398414616029/OpenLayers.METERS_PER_INCH,"IndianYard":0.91439853074444079983/OpenLayers.METERS_PER_INCH,"IndianYd37":0.91439523/OpenLayers.METERS_PER_INCH,"IndianYd62":0.9143988/OpenLayers.METERS_PER_INCH,"IndianYd75":0.9143985/OpenLayers.METERS_PER_INCH,"IndianFoot":0.30479951/OpenLayers.METERS_PER_INCH,"IndianFt37":0.30479841/OpenLayers.METERS_PER_INCH,"IndianFt62":0.3047996/OpenLayers.METERS_PER_INCH,"IndianFt75":0.3047995/OpenLayers.METERS_PER_INCH,"Mile":1609.34721869443738887477/OpenLayers.METERS_PER_INCH,"IYard":0.91440000000000000000/OpenLayers.METERS_PER_INCH,"IMile":1609.34400000000000000000/OpenLayers.METERS_PER_INCH,"NautM":1852.00000000000000000000/OpenLayers.METERS_PER_INCH,"Lat-66":110943.316488932731/OpenLayers.METERS_PER_INCH,"Lat-83":110946.25736872234125/OpenLayers.METERS_PER_INCH,"Decimeter":0.10000000000000000000/OpenLayers.METERS_PER_INCH,"Millimeter":0.00100000000000000000/OpenLayers.METERS_PER_INCH,"Dekameter":10.00000000000000000000/OpenLayers.METERS_PER_INCH,"Decameter":10.00000000000000000000/OpenLayers.METERS_PER_INCH,"Hectometer":100.00000000000000000000/OpenLayers.METERS_PER_INCH,"GermanMeter":1.0000135965/OpenLayers.METERS_PER_INCH,"CaGrid":0.999738/OpenLayers.METERS_PER_INCH,"ClarkeChain":20.1166194976/OpenLayers.METERS_PER_INCH,"GunterChain":20.11684023368047/OpenLayers.METERS_PER_INCH,"BenoitChain":20.116782494375872/OpenLayers.METERS_PER_INCH,"SearsChain":20.11676512155/OpenLayers.METERS_PER_INCH,"ClarkeLink":0.201166194976/OpenLayers.METERS_PER_INCH,"GunterLink":0.2011684023368047/OpenLayers.METERS_PER_INCH,"BenoitLink":0.20116782494375872/OpenLayers.METERS_PER_INCH,"SearsLink":0.2011676512155/OpenLayers.METERS_PER_INCH,"Rod":5.02921005842012/OpenLayers.METERS_PER_INCH,"IntnlChain":20.1168/OpenLayers.METERS_PER_INCH,"IntnlLink":0.201168/OpenLayers.METERS_PER_INCH,"Perch":5.02921005842012/OpenLayers.METERS_PER_INCH,"Pole":5.02921005842012/OpenLayers.METERS_PER_INCH,"Furlong":201.1684023368046/OpenLayers.METERS_PER_INCH,"Rood":3.778266898/OpenLayers.METERS_PER_INCH,"CapeFoot":0.3047972615/OpenLayers.METERS_PER_INCH,"Brealey":375.00000000000000000000/OpenLayers.METERS_PER_INCH,"ModAmFt":0.304812252984505969011938/OpenLayers.METERS_PER_INCH,"Fathom":1.8288/OpenLayers.METERS_PER_INCH,"NautM-UK":1853.184/OpenLayers.METERS_PER_INCH,"50kilometers":50000.0/OpenLayers.METERS_PER_INCH,"150kilometers":150000.0/OpenLayers.METERS_PER_INCH});OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{"mm":OpenLayers.INCHES_PER_UNIT["Meter"]/1000.0,"cm":OpenLayers.INCHES_PER_UNIT["Meter"]/100.0,"dm":OpenLayers.INCHES_PER_UNIT["Meter"]*100.0,"km":OpenLayers.INCHES_PER_UNIT["Meter"]*1000.0,"kmi":OpenLayers.INCHES_PER_UNIT["nmi"],"fath":OpenLayers.INCHES_PER_UNIT["Fathom"],"ch":OpenLayers.INCHES_PER_UNIT["IntnlChain"],"link":OpenLayers.INCHES_PER_UNIT["IntnlLink"],"us-in":OpenLayers.INCHES_PER_UNIT["inches"],"us-ft":OpenLayers.INCHES_PER_UNIT["Foot"],"us-yd":OpenLayers.INCHES_PER_UNIT["Yard"],"us-ch":OpenLayers.INCHES_PER_UNIT["GunterChain"],"us-mi":OpenLayers.INCHES_PER_UNIT["Mile"],"ind-yd":OpenLayers.INCHES_PER_UNIT["IndianYd37"],"ind-ft":OpenLayers.INCHES_PER_UNIT["IndianFt37"],"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.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<l;i++){if(!content.childNodes[i].style)continue;content.childNodes[i].style.overflow="visible";}}
-container.appendChild(content);if(superContainer){containerElement.appendChild(superContainer);}else{containerElement.appendChild(container);}
-if(!w){w=parseInt(content.scrollWidth);container.style.width=w+"px";}
-if(!h){h=parseInt(content.scrollHeight);}
-container.removeChild(content);if(superContainer){superContainer.removeChild(container);containerElement.removeChild(superContainer);}else{containerElement.removeChild(container);}
-return new OpenLayers.Size(w,h);};OpenLayers.Util.getScrollbarWidth=function(){var scrollbarWidth=OpenLayers.Util._scrollbarWidth;if(scrollbarWidth==null){var scr=null;var inn=null;var wNoScroll=0;var wScroll=0;scr=document.createElement('div');scr.style.position='absolute';scr.style.top='-1000px';scr.style.left='-1000px';scr.style.width='100px';scr.style.height='50px';scr.style.overflow='hidden';inn=document.createElement('div');inn.style.width='100%';inn.style.height='200px';scr.appendChild(inn);document.body.appendChild(scr);wNoScroll=inn.offsetWidth;scr.style.overflow='scroll';wScroll=inn.offsetWidth;document.body.removeChild(document.body.lastChild);OpenLayers.Util._scrollbarWidth=(wNoScroll-wScroll);scrollbarWidth=OpenLayers.Util._scrollbarWidth;}
-return scrollbarWidth;};OpenLayers.Util.getFormattedLonLat=function(coordinate,axis,dmsOption){if(!dmsOption){dmsOption='dms';}
-coordinate=(coordinate+540)%360-180;var abscoordinate=Math.abs(coordinate);var coordinatedegrees=Math.floor(abscoordinate);var coordinateminutes=(abscoordinate-coordinatedegrees)/(1/60);var tempcoordinateminutes=coordinateminutes;coordinateminutes=Math.floor(coordinateminutes);var coordinateseconds=(tempcoordinateminutes-coordinateminutes)/(1/60);coordinateseconds=Math.round(coordinateseconds*10);coordinateseconds/=10;if(coordinateseconds>=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.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&&i<elementObservers.length){var cacheEntry=elementObservers[i];if((cacheEntry.name==name)&&(cacheEntry.observer==observer)&&(cacheEntry.useCapture==useCapture)){elementObservers.splice(i,1);if(elementObservers.length==0){delete OpenLayers.Event.observers[cacheID];}
-foundEntry=true;break;}
-i++;}}
-if(foundEntry){if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}}
-return foundEntry;},unloadCache:function(){if(OpenLayers.Event&&OpenLayers.Event.observers){for(var cacheID in OpenLayers.Event.observers){var elementObservers=OpenLayers.Event.observers[cacheID];OpenLayers.Event._removeElementObservers.apply(this,[elementObservers]);}
-OpenLayers.Event.observers=false;}},CLASS_NAME:"OpenLayers.Event"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","rightclick","dblrightclick","resize","focus","blur","touchstart","touchmove","touchend","keydown"],listeners:null,object:null,element:null,eventHandler:null,fallThrough:null,includeXY:false,extensions:null,extensionCount:null,clearMouseListener:null,initialize:function(object,element,eventTypes,fallThrough,options){OpenLayers.Util.extend(this,options);this.object=object;this.fallThrough=fallThrough;this.listeners={};this.extensions={};this.extensionCount={};this._msTouches=[];if(element!=null){this.attachToElement(element);}},destroy:function(){for(var e in this.extensions){if(typeof this.extensions[e]!=="boolean"){this.extensions[e].destroy();}}
-this.extensions=null;if(this.element){OpenLayers.Event.stopObservingElement(this.element);if(this.element.hasScrollEvent){OpenLayers.Event.stopObserving(window,"scroll",this.clearMouseListener);}}
-this.element=null;this.listeners=null;this.object=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){},attachToElement:function(element){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}else{this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);this.clearMouseListener=OpenLayers.Function.bind(this.clearMouseCache,this);}
-this.element=element;var msTouch=!!window.navigator.msMaxTouchPoints;var type;for(var i=0,len=this.BROWSER_EVENTS.length;i<len;i++){type=this.BROWSER_EVENTS[i];OpenLayers.Event.observe(element,type,this.eventHandler);if(msTouch&&type.indexOf('touch')===0){this.addMsTouchListener(element,type,this.eventHandler);}}
-OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},on:function(object){for(var type in object){if(type!="scope"&&object.hasOwnProperty(type)){this.register(type,object.scope,object[type]);}}},register:function(type,obj,func,priority){if(type in OpenLayers.Events&&!this.extensions[type]){this.extensions[type]=new OpenLayers.Events[type](this);}
-if(func!=null){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(!listeners){listeners=[];this.listeners[type]=listeners;this.extensionCount[type]=0;}
-var listener={obj:obj,func:func};if(priority){listeners.splice(this.extensionCount[type],0,listener);if(typeof priority==="object"&&priority.extension){this.extensionCount[type]++;}}else{listeners.push(listener);}}},registerPriority:function(type,obj,func){this.register(type,obj,func,true);},un:function(object){for(var type in object){if(type!="scope"&&object.hasOwnProperty(type)){this.unregister(type,object.scope,object[type]);}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
-var listeners=this.listeners[type];if(listeners!=null){for(var i=0,len=listeners.length;i<len;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){var listeners=this.listeners[type];if(!listeners||listeners.length==0){return undefined;}
-if(evt==null){evt={};}
-evt.object=this.object;evt.element=this.element;if(!evt.type){evt.type=type;}
-listeners=listeners.slice();var continueChain;for(var i=0,len=listeners.length;i<len;i++){var callback=listeners[i];continueChain=callback.func.apply(callback.obj,[evt]);if((continueChain!=undefined)&&(continueChain==false)){break;}}
-if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}
-return continueChain;},handleBrowserEvent:function(evt){var type=evt.type,listeners=this.listeners[type];if(!listeners||listeners.length==0){return;}
-var touches=evt.touches;if(touches&&touches[0]){var x=0;var y=0;var num=touches.length;var touch;for(var i=0;i<num;++i){touch=this.getTouchClientXY(touches[i]);x+=touch.clientX;y+=touch.clientY;}
-evt.clientX=x/num;evt.clientY=y/num;}
-if(this.includeXY){evt.xy=this.getMousePosition(evt);}
-this.triggerEvent(type,evt);},getTouchClientXY:function(evt){var win=window.olMockWin||window,winPageX=win.pageXOffset,winPageY=win.pageYOffset,x=evt.clientX,y=evt.clientY;if(evt.pageY===0&&Math.floor(y)>Math.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<ii;++i){if(touches[i].pointerId==e.pointerId){alreadyInArray=true;break;}}
-if(!alreadyInArray){touches.push(e);}
-e.touches=touches.slice();handler(e);};OpenLayers.Event.observe(element,'MSPointerDown',cb);var internalCb=function(e){for(var i=0,ii=touches.length;i<ii;++i){if(touches[i].pointerId==e.pointerId){touches.splice(i,1);break;}}};OpenLayers.Event.observe(element,'MSPointerUp',internalCb);},addMsTouchListenerMove:function(element,type,handler){var touches=this._msTouches;var cb=function(e){if(e.pointerType==e.MSPOINTER_TYPE_MOUSE&&e.buttons==0){return;}
-if(touches.length==1&&touches[0].pageX==e.pageX&&touches[0].pageY==e.pageY){return;}
-for(var i=0,ii=touches.length;i<ii;++i){if(touches[i].pointerId==e.pointerId){touches[i]=e;break;}}
-e.touches=touches.slice();handler(e);};OpenLayers.Event.observe(element,'MSPointerMove',cb);},addMsTouchListenerEnd:function(element,type,handler){var touches=this._msTouches;var cb=function(e){for(var i=0,ii=touches.length;i<ii;++i){if(touches[i].pointerId==e.pointerId){touches.splice(i,1);break;}}
-e.touches=touches.slice();handler(e);};OpenLayers.Event.observe(element,'MSPointerUp',cb);},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:['mousedown','mouseup','click','dblclick','touchstart','touchmove','touchend','keydown'],startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(target){this.target=target;for(var i=this.events.length-1;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.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){this.id=null;this.bounds=null;},clone:function(){return new OpenLayers.Geometry();},setBounds:function(bounds){if(bounds){this.bounds=bounds.clone();}},clearBounds:function(){this.bounds=null;if(this.parent){this.parent.clearBounds();}},extendBounds:function(newBounds){var bounds=this.getBounds();if(!bounds){this.setBounds(newBounds);}else{this.bounds.extend(newBounds);}},getBounds:function(){if(this.bounds==null){this.calculateBounds();}
-return this.bounds;},calculateBounds:function(){},distanceTo:function(geometry,options){},getVertices:function(nodes){},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;var bounds=this.getBounds();if((bounds!=null)&&(lonlat!=null)){var dX=(toleranceLon!=null)?toleranceLon:0;var dY=(toleranceLat!=null)?toleranceLat:0;var toleranceBounds=new OpenLayers.Bounds(this.bounds.left-dX,this.bounds.bottom-dY,this.bounds.right+dX,this.bounds.top+dY);atPoint=toleranceBounds.containsLonLat(lonlat);}
-return atPoint;},getLength:function(){return 0.0;},getArea:function(){return 0.0;},getCentroid:function(){return null;},toString:function(){var string;if(OpenLayers.Format&&OpenLayers.Format.WKT){string=OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this));}else{string=Object.prototype.toString.call(this);}
-return string;},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(wkt){var geom;if(OpenLayers.Format&&OpenLayers.Format.WKT){var format=OpenLayers.Geometry.fromWKT.format;if(!format){format=new OpenLayers.Format.WKT();OpenLayers.Geometry.fromWKT.format=format;}
-var result=format.read(wkt);if(result instanceof OpenLayers.Feature.Vector){geom=result.geometry;}else if(OpenLayers.Util.isArray(result)){var len=result.length;var components=new Array(len);for(var i=0;i<len;++i){components[i]=result[i].geometry;}
-geom=new OpenLayers.Geometry.Collection(components);}}
-return geom;};OpenLayers.Geometry.segmentsIntersect=function(seg1,seg2,options){var point=options&&options.point;var tolerance=options&&options.tolerance;var intersection=false;var x11_21=seg1.x1-seg2.x1;var y11_21=seg1.y1-seg2.y1;var x12_11=seg1.x2-seg1.x1;var y12_11=seg1.y2-seg1.y1;var y22_21=seg2.y2-seg2.y1;var x22_21=seg2.x2-seg2.x1;var d=(y22_21*x12_11)-(x22_21*y12_11);var n1=(x22_21*y11_21)-(y22_21*x11_21);var n2=(x12_11*y11_21)-(y12_11*x11_21);if(d==0){if(n1==0&&n2==0){intersection=true;}}else{var along1=n1/d;var along2=n2/d;if(along1>=0&&along1<=1&&along2>=0&&along2<=1){if(!point){intersection=true;}else{var x=seg1.x1+(along1*x12_11);var y=seg1.y1+(along1*y12_11);intersection=new OpenLayers.Geometry.Point(x,y);}}}
-if(tolerance){var dist;if(intersection){if(point){var segs=[seg1,seg2];var seg,x,y;outer:for(var i=0;i<2;++i){seg=segs[i];for(var j=1;j<3;++j){x=seg["x"+j];y=seg["y"+j];dist=Math.sqrt(Math.pow(x-intersection.x,2)+
-Math.pow(y-intersection.y,2));if(dist<tolerance){intersection.x=x;intersection.y=y;break outer;}}}}}else{var segs=[seg1,seg2];var source,target,x,y,p,result;outer:for(var i=0;i<2;++i){source=segs[i];target=segs[(i+1)%2];for(var j=1;j<3;++j){p={x:source["x"+j],y:source["y"+j]};result=OpenLayers.Geometry.distanceToSegment(p,target);if(result.distance<tolerance){if(point){intersection=new OpenLayers.Geometry.Point(p.x,p.y);}else{intersection=true;}
-break outer;}}}}}
-return intersection;};OpenLayers.Geometry.distanceToSegment=function(point,segment){var result=OpenLayers.Geometry.distanceSquaredToSegment(point,segment);result.distance=Math.sqrt(result.distance);return result;};OpenLayers.Geometry.distanceSquaredToSegment=function(point,segment){var x0=point.x;var y0=point.y;var x1=segment.x1;var y1=segment.y1;var x2=segment.x2;var y2=segment.y2;var dx=x2-x1;var dy=y2-y1;var along=((dx*(x0-x1))+(dy*(y0-y1)))/(Math.pow(dx,2)+Math.pow(dy,2));var x,y;if(along<=0.0){x=x1;y=y1;}else if(along>=1.0){x=x2;y=y2;}else{x=x1+along*dx;y=y1+along*dy;}
-return{distance:Math.pow(x-x0,2)+Math.pow(y-y0,2),x:x,y:y,along:along};};OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(components){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];if(components!=null){this.addComponents(components);}},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments);},clone:function(){var geometry=eval("new "+this.CLASS_NAME+"()");for(var i=0,len=this.components.length;i<len;i++){geometry.addComponent(this.components[i].clone());}
-OpenLayers.Util.applyDefaults(geometry,this);return geometry;},getComponentsString:function(){var strings=[];for(var i=0,len=this.components.length;i<len;i++){strings.push(this.components[i].toShortString());}
-return strings.join(",");},calculateBounds:function(){this.bounds=null;var bounds=new OpenLayers.Bounds();var components=this.components;if(components){for(var i=0,len=components.length;i<len;i++){bounds.extend(components[i].getBounds());}}
-if(bounds.left!=null&&bounds.bottom!=null&&bounds.right!=null&&bounds.top!=null){this.setBounds(bounds);}},addComponents:function(components){if(!(OpenLayers.Util.isArray(components))){components=[components];}
-for(var i=0,len=components.length;i<len;i++){this.addComponent(components[i]);}},addComponent:function(component,index){var added=false;if(component){if(this.componentTypes==null||(OpenLayers.Util.indexOf(this.componentTypes,component.CLASS_NAME)>-1)){if(index!=null&&(index<this.components.length)){var components1=this.components.slice(0,index);var components2=this.components.slice(index,this.components.length);components1.push(component);this.components=components1.concat(components2);}else{this.components.push(component);}
-component.parent=this;this.clearBounds();added=true;}}
-return added;},removeComponents:function(components){var removed=false;if(!(OpenLayers.Util.isArray(components))){components=[components];}
-for(var i=components.length-1;i>=0;--i){removed=this.removeComponent(components[i])||removed;}
-return removed;},removeComponent:function(component){OpenLayers.Util.removeItem(this.components,component);this.clearBounds();return true;},getLength:function(){var length=0.0;for(var i=0,len=this.components.length;i<len;i++){length+=this.components[i].getLength();}
-return length;},getArea:function(){var area=0.0;for(var i=0,len=this.components.length;i<len;i++){area+=this.components[i].getArea();}
-return area;},getGeodesicArea:function(projection){var area=0.0;for(var i=0,len=this.components.length;i<len;i++){area+=this.components[i].getGeodesicArea(projection);}
-return area;},getCentroid:function(weighted){if(!weighted){return this.components.length&&this.components[0].getCentroid();}
-var len=this.components.length;if(!len){return false;}
-var areas=[];var centroids=[];var areaSum=0;var minArea=Number.MAX_VALUE;var component;for(var i=0;i<len;++i){component=this.components[i];var area=component.getArea();var centroid=component.getCentroid(true);if(isNaN(area)||isNaN(centroid.x)||isNaN(centroid.y)){continue;}
-areas.push(area);areaSum+=area;minArea=(area<minArea&&area>0)?area:minArea;centroids.push(centroid);}
-len=areas.length;if(areaSum===0){for(var i=0;i<len;++i){areas[i]=1;}
-areaSum=areas.length;}else{for(var i=0;i<len;++i){areas[i]/=minArea;}
-areaSum/=minArea;}
-var xSum=0,ySum=0,centroid,area;for(var i=0;i<len;++i){centroid=centroids[i];area=areas[i];xSum+=centroid.x*area;ySum+=centroid.y*area;}
-return new OpenLayers.Geometry.Point(xSum/areaSum,ySum/areaSum);},getGeodesicLength:function(projection){var length=0.0;for(var i=0,len=this.components.length;i<len;i++){length+=this.components[i].getGeodesicLength(projection);}
-return length;},move:function(x,y){for(var i=0,len=this.components.length;i<len;i++){this.components[i].move(x,y);}},rotate:function(angle,origin){for(var i=0,len=this.components.length;i<len;++i){this.components[i].rotate(angle,origin);}},resize:function(scale,origin,ratio){for(var i=0;i<this.components.length;++i){this.components[i].resize(scale,origin,ratio);}
-return this;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best,distance;var min=Number.POSITIVE_INFINITY;for(var i=0,len=this.components.length;i<len;++i){result=this.components[i].distanceTo(geometry,options);distance=details?result.distance:result;if(distance<min){min=distance;best=result;if(min==0){break;}}}
-return best;},equals:function(geometry){var equivalent=true;if(!geometry||!geometry.CLASS_NAME||(this.CLASS_NAME!=geometry.CLASS_NAME)){equivalent=false;}else if(!(OpenLayers.Util.isArray(geometry.components))||(geometry.components.length!=this.components.length)){equivalent=false;}else{for(var i=0,len=this.components.length;i<len;++i){if(!this.components[i].equals(geometry.components[i])){equivalent=false;break;}}}
-return equivalent;},transform:function(source,dest){if(source&&dest){for(var i=0,len=this.components.length;i<len;i++){var component=this.components[i];component.transform(source,dest);}
-this.bounds=null;}
-return this;},intersects:function(geometry){var intersect=false;for(var i=0,len=this.components.length;i<len;++i){intersect=geometry.intersects(this.components[i]);if(intersect){break;}}
-return intersect;},getVertices:function(nodes){var vertices=[];for(var i=0,len=this.components.length;i<len;++i){Array.prototype.push.apply(vertices,this.components[i].getVertices(nodes));}
-return vertices;},CLASS_NAME:"OpenLayers.Geometry.Collection"});OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(x,y){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(x);this.y=parseFloat(y);},clone:function(obj){if(obj==null){obj=new OpenLayers.Geometry.Point(this.x,this.y);}
-OpenLayers.Util.applyDefaults(obj,this);return obj;},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y);},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var distance,x0,y0,x1,y1,result;if(geometry instanceof OpenLayers.Geometry.Point){x0=this.x;y0=this.y;x1=geometry.x;y1=geometry.y;distance=Math.sqrt(Math.pow(x0-x1,2)+Math.pow(y0-y1,2));result=!details?distance:{x0:x0,y0:y0,x1:x1,y1:y1,distance:distance};}else{result=geometry.distanceTo(this,options);if(details){result={x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0,distance:result.distance};}}
-return result;},equals:function(geom){var equals=false;if(geom!=null){equals=((this.x==geom.x&&this.y==geom.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(geom.x)&&isNaN(geom.y)));}
-return equals;},toShortString:function(){return(this.x+", "+this.y);},move:function(x,y){this.x=this.x+x;this.y=this.y+y;this.clearBounds();},rotate:function(angle,origin){angle*=Math.PI/180;var radius=this.distanceTo(origin);var theta=angle+Math.atan2(this.y-origin.y,this.x-origin.x);this.x=origin.x+(radius*Math.cos(theta));this.y=origin.y+(radius*Math.sin(theta));this.clearBounds();},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y);},resize:function(scale,origin,ratio){ratio=(ratio==undefined)?1:ratio;this.x=origin.x+(scale*ratio*(this.x-origin.x));this.y=origin.y+(scale*(this.y-origin.y));this.clearBounds();return this;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.equals(geometry);}else{intersect=geometry.intersects(this);}
-return intersect;},transform:function(source,dest){if((source&&dest)){OpenLayers.Projection.transform(this,source,dest);this.bounds=null;}
-return this;},getVertices:function(nodes){return[this];},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.MultiPoint=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Point"],addPoint:function(point,index){this.addComponent(point,index);},removePoint:function(point){this.removeComponent(point);},CLASS_NAME:"OpenLayers.Geometry.MultiPoint"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],getLength:function(){var length=0.0;if(this.components&&(this.components.length>1)){for(var i=1,len=this.components.length;i<len;i++){length+=this.components[i-1].distanceTo(this.components[i]);}}
-return length;},getGeodesicLength:function(projection){var geom=this;if(projection){var gg=new OpenLayers.Projection("EPSG:4326");if(!gg.equals(projection)){geom=this.clone().transform(projection,gg);}}
-var length=0.0;if(geom.components&&(geom.components.length>1)){var p1,p2;for(var i=1,len=geom.components.length;i<len;i++){p1=geom.components[i-1];p2=geom.components[i];length+=OpenLayers.Util.distVincenty({lon:p1.x,lat:p1.y},{lon:p2.x,lat:p2.y});}}
-return length*1000;},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(point){var removed=this.components&&(this.components.length>2);if(removed){OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);}
-return removed;},intersects:function(geometry){var intersect=false;var type=geometry.CLASS_NAME;if(type=="OpenLayers.Geometry.LineString"||type=="OpenLayers.Geometry.LinearRing"||type=="OpenLayers.Geometry.Point"){var segs1=this.getSortedSegments();var segs2;if(type=="OpenLayers.Geometry.Point"){segs2=[{x1:geometry.x,y1:geometry.y,x2:geometry.x,y2:geometry.y}];}else{segs2=geometry.getSortedSegments();}
-var seg1,seg1x1,seg1x2,seg1y1,seg1y2,seg2,seg2y1,seg2y2;outer:for(var i=0,len=segs1.length;i<len;++i){seg1=segs1[i];seg1x1=seg1.x1;seg1x2=seg1.x2;seg1y1=seg1.y1;seg1y2=seg1.y2;inner:for(var j=0,jlen=segs2.length;j<jlen;++j){seg2=segs2[j];if(seg2.x1>seg1x2){break;}
-if(seg2.x2<seg1x1){continue;}
-seg2y1=seg2.y1;seg2y2=seg2.y2;if(Math.min(seg2y1,seg2y2)>Math.max(seg1y1,seg1y2)){continue;}
-if(Math.max(seg2y1,seg2y2)<Math.min(seg1y1,seg1y2)){continue;}
-if(OpenLayers.Geometry.segmentsIntersect(seg1,seg2)){intersect=true;break outer;}}}}else{intersect=geometry.intersects(this);}
-return intersect;},getSortedSegments:function(){var numSeg=this.components.length-1;var segments=new Array(numSeg),point1,point2;for(var i=0;i<numSeg;++i){point1=this.components[i];point2=this.components[i+1];if(point1.x<point2.x){segments[i]={x1:point1.x,y1:point1.y,x2:point2.x,y2:point2.y};}else{segments[i]={x1:point2.x,y1:point2.y,x2:point1.x,y2:point1.y};}}
-function byX1(seg1,seg2){return seg1.x1-seg2.x1;}
-return segments.sort(byX1);},splitWithSegment:function(seg,options){var edge=!(options&&options.edge===false);var tolerance=options&&options.tolerance;var lines=[];var verts=this.getVertices();var points=[];var intersections=[];var split=false;var vert1,vert2,point;var node,vertex,target;var interOptions={point:true,tolerance:tolerance};var result=null;for(var i=0,stop=verts.length-2;i<=stop;++i){vert1=verts[i];points.push(vert1.clone());vert2=verts[i+1];target={x1:vert1.x,y1:vert1.y,x2:vert2.x,y2:vert2.y};point=OpenLayers.Geometry.segmentsIntersect(seg,target,interOptions);if(point instanceof OpenLayers.Geometry.Point){if((point.x===seg.x1&&point.y===seg.y1)||(point.x===seg.x2&&point.y===seg.y2)||point.equals(vert1)||point.equals(vert2)){vertex=true;}else{vertex=false;}
-if(vertex||edge){if(!point.equals(intersections[intersections.length-1])){intersections.push(point.clone());}
-if(i===0){if(point.equals(vert1)){continue;}}
-if(point.equals(vert2)){continue;}
-split=true;if(!point.equals(vert1)){points.push(point);}
-lines.push(new OpenLayers.Geometry.LineString(points));points=[point.clone()];}}}
-if(split){points.push(vert2.clone());lines.push(new OpenLayers.Geometry.LineString(points));}
-if(intersections.length>0){var xDir=seg.x1<seg.x2?1:-1;var yDir=seg.y1<seg.y2?1:-1;result={lines:lines,points:intersections.sort(function(p1,p2){return(xDir*p1.x-xDir*p2.x)||(yDir*p1.y-yDir*p2.y);})};}
-return result;},split:function(target,options){var results=null;var mutual=options&&options.mutual;var sourceSplit,targetSplit,sourceParts,targetParts;if(target instanceof OpenLayers.Geometry.LineString){var verts=this.getVertices();var vert1,vert2,seg,splits,lines,point;var points=[];sourceParts=[];for(var i=0,stop=verts.length-2;i<=stop;++i){vert1=verts[i];vert2=verts[i+1];seg={x1:vert1.x,y1:vert1.y,x2:vert2.x,y2:vert2.y};targetParts=targetParts||[target];if(mutual){points.push(vert1.clone());}
-for(var j=0;j<targetParts.length;++j){splits=targetParts[j].splitWithSegment(seg,options);if(splits){lines=splits.lines;if(lines.length>0){lines.unshift(j,1);Array.prototype.splice.apply(targetParts,lines);j+=lines.length-2;}
-if(mutual){for(var k=0,len=splits.points.length;k<len;++k){point=splits.points[k];if(!point.equals(vert1)){points.push(point);sourceParts.push(new OpenLayers.Geometry.LineString(points));if(point.equals(vert2)){points=[];}else{points=[point.clone()];}}}}}}}
-if(mutual&&sourceParts.length>0&&points.length>0){points.push(vert2.clone());sourceParts.push(new OpenLayers.Geometry.LineString(points));}}else{results=target.splitWith(this,options);}
-if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
-if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
-if(targetSplit||sourceSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
-return results;},splitWith:function(geometry,options){return geometry.split(this,options);},getVertices:function(nodes){var vertices;if(nodes===true){vertices=[this.components[0],this.components[this.components.length-1]];}else if(nodes===false){vertices=this.components.slice(1,this.components.length-1);}else{vertices=this.components.slice();}
-return vertices;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best={};var min=Number.POSITIVE_INFINITY;if(geometry instanceof OpenLayers.Geometry.Point){var segs=this.getSortedSegments();var x=geometry.x;var y=geometry.y;var seg;for(var i=0,len=segs.length;i<len;++i){seg=segs[i];result=OpenLayers.Geometry.distanceToSegment(geometry,seg);if(result.distance<min){min=result.distance;best=result;if(min===0){break;}}else{if(seg.x2>x&&((y>seg.y1&&y<seg.y2)||(y<seg.y1&&y>seg.y2))){break;}}}
-if(details){best={distance:best.distance,x0:best.x,y0:best.y,x1:x,y1:y};}else{best=best.distance;}}else if(geometry instanceof OpenLayers.Geometry.LineString){var segs0=this.getSortedSegments();var segs1=geometry.getSortedSegments();var seg0,seg1,intersection,x0,y0;var len1=segs1.length;var interOptions={point:true};outer:for(var i=0,len=segs0.length;i<len;++i){seg0=segs0[i];x0=seg0.x1;y0=seg0.y1;for(var j=0;j<len1;++j){seg1=segs1[j];intersection=OpenLayers.Geometry.segmentsIntersect(seg0,seg1,interOptions);if(intersection){min=0;best={distance:0,x0:intersection.x,y0:intersection.y,x1:intersection.x,y1:intersection.y};break outer;}else{result=OpenLayers.Geometry.distanceToSegment({x:x0,y:y0},seg1);if(result.distance<min){min=result.distance;best={distance:min,x0:x0,y0:y0,x1:result.x,y1:result.y};}}}}
-if(!details){best=best.distance;}
-if(min!==0){if(seg0){result=geometry.distanceTo(new OpenLayers.Geometry.Point(seg0.x2,seg0.y2),options);var dist=details?result.distance:result;if(dist<min){if(details){best={distance:min,x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0};}else{best=dist;}}}}}else{best=geometry.distanceTo(this,options);if(details){best={distance:best.distance,x0:best.x1,y0:best.y1,x1:best.x0,y1:best.y0};}}
-return best;},simplify:function(tolerance){if(this&&this!==null){var points=this.getVertices();if(points.length<3){return this;}
-var compareNumbers=function(a,b){return(a-b);};var douglasPeuckerReduction=function(points,firstPoint,lastPoint,tolerance){var maxDistance=0;var indexFarthest=0;for(var index=firstPoint,distance;index<lastPoint;index++){distance=perpendicularDistance(points[firstPoint],points[lastPoint],points[index]);if(distance>maxDistance){maxDistance=distance;indexFarthest=index;}}
-if(maxDistance>tolerance&&indexFarthest!=firstPoint){pointIndexsToKeep.push(indexFarthest);douglasPeuckerReduction(points,firstPoint,indexFarthest,tolerance);douglasPeuckerReduction(points,indexFarthest,lastPoint,tolerance);}};var perpendicularDistance=function(point1,point2,point){var area=Math.abs(0.5*(point1.x*point2.y+point2.x*point.y+point.x*point1.y-point2.x*point1.y-point.x*point2.y-point1.x*point.y));var bottom=Math.sqrt(Math.pow(point1.x-point2.x,2)+Math.pow(point1.y-point2.y,2));var height=area/bottom*2;return height;};var firstPoint=0;var lastPoint=points.length-1;var pointIndexsToKeep=[];pointIndexsToKeep.push(firstPoint);pointIndexsToKeep.push(lastPoint);while(points[firstPoint].equals(points[lastPoint])){lastPoint--;pointIndexsToKeep.push(lastPoint);}
-douglasPeuckerReduction(points,firstPoint,lastPoint,tolerance);var returnPoints=[];pointIndexsToKeep.sort(compareNumbers);for(var index=0;index<pointIndexsToKeep.length;index++){returnPoints.push(points[pointIndexsToKeep[index]]);}
-return new OpenLayers.Geometry.LineString(returnPoints);}
-else{return this;}},CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(point,index){var added=false;var lastPoint=this.components.pop();if(index!=null||!point.equals(lastPoint)){added=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);}
-var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);return added;},removeComponent:function(point){var removed=this.components&&(this.components.length>3);if(removed){this.components.pop();OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);}
-return removed;},move:function(x,y){for(var i=0,len=this.components.length;i<len-1;i++){this.components[i].move(x,y);}},rotate:function(angle,origin){for(var i=0,len=this.components.length;i<len-1;++i){this.components[i].rotate(angle,origin);}},resize:function(scale,origin,ratio){for(var i=0,len=this.components.length;i<len-1;++i){this.components[i].resize(scale,origin,ratio);}
-return this;},transform:function(source,dest){if(source&&dest){for(var i=0,len=this.components.length;i<len-1;i++){var component=this.components[i];component.transform(source,dest);}
-this.bounds=null;}
-return this;},getCentroid:function(){if(this.components){var len=this.components.length;if(len>0&&len<=2){return this.components[0].clone();}else if(len>2){var sumX=0.0;var sumY=0.0;var x0=this.components[0].x;var y0=this.components[0].y;var area=-1*this.getArea();if(area!=0){for(var i=0;i<len-1;i++){var b=this.components[i];var c=this.components[i+1];sumX+=(b.x+c.x-2*x0)*((b.x-x0)*(c.y-y0)-(c.x-x0)*(b.y-y0));sumY+=(b.y+c.y-2*y0)*((b.x-x0)*(c.y-y0)-(c.x-x0)*(b.y-y0));}
-var x=x0+sumX/(6*area);var y=y0+sumY/(6*area);}else{for(var i=0;i<len-1;i++){sumX+=this.components[i].x;sumY+=this.components[i].y;}
-var x=sumX/(len-1);var y=sumY/(len-1);}
-return new OpenLayers.Geometry.Point(x,y);}else{return null;}}},getArea:function(){var area=0.0;if(this.components&&(this.components.length>2)){var sum=0.0;for(var i=0,len=this.components.length;i<len-1;i++){var b=this.components[i];var c=this.components[i+1];sum+=(b.x+c.x)*(c.y-b.y);}
-area=-sum/2.0;}
-return area;},getGeodesicArea:function(projection){var ring=this;if(projection){var gg=new OpenLayers.Projection("EPSG:4326");if(!gg.equals(projection)){ring=this.clone().transform(projection,gg);}}
-var area=0.0;var len=ring.components&&ring.components.length;if(len>2){var p1,p2;for(var i=0;i<len-1;i++){p1=ring.components[i];p2=ring.components[i+1];area+=OpenLayers.Util.rad(p2.x-p1.x)*(2+Math.sin(OpenLayers.Util.rad(p1.y))+
-Math.sin(OpenLayers.Util.rad(p2.y)));}
-area=area*6378137.0*6378137.0/2.0;}
-return area;},containsPoint:function(point){var approx=OpenLayers.Number.limitSigDigs;var digs=14;var px=approx(point.x,digs);var py=approx(point.y,digs);function getX(y,x1,y1,x2,y2){return(y-y2)*((x2-x1)/(y2-y1))+x2;}
-var numSeg=this.components.length-1;var start,end,x1,y1,x2,y2,cx,cy;var crosses=0;for(var i=0;i<numSeg;++i){start=this.components[i];x1=approx(start.x,digs);y1=approx(start.y,digs);end=this.components[i+1];x2=approx(end.x,digs);y2=approx(end.y,digs);if(y1==y2){if(py==y1){if(x1<=x2&&(px>=x1&&px<=x2)||x1>=x2&&(px<=x1&&px>=x2)){crosses=-1;break;}}
-continue;}
-cx=approx(getX(py,x1,y1,x2,y2),digs);if(cx==px){if(y1<y2&&(py>=y1&&py<=y2)||y1>y2&&(py<=y1&&py>=y2)){crosses=-1;break;}}
-if(cx<=px){continue;}
-if(x1!=x2&&(cx<Math.min(x1,x2)||cx>Math.max(x1,x2))){continue;}
-if(y1<y2&&(py>=y1&&py<y2)||y1>y2&&(py<y1&&py>=y2)){++crosses;}}
-var contained=(crosses==-1)?1:!!(crosses&1);return contained;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"){intersect=geometry.intersects(this);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){intersect=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[geometry]);}else{for(var i=0,len=geometry.components.length;i<len;++i){intersect=geometry.components[i].intersects(this);if(intersect){break;}}}
-return intersect;},getVertices:function(nodes){return(nodes===true)?[]:this.components.slice(0,this.components.length-1);},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,touch:false,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;var map=this.map||control.map;if(map){this.setMap(map);}
-this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
-var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0)|(evt.metaKey?OpenLayers.Handler.MOD_META:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
-var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
-this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
-var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
-this.touch=false;this.active=false;return true;},startTouch:function(){if(!this.touch){this.touch=true;var events=["mousedown","mouseup","mousemove","click","dblclick","mouseout"];for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}}},callback:function(name,args){if(name&&this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Handler.MOD_META=8;OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:false,citeCompliant:false,mouseDown:false,stoppedDown:null,lastDown:null,lastUp:null,persist:false,stopDown:false,stopUp:false,layerOptions:null,pixelTolerance:5,lastTouchPx:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
-OpenLayers.Handler.prototype.initialize.apply(this,arguments);},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,arguments)){return false;}
-var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);return true;},createFeature:function(pixel){var lonlat=this.layer.getLonLatFromViewPortPx(pixel);var geometry=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);this.point=new OpenLayers.Feature.Vector(geometry);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.layer.addFeatures([this.point],{silent:true});},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){return false;}
-this.cancel();if(this.layer.map!=null){this.destroyFeature(true);this.layer.destroy(false);}
-this.layer=null;return true;},destroyFeature:function(force){if(this.layer&&(force||!this.persist)){this.layer.destroyFeatures();}
-this.point=null;},destroyPersistedFeature:function(){var layer=this.layer;if(layer&&layer.features.length>1){this.layer.features[0].destroy();}},finalize:function(cancel){var key=cancel?"cancel":"done";this.mouseDown=false;this.lastDown=null;this.lastUp=null;this.lastTouchPx=null;this.callback(key,[this.geometryClone()]);this.destroyFeature(cancel);},cancel:function(){this.finalize(true);},click:function(evt){OpenLayers.Event.stop(evt);return false;},dblclick:function(evt){OpenLayers.Event.stop(evt);return false;},modifyFeature:function(pixel){if(!this.point){this.createFeature(pixel);}
-var lonlat=this.layer.getLonLatFromViewPortPx(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.point,false]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.point,this.style);},getGeometry:function(){var geometry=this.point&&this.point.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiPoint([geometry]);}
-return geometry;},geometryClone:function(){var geom=this.getGeometry();return geom&&geom.clone();},mousedown:function(evt){return this.down(evt);},touchstart:function(evt){this.startTouch();this.lastTouchPx=evt.xy;return this.down(evt);},mousemove:function(evt){return this.move(evt);},touchmove:function(evt){this.lastTouchPx=evt.xy;return this.move(evt);},mouseup:function(evt){return this.up(evt);},touchend:function(evt){evt.xy=this.lastTouchPx;return this.up(evt);},down:function(evt){this.mouseDown=true;this.lastDown=evt.xy;if(!this.touch){this.modifyFeature(evt.xy);}
-this.stoppedDown=this.stopDown;return!this.stopDown;},move:function(evt){if(!this.touch&&(!this.mouseDown||this.stoppedDown)){this.modifyFeature(evt.xy);}
-return true;},up:function(evt){this.mouseDown=false;this.stoppedDown=this.stopDown;if(!this.checkModifiers(evt)){return true;}
-if(this.lastUp&&this.lastUp.equals(evt.xy)){return true;}
-if(this.lastDown&&this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance)){if(this.touch){this.modifyFeature(evt.xy);}
-if(this.persist){this.destroyPersistedFeature();}
-this.lastUp=evt.xy;this.finalize();return!this.stopUp;}else{return true;}},mouseout:function(evt){if(OpenLayers.Util.mouseLeft(evt,this.map.viewPortDiv)){this.stoppedDown=this.stopDown;this.mouseDown=false;}},passesTolerance:function(pixel1,pixel2,tolerance){var passes=true;if(tolerance!=null&&pixel1&&pixel2){var dist=pixel1.distanceTo(pixel2);if(dist>tolerance){passes=false;}}
-return passes;},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:false,freehandToggle:'shiftKey',timerId:null,redoStack:null,createFeature:function(pixel){var lonlat=this.layer.getLonLatFromViewPortPx(pixel);var geometry=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);this.point=new OpenLayers.Feature.Vector(geometry);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([this.point.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.line,this.point],{silent:true});},destroyFeature:function(force){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,force);this.line=null;},destroyPersistedFeature:function(){var layer=this.layer;if(layer&&layer.features.length>2){this.layer.features[0].destroy();}},removePoint:function(){if(this.point){this.layer.removeFeatures([this.point]);}},addPoint:function(pixel){this.layer.removeFeatures([this.point]);var lonlat=this.layer.getLonLatFromViewPortPx(pixel);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack;},insertXY:function(x,y){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(x,y),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack;},insertDeltaXY:function(dx,dy){var previousIndex=this.getCurrentPointIndex()-1;var p0=this.line.geometry.components[previousIndex];if(p0&&!isNaN(p0.x)&&!isNaN(p0.y)){this.insertXY(p0.x+dx,p0.y+dy);}},insertDirectionLength:function(direction,length){direction*=Math.PI/180;var dx=length*Math.cos(direction);var dy=length*Math.sin(direction);this.insertDeltaXY(dx,dy);},insertDeflectionLength:function(deflection,length){var previousIndex=this.getCurrentPointIndex()-1;if(previousIndex>0){var p1=this.line.geometry.components[previousIndex];var p0=this.line.geometry.components[previousIndex-1];var theta=Math.atan2(p1.y-p0.y,p1.x-p0.x);this.insertDirectionLength((theta*180/Math.PI)+deflection,length);}},getCurrentPointIndex:function(){return this.line.geometry.components.length-1;},undo:function(){var geometry=this.line.geometry;var components=geometry.components;var index=this.getCurrentPointIndex()-1;var target=components[index];var undone=geometry.removeComponent(target);if(undone){if(this.touch&&index>0){components=geometry.components;var lastpt=components[index-1];var curptidx=this.getCurrentPointIndex();var curpt=components[curptidx];curpt.x=lastpt.x;curpt.y=lastpt.y;}
-if(!this.redoStack){this.redoStack=[];}
-this.redoStack.push(target);this.drawFeature();}
-return undone;},redo:function(){var target=this.redoStack&&this.redoStack.pop();if(target){this.line.geometry.addComponent(target,this.getCurrentPointIndex());this.drawFeature();}
-return!!target;},freehandMode:function(evt){return(this.freehandToggle&&evt[this.freehandToggle])?!this.freehand:this.freehand;},modifyFeature:function(pixel,drawing){if(!this.line){this.createFeature(pixel);}
-var lonlat=this.layer.getLonLatFromViewPortPx(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.getSketch(),drawing]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style);},getSketch:function(){return this.line;},getGeometry:function(){var geometry=this.line&&this.line.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiLineString([geometry]);}
-return geometry;},touchstart:function(evt){if(this.timerId&&this.passesTolerance(this.lastTouchPx,evt.xy,this.doubleTouchTolerance)){this.finishGeometry();window.clearTimeout(this.timerId);this.timerId=null;return false;}else{if(this.timerId){window.clearTimeout(this.timerId);this.timerId=null;}
-this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null;},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,evt);}},down:function(evt){var stopDown=this.stopDown;if(this.freehandMode(evt)){stopDown=true;if(this.touch){this.modifyFeature(evt.xy,!!this.lastUp);OpenLayers.Event.stop(evt);}}
-if(!this.touch&&(!this.lastDown||!this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance))){this.modifyFeature(evt.xy,!!this.lastUp);}
-this.mouseDown=true;this.lastDown=evt.xy;this.stoppedDown=stopDown;return!stopDown;},move:function(evt){if(this.stoppedDown&&this.freehandMode(evt)){if(this.persist){this.destroyPersistedFeature();}
-if(this.maxVertices&&this.line&&this.line.geometry.components.length===this.maxVertices){this.removePoint();this.finalize();}else{this.addPoint(evt.xy);}
-return false;}
-if(!this.touch&&(!this.mouseDown||this.stoppedDown)){this.modifyFeature(evt.xy,!!this.lastUp);}
-return true;},up:function(evt){if(this.mouseDown&&(!this.lastUp||!this.lastUp.equals(evt.xy))){if(this.stoppedDown&&this.freehandMode(evt)){if(this.persist){this.destroyPersistedFeature();}
-this.removePoint();this.finalize();}else{if(this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance)){if(this.touch){this.modifyFeature(evt.xy);}
-if(this.lastUp==null&&this.persist){this.destroyPersistedFeature();}
-this.addPoint(evt.xy);this.lastUp=evt.xy;if(this.line.geometry.components.length===this.maxVertices+1){this.finishGeometry();}}}}
-this.stoppedDown=this.stopDown;this.mouseDown=false;return!this.stopUp;},finishGeometry:function(){var index=this.line.geometry.components.length-1;this.line.geometry.removeComponent(this.line.geometry.components[index]);this.removePoint();this.finalize();},dblclick:function(evt){if(!this.freehandMode(evt)){this.finishGeometry();}
-return false;},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],getArea:function(){var area=0.0;if(this.components&&(this.components.length>0)){area+=Math.abs(this.components[0].getArea());for(var i=1,len=this.components.length;i<len;i++){area-=Math.abs(this.components[i].getArea());}}
-return area;},getGeodesicArea:function(projection){var area=0.0;if(this.components&&(this.components.length>0)){area+=Math.abs(this.components[0].getGeodesicArea(projection));for(var i=1,len=this.components.length;i<len;i++){area-=Math.abs(this.components[i].getGeodesicArea(projection));}}
-return area;},containsPoint:function(point){var numRings=this.components.length;var contained=false;if(numRings>0){contained=this.components[0].containsPoint(point);if(contained!==1){if(contained&&numRings>1){var hole;for(var i=1;i<numRings;++i){hole=this.components[i].containsPoint(point);if(hole){if(hole===1){contained=1;}else{contained=false;}
-break;}}}}}
-return contained;},intersects:function(geometry){var intersect=false;var i,len;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"||geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){for(i=0,len=this.components.length;i<len;++i){intersect=geometry.intersects(this.components[i]);if(intersect){break;}}
-if(!intersect){for(i=0,len=geometry.components.length;i<len;++i){intersect=this.containsPoint(geometry.components[i]);if(intersect){break;}}}}else{for(i=0,len=geometry.components.length;i<len;++i){intersect=this.intersects(geometry.components[i]);if(intersect){break;}}}
-if(!intersect&&geometry.CLASS_NAME=="OpenLayers.Geometry.Polygon"){var ring=this.components[0];for(i=0,len=ring.components.length;i<len;++i){intersect=geometry.containsPoint(ring.components[i]);if(intersect){break;}}}
-return intersect;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var result;if(!edge&&this.intersects(geometry)){result=0;}else{result=OpenLayers.Geometry.Collection.prototype.distanceTo.apply(this,[geometry,options]);}
-return result;},CLASS_NAME:"OpenLayers.Geometry.Polygon"});OpenLayers.Geometry.Polygon.createRegularPolygon=function(origin,radius,sides,rotation){var angle=Math.PI*((1/sides)-(1/2));if(rotation){angle+=(rotation/180)*Math.PI;}
-var rotatedAngle,x,y;var points=[];for(var i=0;i<sides;++i){rotatedAngle=angle+(i*2*Math.PI/sides);x=origin.x+(radius*Math.cos(rotatedAngle));y=origin.y+(radius*Math.sin(rotatedAngle));points.push(new OpenLayers.Geometry.Point(x,y));}
-var ring=new OpenLayers.Geometry.LinearRing(points);return new OpenLayers.Geometry.Polygon([ring]);};OpenLayers.Handler.Polygon=OpenLayers.Class(OpenLayers.Handler.Path,{holeModifier:null,drawingHole:false,polygon:null,createFeature:function(pixel){var lonlat=this.layer.getLonLatFromViewPortPx(pixel);var geometry=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);this.point=new OpenLayers.Feature.Vector(geometry);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LinearRing([this.point.geometry]));this.polygon=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([this.line.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.polygon,this.point],{silent:true});},addPoint:function(pixel){if(!this.drawingHole&&this.holeModifier&&this.evt&&this.evt[this.holeModifier]){var geometry=this.point.geometry;var features=this.control.layer.features;var candidate,polygon;for(var i=features.length-1;i>=0;--i){candidate=features[i].geometry;if((candidate instanceof OpenLayers.Geometry.Polygon||candidate instanceof OpenLayers.Geometry.MultiPolygon)&&candidate.intersects(geometry)){polygon=features[i];this.control.layer.removeFeatures([polygon],{silent:true});this.control.layer.events.registerPriority("sketchcomplete",this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);polygon.geometry.addComponent(this.line.geometry);this.polygon=polygon;this.drawingHole=true;break;}}}
-OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments);},getCurrentPointIndex:function(){return this.line.geometry.components.length-2;},enforceTopology:function(event){var point=event.vertex;var components=this.line.geometry.components;if(!this.polygon.geometry.intersects(point)){var last=components[components.length-3];point.x=last.x;point.y=last.y;}},finishGeometry:function(){var index=this.line.geometry.components.length-2;this.line.geometry.removeComponent(this.line.geometry.components[index]);this.removePoint();this.finalize();},finalizeInteriorRing:function(){var ring=this.line.geometry;var modified=(ring.getArea()!==0);if(modified){var rings=this.polygon.geometry.components;for(var i=rings.length-2;i>=0;--i){if(ring.intersects(rings[i])){modified=false;break;}}
-if(modified){var target;outer:for(var i=rings.length-2;i>0;--i){var points=rings[i].components;for(var j=0,jj=points.length;j<jj;++j){if(ring.containsPoint(points[j])){modified=false;break outer;}}}}}
-if(modified){if(this.polygon.state!==OpenLayers.State.INSERT){this.polygon.state=OpenLayers.State.UPDATE;}}else{this.polygon.geometry.removeComponent(ring);}
-this.restoreFeature();return false;},cancel:function(){if(this.drawingHole){this.polygon.geometry.removeComponent(this.line.geometry);this.restoreFeature(true);}
-return OpenLayers.Handler.Path.prototype.cancel.apply(this,arguments);},restoreFeature:function(cancel){this.control.layer.events.unregister("sketchcomplete",this,this.finalizeInteriorRing);this.control.layer.events.unregister("sketchmodified",this,this.enforceTopology);this.layer.removeFeatures([this.polygon],{silent:true});this.control.layer.addFeatures([this.polygon],{silent:true});this.drawingHole=false;if(!cancel){this.control.layer.events.triggerEvent("sketchcomplete",{feature:this.polygon});}},destroyFeature:function(force){OpenLayers.Handler.Path.prototype.destroyFeature.call(this,force);this.polygon=null;},drawFeature:function(){this.layer.drawFeature(this.polygon,this.style);this.layer.drawFeature(this.point,this.style);},getSketch:function(){return this.polygon;},getGeometry:function(){var geometry=this.polygon&&this.polygon.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiPolygon([geometry]);}
-return geometry;},CLASS_NAME:"OpenLayers.Handler.Polygon"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:false,size:null,resolution:null,map:null,featureDx:0,initialize:function(containerID,options){this.container=OpenLayers.Util.getElement(containerID);OpenLayers.Util.extend(this,options);},destroy:function(){this.container=null;this.extent=null;this.size=null;this.resolution=null;this.map=null;},supported:function(){return false;},setExtent:function(extent,resolutionChanged){this.extent=extent.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var ratio=extent.getWidth()/this.map.getExtent().getWidth(),extent=extent.scale(1/ratio);this.extent=extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio);}
-if(resolutionChanged){this.resolution=null;}
-return true;},setSize:function(size){this.size=size.clone();this.resolution=null;},getResolution:function(){this.resolution=this.resolution||this.map.getResolution();return this.resolution;},drawFeature:function(feature,style){if(style==null){style=feature.style;}
-if(feature.geometry){var bounds=feature.geometry.getBounds();if(bounds){var worldBounds;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){worldBounds=this.map.getMaxExtent();}
-if(!bounds.intersectsBounds(this.extent,{worldBounds:worldBounds})){style={display:"none"};}else{this.calculateFeatureDx(bounds,worldBounds);}
-var rendered=this.drawGeometry(feature.geometry,style,feature.id);if(style.display!="none"&&style.label&&rendered!==false){var location=feature.geometry.getCentroid();if(style.labelXOffset||style.labelYOffset){var xOffset=isNaN(style.labelXOffset)?0:style.labelXOffset;var yOffset=isNaN(style.labelYOffset)?0:style.labelYOffset;var res=this.getResolution();location.move(xOffset*res,yOffset*res);}
-this.drawText(feature.id,style,location);}else{this.removeText(feature.id);}
-return rendered;}}},calculateFeatureDx:function(bounds,worldBounds){this.featureDx=0;if(worldBounds){var worldWidth=worldBounds.getWidth(),rendererCenterX=(this.extent.left+this.extent.right)/2,featureCenterX=(bounds.left+bounds.right)/2,worldsAway=Math.round((featureCenterX-rendererCenterX)/worldWidth);this.featureDx=worldsAway*worldWidth;}},drawGeometry:function(geometry,style,featureId){},drawText:function(featureId,style,location){},removeText:function(featureId){},clear:function(){},getFeatureIdFromEvent:function(evt){},eraseFeatures:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
-for(var i=0,len=features.length;i<len;++i){var feature=features[i];this.eraseGeometry(feature.geometry,feature.id);this.removeText(feature.id);}},eraseGeometry:function(geometry,featureId){},moveRoot:function(renderer){},getRenderLayerId:function(){return this.container.id;},applyDefaultSymbolizer:function(symbolizer){var result=OpenLayers.Util.extend({},OpenLayers.Renderer.defaultSymbolizer);if(symbolizer.stroke===false){delete result.strokeWidth;delete result.strokeColor;}
-if(symbolizer.fill===false){delete result.fillColor;}
-OpenLayers.Util.extend(result,symbolizer);return result;},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Renderer.defaultSymbolizer={fillColor:"#000000",strokeColor:"#000000",strokeWidth:2,fillOpacity:1,strokeOpacity:1,pointRadius:0,labelAlign:'cm'};OpenLayers.Renderer.symbol={"star":[350,75,379,161,469,161,397,215,423,301,350,250,277,301,303,215,231,161,321,161,350,75],"cross":[4,0,6,0,6,4,10,4,10,6,6,6,6,10,4,10,4,6,0,6,0,4,4,4,4,0],"x":[0,0,25,0,50,35,75,0,100,0,65,50,100,100,75,100,50,65,25,100,0,100,35,50,0,0],"square":[0,0,0,1,1,1,1,0,0,0],"triangle":[0,10,10,10,5,0,0,10]};OpenLayers.Renderer.Canvas=OpenLayers.Class(OpenLayers.Renderer,{hitDetection:true,hitOverflow:0,canvas:null,features:null,pendingRedraw:false,cachedSymbolBounds:{},initialize:function(containerID,options){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.root=document.createElement("canvas");this.container.appendChild(this.root);this.canvas=this.root.getContext("2d");this.features={};if(this.hitDetection){this.hitCanvas=document.createElement("canvas");this.hitContext=this.hitCanvas.getContext("2d");}},setExtent:function(){OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);return false;},eraseGeometry:function(geometry,featureId){this.eraseFeatures(this.features[featureId][0]);},supported:function(){return OpenLayers.CANVAS_SUPPORTED;},setSize:function(size){this.size=size.clone();var root=this.root;root.style.width=size.w+"px";root.style.height=size.h+"px";root.width=size.w;root.height=size.h;this.resolution=null;if(this.hitDetection){var hitCanvas=this.hitCanvas;hitCanvas.style.width=size.w+"px";hitCanvas.style.height=size.h+"px";hitCanvas.width=size.w;hitCanvas.height=size.h;}},drawFeature:function(feature,style){var rendered;if(feature.geometry){style=this.applyDefaultSymbolizer(style||feature.style);var bounds=feature.geometry.getBounds();var worldBounds;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){worldBounds=this.map.getMaxExtent();}
-var intersects=bounds&&bounds.intersectsBounds(this.extent,{worldBounds:worldBounds});rendered=(style.display!=="none")&&!!bounds&&intersects;if(rendered){this.features[feature.id]=[feature,style];}
-else{delete(this.features[feature.id]);}
-this.pendingRedraw=true;}
-if(this.pendingRedraw&&!this.locked){this.redraw();this.pendingRedraw=false;}
-return rendered;},drawGeometry:function(geometry,style,featureId){var className=geometry.CLASS_NAME;if((className=="OpenLayers.Geometry.Collection")||(className=="OpenLayers.Geometry.MultiPoint")||(className=="OpenLayers.Geometry.MultiLineString")||(className=="OpenLayers.Geometry.MultiPolygon")){for(var i=0;i<geometry.components.length;i++){this.drawGeometry(geometry.components[i],style,featureId);}
-return;}
-switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":this.drawPoint(geometry,style,featureId);break;case"OpenLayers.Geometry.LineString":this.drawLineString(geometry,style,featureId);break;case"OpenLayers.Geometry.LinearRing":this.drawLinearRing(geometry,style,featureId);break;case"OpenLayers.Geometry.Polygon":this.drawPolygon(geometry,style,featureId);break;default:break;}},drawExternalGraphic:function(geometry,style,featureId){var img=new Image();var title=style.title||style.graphicTitle;if(title){img.title=title;}
-var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);var opacity=style.graphicOpacity||style.fillOpacity;var onLoad=function(){if(!this.features[featureId]){return;}
-var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(!isNaN(p0)&&!isNaN(p1)){var x=(p0+xOffset)|0;var y=(p1+yOffset)|0;var canvas=this.canvas;canvas.globalAlpha=opacity;var factor=OpenLayers.Renderer.Canvas.drawImageScaleFactor||(OpenLayers.Renderer.Canvas.drawImageScaleFactor=/android 2.1/.test(navigator.userAgent.toLowerCase())?320/window.screen.width:1);canvas.drawImage(img,x*factor,y*factor,width*factor,height*factor);if(this.hitDetection){this.setHitContextStyle("fill",featureId);this.hitContext.fillRect(x,y,width,height);}}};img.onload=OpenLayers.Function.bind(onLoad,this);img.src=style.externalGraphic;},drawNamedSymbol:function(geometry,style,featureId){var x,y,cx,cy,i,symbolBounds,scaling,angle;var unscaledStrokeWidth;var deg2rad=Math.PI/180.0;var symbol=OpenLayers.Renderer.symbol[style.graphicName];if(!symbol){throw new Error(style.graphicName+' is not a valid symbol name');}
-if(!symbol.length||symbol.length<2)return;var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(isNaN(p0)||isNaN(p1))return;this.canvas.lineCap="round";this.canvas.lineJoin="round";if(this.hitDetection){this.hitContext.lineCap="round";this.hitContext.lineJoin="round";}
-if(style.graphicName in this.cachedSymbolBounds){symbolBounds=this.cachedSymbolBounds[style.graphicName];}else{symbolBounds=new OpenLayers.Bounds();for(i=0;i<symbol.length;i+=2){symbolBounds.extend(new OpenLayers.LonLat(symbol[i],symbol[i+1]));}
-this.cachedSymbolBounds[style.graphicName]=symbolBounds;}
-this.canvas.save();if(this.hitDetection){this.hitContext.save();}
-this.canvas.translate(p0,p1);if(this.hitDetection){this.hitContext.translate(p0,p1);}
-angle=deg2rad*style.rotation;if(!isNaN(angle)){this.canvas.rotate(angle);if(this.hitDetection){this.hitContext.rotate(angle);}}
-scaling=2.0*style.pointRadius/Math.max(symbolBounds.getWidth(),symbolBounds.getHeight());this.canvas.scale(scaling,scaling);if(this.hitDetection){this.hitContext.scale(scaling,scaling);}
-cx=symbolBounds.getCenterLonLat().lon;cy=symbolBounds.getCenterLonLat().lat;this.canvas.translate(-cx,-cy);if(this.hitDetection){this.hitContext.translate(-cx,-cy);}
-unscaledStrokeWidth=style.strokeWidth;style.strokeWidth=unscaledStrokeWidth/scaling;if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.canvas.moveTo(x,y);this.canvas.lineTo(x,y);}
-this.canvas.closePath();this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.hitContext.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.canvas.moveTo(x,y);this.hitContext.lineTo(x,y);}
-this.hitContext.closePath();this.hitContext.fill();}}
-if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.canvas.moveTo(x,y);this.canvas.lineTo(x,y);}
-this.canvas.closePath();this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style,scaling);this.hitContext.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.hitContext.moveTo(x,y);this.hitContext.lineTo(x,y);}
-this.hitContext.closePath();this.hitContext.stroke();}}
-style.strokeWidth=unscaledStrokeWidth;this.canvas.restore();if(this.hitDetection){this.hitContext.restore();}
-this.setCanvasStyle("reset");},setCanvasStyle:function(type,style){if(type==="fill"){this.canvas.globalAlpha=style['fillOpacity'];this.canvas.fillStyle=style['fillColor'];}else if(type==="stroke"){this.canvas.globalAlpha=style['strokeOpacity'];this.canvas.strokeStyle=style['strokeColor'];this.canvas.lineWidth=style['strokeWidth'];}else{this.canvas.globalAlpha=0;this.canvas.lineWidth=1;}},featureIdToHex:function(featureId){var id=Number(featureId.split("_").pop())+1;if(id>=16777216){this.hitOverflow=id-16777215;id=id%16777216+1;}
-var hex="000000"+id.toString(16);var len=hex.length;hex="#"+hex.substring(len-6,len);return hex;},setHitContextStyle:function(type,featureId,symbolizer,strokeScaling){var hex=this.featureIdToHex(featureId);if(type=="fill"){this.hitContext.globalAlpha=1.0;this.hitContext.fillStyle=hex;}else if(type=="stroke"){this.hitContext.globalAlpha=1.0;this.hitContext.strokeStyle=hex;if(typeof strokeScaling==="undefined"){this.hitContext.lineWidth=symbolizer.strokeWidth+2;}else{if(!isNaN(strokeScaling)){this.hitContext.lineWidth=symbolizer.strokeWidth+2.0/strokeScaling;}}}else{this.hitContext.globalAlpha=0;this.hitContext.lineWidth=1;}},drawPoint:function(geometry,style,featureId){if(style.graphic!==false){if(style.externalGraphic){this.drawExternalGraphic(geometry,style,featureId);}else if(style.graphicName&&(style.graphicName!="circle")){this.drawNamedSymbol(geometry,style,featureId);}else{var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(!isNaN(p0)&&!isNaN(p1)){var twoPi=Math.PI*2;var radius=style.pointRadius;if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();this.canvas.arc(p0,p1,radius,0,twoPi,true);this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.hitContext.beginPath();this.hitContext.arc(p0,p1,radius,0,twoPi,true);this.hitContext.fill();}}
-if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();this.canvas.arc(p0,p1,radius,0,twoPi,true);this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style);this.hitContext.beginPath();this.hitContext.arc(p0,p1,radius,0,twoPi,true);this.hitContext.stroke();}
-this.setCanvasStyle("reset");}}}}},drawLineString:function(geometry,style,featureId){style=OpenLayers.Util.applyDefaults({fill:false},style);this.drawLinearRing(geometry,style,featureId);},drawLinearRing:function(geometry,style,featureId){if(style.fill!==false){this.setCanvasStyle("fill",style);this.renderPath(this.canvas,geometry,style,featureId,"fill");if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.renderPath(this.hitContext,geometry,style,featureId,"fill");}}
-if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.renderPath(this.canvas,geometry,style,featureId,"stroke");if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style);this.renderPath(this.hitContext,geometry,style,featureId,"stroke");}}
-this.setCanvasStyle("reset");},renderPath:function(context,geometry,style,featureId,type){var components=geometry.components;var len=components.length;context.beginPath();var start=this.getLocalXY(components[0]);var x=start[0];var y=start[1];if(!isNaN(x)&&!isNaN(y)){context.moveTo(start[0],start[1]);for(var i=1;i<len;++i){var pt=this.getLocalXY(components[i]);context.lineTo(pt[0],pt[1]);}
-if(type==="fill"){context.fill();}else{context.stroke();}}},drawPolygon:function(geometry,style,featureId){var components=geometry.components;var len=components.length;this.drawLinearRing(components[0],style,featureId);for(var i=1;i<len;++i){this.canvas.globalCompositeOperation="destination-out";if(this.hitDetection){this.hitContext.globalCompositeOperation="destination-out";}
-this.drawLinearRing(components[i],OpenLayers.Util.applyDefaults({stroke:false,fillOpacity:1.0},style),featureId);this.canvas.globalCompositeOperation="source-over";if(this.hitDetection){this.hitContext.globalCompositeOperation="source-over";}
-this.drawLinearRing(components[i],OpenLayers.Util.applyDefaults({fill:false},style),featureId);}},drawText:function(location,style){var pt=this.getLocalXY(location);this.setCanvasStyle("reset");this.canvas.fillStyle=style.fontColor;this.canvas.globalAlpha=style.fontOpacity||1.0;var fontStyle=[style.fontStyle?style.fontStyle:"normal","normal",style.fontWeight?style.fontWeight:"normal",style.fontSize?style.fontSize:"1em",style.fontFamily?style.fontFamily:"sans-serif"].join(" ");var labelRows=style.label.split('\n');var numRows=labelRows.length;if(this.canvas.fillText){this.canvas.font=fontStyle;this.canvas.textAlign=OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]]||"center";this.canvas.textBaseline=OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[1]]||"middle";var vfactor=OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];if(vfactor==null){vfactor=-.5;}
-var lineHeight=this.canvas.measureText('Mg').height||this.canvas.measureText('xx').width;pt[1]+=lineHeight*vfactor*(numRows-1);for(var i=0;i<numRows;i++){if(style.labelOutlineWidth){this.canvas.save();this.canvas.globalAlpha=style.labelOutlineOpacity||style.fontOpacity||1.0;this.canvas.strokeStyle=style.labelOutlineColor;this.canvas.lineWidth=style.labelOutlineWidth;this.canvas.strokeText(labelRows[i],pt[0],pt[1]+(lineHeight*i)+1);this.canvas.restore();}
-this.canvas.fillText(labelRows[i],pt[0],pt[1]+(lineHeight*i));}}else if(this.canvas.mozDrawText){this.canvas.mozTextStyle=fontStyle;var hfactor=OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[0]];if(hfactor==null){hfactor=-.5;}
-var vfactor=OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];if(vfactor==null){vfactor=-.5;}
-var lineHeight=this.canvas.mozMeasureText('xx');pt[1]+=lineHeight*(1+(vfactor*numRows));for(var i=0;i<numRows;i++){var x=pt[0]+(hfactor*this.canvas.mozMeasureText(labelRows[i]));var y=pt[1]+(i*lineHeight);this.canvas.translate(x,y);this.canvas.mozDrawText(labelRows[i]);this.canvas.translate(-x,-y);}}
-this.setCanvasStyle("reset");},getLocalXY:function(point){var resolution=this.getResolution();var extent=this.extent;var x=((point.x-this.featureDx)/resolution+(-extent.left/resolution));var y=((extent.top/resolution)-point.y/resolution);return[x,y];},clear:function(){var height=this.root.height;var width=this.root.width;this.canvas.clearRect(0,0,width,height);this.features={};if(this.hitDetection){this.hitContext.clearRect(0,0,width,height);}},getFeatureIdFromEvent:function(evt){var featureId,feature;if(this.hitDetection&&this.root.style.display!=="none"){if(!this.map.dragging){var xy=evt.xy;var x=xy.x|0;var y=xy.y|0;var data=this.hitContext.getImageData(x,y,1,1).data;if(data[3]===255){var id=data[2]+(256*(data[1]+(256*data[0])));if(id){featureId="OpenLayers_Feature_Vector_"+(id-1+this.hitOverflow);try{feature=this.features[featureId][0];}catch(err){}}}}}
-return feature;},eraseFeatures:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
-for(var i=0;i<features.length;++i){delete this.features[features[i].id];}
-this.redraw();},redraw:function(){if(!this.locked){var height=this.root.height;var width=this.root.width;this.canvas.clearRect(0,0,width,height);if(this.hitDetection){this.hitContext.clearRect(0,0,width,height);}
-var labelMap=[];var feature,geometry,style;var worldBounds=(this.map.baseLayer&&this.map.baseLayer.wrapDateLine)&&this.map.getMaxExtent();for(var id in this.features){if(!this.features.hasOwnProperty(id)){continue;}
-feature=this.features[id][0];geometry=feature.geometry;this.calculateFeatureDx(geometry.getBounds(),worldBounds);style=this.features[id][1];this.drawGeometry(geometry,style,feature.id);if(style.label){labelMap.push([feature,style]);}}
-var item;for(var i=0,len=labelMap.length;i<len;++i){item=labelMap[i];this.drawText(item[0].geometry.getCentroid(),item[1]);}}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={"l":"left","r":"right","t":"top","b":"bottom"};OpenLayers.Renderer.Canvas.LABEL_FACTOR={"l":0,"r":-1,"t":0,"b":-1};OpenLayers.Renderer.Canvas.drawImageScaleFactor=null;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.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.Keyboard=OpenLayers.Class(OpenLayers.Handler,{KEY_EVENTS:["keydown","keyup"],eventListener:null,observeElement:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.eventListener=OpenLayers.Function.bindAsEventListener(this.handleKeyEvent,this);},destroy:function(){this.deactivate();this.eventListener=null;OpenLayers.Handler.prototype.destroy.apply(this,arguments);},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.observeElement=this.observeElement||document;for(var i=0,len=this.KEY_EVENTS.length;i<len;i++){OpenLayers.Event.observe(this.observeElement,this.KEY_EVENTS[i],this.eventListener);}
-return true;}else{return false;}},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){for(var i=0,len=this.KEY_EVENTS.length;i<len;i++){OpenLayers.Event.stopObserving(this.observeElement,this.KEY_EVENTS[i],this.eventListener);}
-deactivated=true;}
-return deactivated;},handleKeyEvent:function(evt){if(this.checkModifiers(evt)){this.callback(evt.type,[evt]);}},CLASS_NAME:"OpenLayers.Handler.Keyboard"});OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{documentDrag:false,geometryTypes:null,clickout:true,toggle:true,standalone:false,layer:null,feature:null,vertex:null,vertices:null,virtualVertices:null,handlers:null,deleteCodes:null,virtualStyle:null,vertexRenderIntent:null,mode:null,createVertices:true,modified:false,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(layer,options){options=options||{};this.layer=layer;this.vertices=[];this.virtualVertices=[];this.virtualStyle=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer(null,options.vertexRenderIntent));this.virtualStyle.fillOpacity=0.3;this.virtualStyle.strokeOpacity=0.3;this.deleteCodes=[46,68];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[options]);if(!(OpenLayers.Util.isArray(this.deleteCodes))){this.deleteCodes=[this.deleteCodes];}
-var dragCallbacks={down:function(pixel){this.vertex=null;var feature=this.layer.getFeatureFromEvent(this.handlers.drag.evt);if(feature){this.dragStart(feature);}else if(this.clickout){this._unselect=this.feature;}},move:function(pixel){delete this._unselect;if(this.vertex){this.dragVertex(this.vertex,pixel);}},up:function(){this.handlers.drag.stopDown=false;if(this._unselect){this.unselectFeature(this._unselect);delete this._unselect;}},done:function(pixel){if(this.vertex){this.dragComplete(this.vertex);}}};var dragOptions={documentDrag:this.documentDrag,stopDown:false};var keyboardOptions={keydown:this.handleKeypress};this.handlers={keyboard:new OpenLayers.Handler.Keyboard(this,keyboardOptions),drag:new OpenLayers.Handler.Drag(this,dragCallbacks,dragOptions)};},destroy:function(){if(this.map){this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});}
-this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){this.moveLayerToTop();this.map.events.on({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});return(this.handlers.keyboard.activate()&&this.handlers.drag.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){var deactivated=false;if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});this.layer.removeFeatures(this.vertices,{silent:true});this.layer.removeFeatures(this.virtualVertices,{silent:true});this.vertices=[];this.handlers.drag.deactivate();this.handlers.keyboard.deactivate();var feature=this.feature;if(feature&&feature.geometry&&feature.layer){this.unselectFeature(feature);}
-deactivated=true;}
-return deactivated;},beforeSelectFeature:function(feature){return this.layer.events.triggerEvent("beforefeaturemodified",{feature:feature});},selectFeature:function(feature){if(this.feature===feature||(this.geometryTypes&&OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)==-1)){return;}
-if(this.beforeSelectFeature(feature)!==false){if(this.feature){this.unselectFeature(this.feature);}
-this.feature=feature;this.layer.selectedFeatures.push(feature);this.layer.drawFeature(feature,'select');this.modified=false;this.resetVertices();this.onModificationStart(this.feature);}
-var modified=feature.modified;if(feature.geometry&&!(modified&&modified.geometry)){this._originalGeometry=feature.geometry.clone();}},unselectFeature:function(feature){this.layer.removeFeatures(this.vertices,{silent:true});this.vertices=[];this.layer.destroyFeatures(this.virtualVertices,{silent:true});this.virtualVertices=[];if(this.dragHandle){this.layer.destroyFeatures([this.dragHandle],{silent:true});delete this.dragHandle;}
-if(this.radiusHandle){this.layer.destroyFeatures([this.radiusHandle],{silent:true});delete this.radiusHandle;}
-this.layer.drawFeature(this.feature,'default');this.feature=null;OpenLayers.Util.removeItem(this.layer.selectedFeatures,feature);this.onModificationEnd(feature);this.layer.events.triggerEvent("afterfeaturemodified",{feature:feature,modified:this.modified});this.modified=false;},dragStart:function(feature){var isPoint=feature.geometry.CLASS_NAME=='OpenLayers.Geometry.Point';if(!this.standalone&&((!feature._sketch&&isPoint)||!feature._sketch)){if(this.toggle&&this.feature===feature){this._unselect=feature;}
-this.selectFeature(feature);}
-if(feature._sketch||isPoint){this.vertex=feature;this.handlers.drag.stopDown=true;}},dragVertex:function(vertex,pixel){var pos=this.map.getLonLatFromViewPortPx(pixel);var geom=vertex.geometry;geom.move(pos.lon-geom.x,pos.lat-geom.y);this.modified=true;if(this.feature.geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){this.layer.events.triggerEvent("vertexmodified",{vertex:vertex.geometry,feature:this.feature,pixel:pixel});}else{if(vertex._index){vertex.geometry.parent.addComponent(vertex.geometry,vertex._index);delete vertex._index;OpenLayers.Util.removeItem(this.virtualVertices,vertex);this.vertices.push(vertex);}else if(vertex==this.dragHandle){this.layer.removeFeatures(this.vertices,{silent:true});this.vertices=[];if(this.radiusHandle){this.layer.destroyFeatures([this.radiusHandle],{silent:true});this.radiusHandle=null;}}else if(vertex!==this.radiusHandle){this.layer.events.triggerEvent("vertexmodified",{vertex:vertex.geometry,feature:this.feature,pixel:pixel});}
-if(this.virtualVertices.length>0){this.layer.destroyFeatures(this.virtualVertices,{silent:true});this.virtualVertices=[];}
-this.layer.drawFeature(this.feature,this.standalone?undefined:'select');}
-this.layer.drawFeature(vertex);},dragComplete:function(vertex){this.resetVertices();this.setFeatureState();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature});},setFeatureState:function(){if(this.feature.state!=OpenLayers.State.INSERT&&this.feature.state!=OpenLayers.State.DELETE){this.feature.state=OpenLayers.State.UPDATE;if(this.modified&&this._originalGeometry){var feature=this.feature;feature.modified=OpenLayers.Util.extend(feature.modified,{geometry:this._originalGeometry});delete this._originalGeometry;}}},resetVertices:function(){if(this.vertices.length>0){this.layer.removeFeatures(this.vertices,{silent:true});this.vertices=[];}
-if(this.virtualVertices.length>0){this.layer.removeFeatures(this.virtualVertices,{silent:true});this.virtualVertices=[];}
-if(this.dragHandle){this.layer.destroyFeatures([this.dragHandle],{silent:true});this.dragHandle=null;}
-if(this.radiusHandle){this.layer.destroyFeatures([this.radiusHandle],{silent:true});this.radiusHandle=null;}
-if(this.feature&&this.feature.geometry.CLASS_NAME!="OpenLayers.Geometry.Point"){if((this.mode&OpenLayers.Control.ModifyFeature.DRAG)){this.collectDragHandle();}
-if((this.mode&(OpenLayers.Control.ModifyFeature.ROTATE|OpenLayers.Control.ModifyFeature.RESIZE))){this.collectRadiusHandle();}
-if(this.mode&OpenLayers.Control.ModifyFeature.RESHAPE){if(!(this.mode&OpenLayers.Control.ModifyFeature.RESIZE)){this.collectVertices();}}}},handleKeypress:function(evt){var code=evt.keyCode;if(this.feature&&OpenLayers.Util.indexOf(this.deleteCodes,code)!=-1){var vertex=this.layer.getFeatureFromEvent(this.handlers.drag.evt);if(vertex&&OpenLayers.Util.indexOf(this.vertices,vertex)!=-1&&!this.handlers.drag.dragging&&vertex.geometry.parent){vertex.geometry.parent.removeComponent(vertex.geometry);this.layer.events.triggerEvent("vertexremoved",{vertex:vertex.geometry,feature:this.feature,pixel:evt.xy});this.layer.drawFeature(this.feature,this.standalone?undefined:'select');this.modified=true;this.resetVertices();this.setFeatureState();this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature});}}},collectVertices:function(){this.vertices=[];this.virtualVertices=[];var control=this;function collectComponentVertices(geometry){var i,vertex,component,len;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){vertex=new OpenLayers.Feature.Vector(geometry);vertex._sketch=true;vertex.renderIntent=control.vertexRenderIntent;control.vertices.push(vertex);}else{var numVert=geometry.components.length;if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){numVert-=1;}
-for(i=0;i<numVert;++i){component=geometry.components[i];if(component.CLASS_NAME=="OpenLayers.Geometry.Point"){vertex=new OpenLayers.Feature.Vector(component);vertex._sketch=true;vertex.renderIntent=control.vertexRenderIntent;control.vertices.push(vertex);}else{collectComponentVertices(component);}}
-if(control.createVertices&&geometry.CLASS_NAME!="OpenLayers.Geometry.MultiPoint"){for(i=0,len=geometry.components.length;i<len-1;++i){var prevVertex=geometry.components[i];var nextVertex=geometry.components[i+1];if(prevVertex.CLASS_NAME=="OpenLayers.Geometry.Point"&&nextVertex.CLASS_NAME=="OpenLayers.Geometry.Point"){var x=(prevVertex.x+nextVertex.x)/2;var y=(prevVertex.y+nextVertex.y)/2;var point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(x,y),null,control.virtualStyle);point.geometry.parent=geometry;point._index=i+1;point._sketch=true;control.virtualVertices.push(point);}}}}}
-collectComponentVertices.call(this,this.feature.geometry);this.layer.addFeatures(this.virtualVertices,{silent:true});this.layer.addFeatures(this.vertices,{silent:true});},collectDragHandle:function(){var geometry=this.feature.geometry;var center=geometry.getBounds().getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var origin=new OpenLayers.Feature.Vector(originGeometry);originGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);geometry.move(x,y);};origin._sketch=true;this.dragHandle=origin;this.dragHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.dragHandle],{silent:true});},collectRadiusHandle:function(){var geometry=this.feature.geometry;var bounds=geometry.getBounds();var center=bounds.getCenterLonLat();var originGeometry=new OpenLayers.Geometry.Point(center.lon,center.lat);var radiusGeometry=new OpenLayers.Geometry.Point(bounds.right,bounds.bottom);var radius=new OpenLayers.Feature.Vector(radiusGeometry);var resize=(this.mode&OpenLayers.Control.ModifyFeature.RESIZE);var reshape=(this.mode&OpenLayers.Control.ModifyFeature.RESHAPE);var rotate=(this.mode&OpenLayers.Control.ModifyFeature.ROTATE);radiusGeometry.move=function(x,y){OpenLayers.Geometry.Point.prototype.move.call(this,x,y);var dx1=this.x-originGeometry.x;var dy1=this.y-originGeometry.y;var dx0=dx1-x;var dy0=dy1-y;if(rotate){var a0=Math.atan2(dy0,dx0);var a1=Math.atan2(dy1,dx1);var angle=a1-a0;angle*=180/Math.PI;geometry.rotate(angle,originGeometry);}
-if(resize){var scale,ratio;if(reshape){scale=dy1/dy0;ratio=(dx1/dx0)/scale;}else{var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));scale=l1/l0;}
-geometry.resize(scale,originGeometry,ratio);}};radius._sketch=true;this.radiusHandle=radius;this.radiusHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.radiusHandle],{silent:true});},setMap:function(map){this.handlers.drag.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},handleMapEvents:function(evt){if(evt.type=="removelayer"||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},moveLayerBack:function(){var index=this.layer.getZIndex()-1;if(index>=this.map.Z_INDEX_BASE['Feature']){this.layer.setZIndex(index);}else{this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer));}},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.vendorPrefix=(function(){"use strict";var VENDOR_PREFIXES=["","O","ms","Moz","Webkit"],divStyle=document.createElement("div").style,cssCache={},jsCache={};function domToCss(prefixedDom){if(!prefixedDom){return null;}
-return prefixedDom.replace(/([A-Z])/g,function(c){return"-"+c.toLowerCase();}).replace(/^ms-/,"-ms-");}
-function css(property){if(cssCache[property]===undefined){var domProperty=property.replace(/(-[\s\S])/g,function(c){return c.charAt(1).toUpperCase();});var prefixedDom=style(domProperty);cssCache[property]=domToCss(prefixedDom);}
-return cssCache[property];}
-function js(obj,property){if(jsCache[property]===undefined){var tmpProp,i=0,l=VENDOR_PREFIXES.length,prefix,isStyleObj=(typeof obj.cssText!=="undefined");jsCache[property]=null;for(;i<l;i++){prefix=VENDOR_PREFIXES[i];if(prefix){if(!isStyleObj){prefix=prefix.toLowerCase();}
-tmpProp=prefix+property.charAt(0).toUpperCase()+property.slice(1);}else{tmpProp=property;}
-if(obj[tmpProp]!==undefined){jsCache[property]=tmpProp;break;}}}
-return jsCache[property];}
-function style(property){return js(divStyle,property);}
-return{css:css,js:js,style:style,cssCache:cssCache,jsCache:jsCache};}());OpenLayers.Animation=(function(window){var requestAnimationFrame=OpenLayers.Util.vendorPrefix.js(window,"requestAnimationFrame");var isNative=!!(requestAnimationFrame);var requestFrame=(function(){var request=window[requestAnimationFrame]||function(callback,element){window.setTimeout(callback,16);};return function(callback,element){request.apply(window,[callback,element]);};})();var counter=0;var loops={};function start(callback,duration,element){duration=duration>0?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.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<len;++i){code=codes[i];add(base,code,forwardMercator);add(code,base,inverseMercator);for(j=i+1;j<len;++j){other=codes[j];add(code,other,same);add(other,code,same);}}}
-var mercator=["EPSG:900913","EPSG:3857","EPSG:102113","EPSG:102100"],geographic=["CRS:84","urn:ogc:def:crs:EPSG:6.6:4326","EPSG:4326"],i;for(i=mercator.length-1;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,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(OpenLayers.TileManager&&this.tileManager!==null){if(!(this.tileManager instanceof OpenLayers.TileManager)){this.tileManager=new OpenLayers.TileManager(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<len;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
-if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
-if(this.controls==null){this.controls=[];if(OpenLayers.Control!=null){if(OpenLayers.Control.Navigation){this.controls.push(new OpenLayers.Control.Navigation());}else if(OpenLayers.Control.TouchNavigation){this.controls.push(new OpenLayers.Control.TouchNavigation());}
-if(OpenLayers.Control.Zoom){this.controls.push(new OpenLayers.Control.Zoom());}else if(OpenLayers.Control.PanZoom){this.controls.push(new OpenLayers.Control.PanZoom());}
-if(OpenLayers.Control.ArgParser){this.controls.push(new OpenLayers.Control.ArgParser());}
-if(OpenLayers.Control.Attribution){this.controls.push(new OpenLayers.Control.Attribution());}}}
-for(var i=0,len=this.controls.length;i<len;i++){this.addControlToMap(this.controls[i]);}
-this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);if(options&&options.layers){delete this.center;delete this.zoom;this.addLayers(options.layers);if(options.center&&!this.getCenter()){this.setCenter(options.center,options.zoom);}}
-if(this.panMethod){this.panTween=new OpenLayers.Tween(this.panMethod);}
-if(this.zoomMethod&&this.applyTransform.transform){this.zoomTween=new OpenLayers.Tween(this.zoomMethod);}},getViewport:function(){return this.viewPortDiv;},render:function(div){this.div=OpenLayers.Util.getElement(div);OpenLayers.Element.addClass(this.div,'olMap');this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);this.div.appendChild(this.viewPortDiv);this.updateSize();},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
-if(this.panTween){this.panTween.stop();this.panTween=null;}
-if(this.zoomTween){this.zoomTween.stop();this.zoomTween=null;}
-OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.updateSizeDestroy){OpenLayers.Event.stopObserving(window,'resize',this.updateSizeDestroy);}
-this.paddingForPopups=null;if(this.controls!=null){for(var i=this.controls.length-1;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;i<len;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;break;}}
-return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
-+zIdx*5);},resetLayersZIndex:function(){for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];this.setLayerZIndex(layer,i);}},addLayer:function(layer){for(var i=0,len=this.layers.length;i<len;i++){if(this.layers[i]==layer){return false;}}
-if(this.events.triggerEvent("preaddlayer",{layer:layer})===false){return false;}
-if(this.allOverlays){layer.isBaseLayer=false;}
-layer.div.className="olLayerDiv";layer.div.style.overflow="";this.setLayerZIndex(layer,this.layers.length);if(layer.isFixed){this.viewPortDiv.appendChild(layer.div);}else{this.layerContainerDiv.appendChild(layer.div);}
-this.layers.push(layer);layer.setMap(this);if(layer.isBaseLayer||(this.allOverlays&&!this.baseLayer)){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
-this.events.triggerEvent("addlayer",{layer:layer});layer.events.triggerEvent("added",{map:this,layer:layer});layer.afterAdd();return true;},addLayers:function(layers){for(var i=0,len=layers.length;i<len;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){if(this.events.triggerEvent("preremovelayer",{layer:layer})===false){return;}
-if(setNewBaseLayer==null){setNewBaseLayer=true;}
-if(layer.isFixed){this.viewPortDiv.removeChild(layer.div);}else{this.layerContainerDiv.removeChild(layer.div);}
-OpenLayers.Util.removeItem(this.layers,layer);layer.removeMap(this);layer.map=null;if(this.baseLayer==layer){this.baseLayer=null;if(setNewBaseLayer){for(var i=0,len=this.layers.length;i<len;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer||this.allOverlays){this.setBaseLayer(iLayer);break;}}}}
-this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:layer});layer.events.triggerEvent("removed",{map:this,layer:layer});},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},setLayerIndex:function(layer,idx){var base=this.getLayerIndex(layer);if(idx<0){idx=0;}else if(idx>this.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<len;i++){this.setLayerZIndex(this.layers[i],i);}
-this.events.triggerEvent("changelayer",{layer:layer,property:"order"});if(this.allOverlays){if(idx===0){this.setBaseLayer(layer);}else if(this.baseLayer!==this.layers[0]){this.setBaseLayer(this.layers[0]);}}}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){var center=this.getCachedCenter();var newResolution=OpenLayers.Util.getResolutionFromScale(this.getScale(),newBaseLayer.units);if(this.baseLayer!=null&&!this.allOverlays){this.baseLayer.setVisibility(false);}
-this.baseLayer=newBaseLayer;if(!this.allOverlays||this.baseLayer.visibility){this.baseLayer.setVisibility(true);if(this.baseLayer.inRange===false){this.baseLayer.redraw();}}
-if(center!=null){var newZoom=this.getZoomForResolution(newResolution||this.resolution,true);this.setCenter(center,newZoom,false,true);}
-this.events.triggerEvent("changebaselayer",{layer:this.baseLayer});}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControls:function(controls,pixels){var pxs=(arguments.length===1)?[]:pixels;for(var i=0,len=controls.length;i<len;i++){var ctrl=controls[i];var px=(pxs[i])?pxs[i]:null;this.addControl(ctrl,px);}},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);if(this.displayProjection&&!control.displayProjection){control.displayProjection=this.displayProjection;}
-control.setMap(this);var div=control.draw(px);if(div){if(!control.outsideViewport){div.style.zIndex=this.Z_INDEX_BASE['Control']+
-this.controls.length;this.viewPortDiv.appendChild(div);}}
-if(control.autoActivate){control.activate();}},getControl:function(id){var returnControl=null;for(var i=0,len=this.controls.length;i<len;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
-return returnControl;},removeControl:function(control){if((control)&&(control==this.getControl(control.id))){if(control.div&&(control.div.parentNode==this.viewPortDiv)){this.viewPortDiv.removeChild(control.div);}
-OpenLayers.Util.removeItem(this.controls,control);}},addPopup:function(popup,exclusive){if(exclusive){for(var i=this.popups.length-1;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<len;i++){this.layers[i].onMapResize();}
-var center=this.getCachedCenter();if(this.baseLayer!=null&&center!=null){var zoom=this.getZoom();this.zoom=null;this.setCenter(center,zoom);}}}
-this.events.triggerEvent("updatesize");},getCurrentSize:function(){var size=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=this.div.offsetWidth;size.h=this.div.offsetHeight;}
-if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=parseInt(this.div.style.width);size.h=parseInt(this.div.style.height);}
-return size;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCachedCenter();}
-if(resolution==null){resolution=this.getResolution();}
-if((center!=null)&&(resolution!=null)){var halfWDeg=(this.size.w*resolution)/2;var halfHDeg=(this.size.h*resolution)/2;extent=new OpenLayers.Bounds(center.lon-halfWDeg,center.lat-halfHDeg,center.lon+halfWDeg,center.lat+halfHDeg);}
-return extent;},getCenter:function(){var center=null;var cachedCenter=this.getCachedCenter();if(cachedCenter){center=cachedCenter.clone();}
-return center;},getCachedCenter:function(){if(!this.center&&this.size){this.center=this.getLonLatFromViewPortPx({x:this.size.w/2,y:this.size.h/2});}
-return this.center;},getZoom:function(){return this.zoom;},pan:function(dx,dy,options){options=OpenLayers.Util.applyDefaults(options,{animate:true,dragging:false});if(options.dragging){if(dx!=0||dy!=0){this.moveByPx(dx,dy);}}else{var centerPx=this.getViewPortPxFromLonLat(this.getCachedCenter());var newCenterPx=centerPx.add(dx,dy);if(this.dragging||!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);if(options.animate){this.panTo(newCenterLonLat);}else{this.moveTo(newCenterLonLat);if(this.dragging){this.dragging=false;this.events.triggerEvent("moveend");}}}}},panTo:function(lonlat){if(this.panTween&&this.getExtent().scale(this.panRatio).containsLonLat(lonlat)){var center=this.getCachedCenter();if(lonlat.equals(center)){return;}
-var from=this.getPixelFromLonLat(center);var to=this.getPixelFromLonLat(lonlat);var vector={x:to.x-from.x,y:to.y-from.y};var last={x:0,y:0};this.panTween.start({x:0,y:0},vector,this.panDuration,{callbacks:{eachStep:OpenLayers.Function.bind(function(px){var x=px.x-last.x,y=px.y-last.y;this.moveByPx(x,y);last.x=Math.round(px.x);last.y=Math.round(px.y);},this),done:OpenLayers.Function.bind(function(px){this.moveTo(lonlat);this.dragging=false;this.events.triggerEvent("moveend");},this)}});}else{this.setCenter(lonlat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){if(this.panTween){this.panTween.stop();}
-if(this.zoomTween){this.zoomTween.stop();}
-this.moveTo(lonlat,zoom,{'dragging':dragging,'forceZoomChange':forceZoomChange});},moveByPx:function(dx,dy){var hw=this.size.w/2;var hh=this.size.h/2;var x=hw+dx;var y=hh+dy;var wrapDateLine=this.baseLayer.wrapDateLine;var xRestriction=0;var yRestriction=0;if(this.restrictedExtent){xRestriction=hw;yRestriction=hh;wrapDateLine=false;}
-dx=wrapDateLine||x<=this.maxPx.x-xRestriction&&x>=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;i<len;++i){layer=this.layers[i];if(layer.visibility&&(layer===this.baseLayer||layer.inRange)){layer.moveByPx(dx,dy);layer.events.triggerEvent("move");}}
-this.events.triggerEvent("move");}},adjustZoom:function(zoom){if(this.baseLayer&&this.baseLayer.wrapDateLine){var resolution,resolutions=this.baseLayer.resolutions,maxResolution=this.getMaxExtent().getWidth()/this.size.w;if(this.getResolutionForZoom(zoom)>maxResolution){if(this.fractionalZoom){zoom=this.getZoomForResolution(maxResolution);}else{for(var i=zoom|0,ii=resolutions.length;i<ii;++i){if(resolutions[i]<=maxResolution){zoom=i;break;}}}}}
-return zoom;},getMinZoom:function(){return this.adjustZoom(0);},moveTo:function(lonlat,zoom,options){if(lonlat!=null&&!(lonlat instanceof OpenLayers.LonLat)){lonlat=new OpenLayers.LonLat(lonlat);}
-if(!options){options={};}
-if(zoom!=null){zoom=parseFloat(zoom);if(!this.fractionalZoom){zoom=Math.round(zoom);}}
-var requestedZoom=zoom;zoom=this.adjustZoom(zoom);if(zoom!==requestedZoom){lonlat=this.getCenter();}
-var dragging=options.dragging||this.dragging;var forceZoomChange=options.forceZoomChange;if(!this.getCachedCenter()&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();this.center=lonlat.clone();}
-if(this.restrictedExtent!=null){if(lonlat==null){lonlat=this.center;}
-if(zoom==null){zoom=this.getZoom();}
-var resolution=this.getResolutionForZoom(zoom);var extent=this.calculateBounds(lonlat,resolution);if(!this.restrictedExtent.containsBounds(extent)){var maxCenter=this.restrictedExtent.getCenterLonLat();if(extent.getWidth()>this.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.left<this.restrictedExtent.left){lonlat=lonlat.add(this.restrictedExtent.left-
-extent.left,0);}else if(extent.right>this.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.bottom<this.restrictedExtent.bottom){lonlat=lonlat.add(0,this.restrictedExtent.bottom-
-extent.bottom);}
-else if(extent.top>this.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);}
-this.events.triggerEvent("changelayer",{layer:layer,property:"visibility"});}
-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<len;i++){this.popups[i].updatePosition();}
-this.events.triggerEvent("zoomend");}}},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){var oldLeft=this.layerContainerOriginPx.x;var oldTop=this.layerContainerOriginPx.y;var newLeft=Math.round(originPx.x-newPx.x);var newTop=Math.round(originPx.y-newPx.y);this.applyTransform((this.layerContainerOriginPx.x=newLeft),(this.layerContainerOriginPx.y=newTop));var dx=oldLeft-newLeft;var dy=oldTop-newTop;this.minPx.x-=dx;this.maxPx.x-=dx;this.minPx.y-=dy;this.maxPx.y-=dy;}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();var worldBounds=this.baseLayer.wrapDateLine&&maxExtent;valid=maxExtent.containsLonLat(lonlat,{worldBounds:worldBounds});}
-return valid;},getProjection:function(){var projection=this.getProjectionObject();return projection?projection.getCode():null;},getProjectionObject:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
-return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
-return maxResolution;},getMaxExtent:function(options){var maxExtent=null;if(options&&options.restricted&&this.restrictedExtent){maxExtent=this.restrictedExtent;}else if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
-return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
-return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
-return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}else if(this.allOverlays===true&&this.layers.length>0){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<bounds.left){bounds.right+=maxExtent.getWidth();}
-center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
-this.setCenter(center,this.getZoomForExtent(bounds,closest));},zoomToMaxExtent:function(options){var restricted=(options)?options.restricted:true;var maxExtent=this.getMaxExtent({'restricted':restricted});this.zoomToExtent(maxExtent);},zoomToScale:function(scale,closest){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var halfWDeg=(this.size.w*res)/2;var halfHDeg=(this.size.h*res)/2;var center=this.getCachedCenter();var extent=new OpenLayers.Bounds(center.lon-halfWDeg,center.lat-halfHDeg,center.lon+halfWDeg,center.lat+halfHDeg);this.zoomToExtent(extent,closest);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
-return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
-return px;},getZoomTargetCenter:function(xy,resolution){var lonlat=null,size=this.getSize(),deltaX=size.w/2-xy.x,deltaY=xy.y-size.h/2,zoomPoint=this.getLonLatFromPixel(xy);if(zoomPoint){lonlat=new OpenLayers.LonLat(zoomPoint.lon+deltaX*resolution,zoomPoint.lat+deltaY*resolution);}
-return lonlat;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);px.x=Math.round(px.x);px.y=Math.round(px.y);return px;},getGeodesicPixelSize:function(px){var lonlat=px?this.getLonLatFromPixel(px):(this.getCachedCenter()||new OpenLayers.LonLat(0,0));var res=this.getResolution();var left=lonlat.add(-res/2,0);var right=lonlat.add(res/2,0);var bottom=lonlat.add(0,-res/2);var top=lonlat.add(0,res/2);var dest=new OpenLayers.Projection("EPSG:4326");var source=this.getProjectionObject()||dest;if(!source.equals(dest)){left.transform(source,dest);right.transform(source,dest);bottom.transform(source,dest);top.transform(source,dest);}
-return new OpenLayers.Size(OpenLayers.Util.distVincenty(left,right),OpenLayers.Util.distVincenty(bottom,top));},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=this.layerContainerOriginPx.x;var dY=this.layerContainerOriginPx.y;viewPortPx=layerPx.add(dX,dY);}
-return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-this.layerContainerOriginPx.x;var dY=-this.layerContainerOriginPx.y;layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
-return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getPixelFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},applyTransform:function(x,y,scale){scale=scale||1;var origin=this.layerContainerOriginPx,needTransform=scale!==1;x=x||origin.x;y=y||origin.y;var style=this.layerContainerDiv.style,transform=this.applyTransform.transform,template=this.applyTransform.template;if(transform===undefined){transform=OpenLayers.Util.vendorPrefix.style('transform');this.applyTransform.transform=transform;if(transform){var computedStyle=OpenLayers.Element.getStyle(this.viewPortDiv,OpenLayers.Util.vendorPrefix.css('transform'));if(!computedStyle||computedStyle!=='none'){template=['translate3d(',',0) ','scale3d(',',1)'];style[transform]=[template[0],'0,0',template[1]].join('');}
-if(!template||!~style[transform].indexOf(template[0])){template=['translate(',') ','scale(',')'];}
-this.applyTransform.template=template;}}
-if(transform!==null&&(template[0]==='translate3d('||needTransform===true)){if(needTransform===true&&template[0]==='translate('){x-=origin.x;y-=origin.y;style.left=origin.x+'px';style.top=origin.y+'px';}
-style[transform]=[template[0],x,'px,',y,'px',template[1],template[2],scale,',',scale,template[3]].join('');}else{style.left=x+'px';style.top=y+'px';if(transform!==null){style[transform]='';}}},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:1,alwaysInRange:null,RESOLUTION_PROPERTIES:['scales','resolutions','maxScale','minScale','maxResolution','minResolution','numZoomLevels','maxZoomLevel'],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:false,wrapDateLine:false,metadata:null,initialize:function(name,options){this.metadata={};options=OpenLayers.Util.extend({},options);if(this.alwaysInRange!=null){options.alwaysInRange=this.alwaysInRange;}
-this.addOptions(options);this.name=name;if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.div=OpenLayers.Util.createDiv(this.id);this.div.style.width="100%";this.div.style.height="100%";this.div.dir="ltr";this.events=new OpenLayers.Events(this,this.div);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}}},destroy:function(setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
-if(this.map!=null){this.map.removeLayer(this,setNewBaseLayer);}
-this.projection=null;this.map=null;this.name=null;this.div=null;this.options=null;if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
-this.events.destroy();}
-this.eventListeners=null;this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.getOptions());}
-OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},getOptions:function(){var options={};for(var o in this.options){options[o]=this[o];}
-return options;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"name"});}}},addOptions:function(newOptions,reinitialize){if(this.options==null){this.options={};}
-if(newOptions){if(typeof newOptions.projection=="string"){newOptions.projection=new OpenLayers.Projection(newOptions.projection);}
-if(newOptions.projection){OpenLayers.Util.applyDefaults(newOptions,OpenLayers.Projection.defaults[newOptions.projection.getCode()]);}
-if(newOptions.maxExtent&&!(newOptions.maxExtent instanceof OpenLayers.Bounds)){newOptions.maxExtent=new OpenLayers.Bounds(newOptions.maxExtent);}
-if(newOptions.minExtent&&!(newOptions.minExtent instanceof OpenLayers.Bounds)){newOptions.minExtent=new OpenLayers.Bounds(newOptions.minExtent);}}
-OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);if(this.projection&&this.projection.getUnits()){this.units=this.projection.getUnits();}
-if(this.map){var resolution=this.map.getResolution();var properties=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]);for(var o in newOptions){if(newOptions.hasOwnProperty(o)&&OpenLayers.Util.indexOf(properties,o)>=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();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});}
-this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display&&this.calculateInRange())?"block":"none";}},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<len;i++){p=this.RESOLUTION_PROPERTIES[i];props[p]=this.options[p];if(alwaysInRange&&this.options[p]){alwaysInRange=false;}}
-if(this.options.alwaysInRange==null){this.alwaysInRange=alwaysInRange;}
-if(props.resolutions==null){props.resolutions=this.resolutionsFromScales(props.scales);}
-if(props.resolutions==null){props.resolutions=this.calculateResolutions(props);}
-if(props.resolutions==null){for(i=0,len=this.RESOLUTION_PROPERTIES.length;i<len;i++){p=this.RESOLUTION_PROPERTIES[i];props[p]=this.options[p]!=null?this.options[p]:this.map[p];}
-if(props.resolutions==null){props.resolutions=this.resolutionsFromScales(props.scales);}
-if(props.resolutions==null){props.resolutions=this.calculateResolutions(props);}}
-var maxResolution;if(this.options.maxResolution&&this.options.maxResolution!=="auto"){maxResolution=this.options.maxResolution;}
-if(this.options.minScale){maxResolution=OpenLayers.Util.getResolutionFromScale(this.options.minScale,this.units);}
-var minResolution;if(this.options.minResolution&&this.options.minResolution!=="auto"){minResolution=this.options.minResolution;}
-if(this.options.maxScale){minResolution=OpenLayers.Util.getResolutionFromScale(this.options.maxScale,this.units);}
-if(props.resolutions){props.resolutions.sort(function(a,b){return(b-a);});if(!maxResolution){maxResolution=props.resolutions[0];}
-if(!minResolution){var lastIdx=props.resolutions.length-1;minResolution=props.resolutions[lastIdx];}}
-this.resolutions=props.resolutions;if(this.resolutions){len=this.resolutions.length;this.scales=new Array(len);for(i=0;i<len;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(this.resolutions[i],this.units);}
-this.numZoomLevels=len;}
-this.minResolution=minResolution;if(minResolution){this.maxScale=OpenLayers.Util.getScaleFromResolution(minResolution,this.units);}
-this.maxResolution=maxResolution;if(maxResolution){this.minScale=OpenLayers.Util.getScaleFromResolution(maxResolution,this.units);}},resolutionsFromScales:function(scales){if(scales==null){return;}
-var resolutions,i,len;len=scales.length;resolutions=new Array(len);for(i=0;i<len;i++){resolutions[i]=OpenLayers.Util.getResolutionFromScale(scales[i],this.units);}
-return resolutions;},calculateResolutions:function(props){var viewSize,wRes,hRes;var maxResolution=props.maxResolution;if(props.minScale!=null){maxResolution=OpenLayers.Util.getResolutionFromScale(props.minScale,this.units);}else if(maxResolution=="auto"&&this.maxExtent!=null){viewSize=this.map.getSize();wRes=this.maxExtent.getWidth()/viewSize.w;hRes=this.maxExtent.getHeight()/viewSize.h;maxResolution=Math.max(wRes,hRes);}
-var minResolution=props.minResolution;if(props.maxScale!=null){minResolution=OpenLayers.Util.getResolutionFromScale(props.maxScale,this.units);}else if(props.minResolution=="auto"&&this.minExtent!=null){viewSize=this.map.getSize();wRes=this.minExtent.getWidth()/viewSize.w;hRes=this.minExtent.getHeight()/viewSize.h;minResolution=Math.max(wRes,hRes);}
-if(typeof maxResolution!=="number"&&typeof minResolution!=="number"&&this.maxExtent!=null){var tileSize=this.map.getTileSize();maxResolution=Math.max(this.maxExtent.getWidth()/tileSize.w,this.maxExtent.getHeight()/tileSize.h);}
-var maxZoomLevel=props.maxZoomLevel;var numZoomLevels=props.numZoomLevels;if(typeof minResolution==="number"&&typeof maxResolution==="number"&&numZoomLevels===undefined){var ratio=maxResolution/minResolution;numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}else if(numZoomLevels===undefined&&maxZoomLevel!=null){numZoomLevels=maxZoomLevel+1;}
-if(typeof numZoomLevels!=="number"||numZoomLevels<=0||(typeof maxResolution!=="number"&&typeof minResolution!=="number")){return;}
-var resolutions=new Array(numZoomLevels);var base=2;if(typeof minResolution=="number"&&typeof maxResolution=="number"){base=Math.pow((maxResolution/minResolution),(1/(numZoomLevels-1)));}
-var i;if(typeof maxResolution==="number"){for(i=0;i<numZoomLevels;i++){resolutions[i]=maxResolution/Math.pow(base,i);}}else{for(i=0;i<numZoomLevels;i++){resolutions[numZoomLevels-1-i]=minResolution*Math.pow(base,i);}}
-return resolutions;},getResolution:function(){var zoom=this.map.getZoom();return this.getResolutionForZoom(zoom);},getExtent:function(){return this.map.calculateBounds();},getZoomForExtent:function(extent,closest){var viewSize=this.map.getSize();var idealResolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);return this.getZoomForResolution(idealResolution,closest);},getDataExtent:function(){},getResolutionForZoom:function(zoom){zoom=Math.max(0,Math.min(zoom,this.resolutions.length-1));var resolution;if(this.map.fractionalZoom){var low=Math.floor(zoom);var high=Math.ceil(zoom);resolution=this.resolutions[low]-
-((zoom-low)*(this.resolutions[low]-this.resolutions[high]));}else{resolution=this.resolutions[Math.round(zoom)];}
-return resolution;},getZoomForResolution:function(resolution,closest){var zoom,i,len;if(this.map.fractionalZoom){var lowZoom=0;var highZoom=this.resolutions.length-1;var highRes=this.resolutions[lowZoom];var lowRes=this.resolutions[highZoom];var res;for(i=0,len=this.resolutions.length;i<len;++i){res=this.resolutions[i];if(res>=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;i<len;i++){if(closest){diff=Math.abs(this.resolutions[i]-resolution);if(diff>minDiff){break;}
-minDiff=diff;}else{if(this.resolutions[i]<resolution){break;}}}
-zoom=Math.max(0,i-1);}
-return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;var map=this.map;if(viewPortPx!=null&&map.minPx){var res=map.getResolution();var maxExtent=map.getMaxExtent({restricted:true});var lon=(viewPortPx.x-map.minPx.x)*res+maxExtent.left;var lat=(map.minPx.y-viewPortPx.y)*res+maxExtent.top;lonlat=new OpenLayers.LonLat(lon,lat);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}
-return lonlat;},getViewPortPxFromLonLat:function(lonlat,resolution){var px=null;if(lonlat!=null){resolution=resolution||this.map.getResolution();var extent=this.map.calculateBounds(null,resolution);px=new OpenLayers.Pixel((1/resolution*(lonlat.lon-extent.left)),(1/resolution*(extent.top-lonlat.lat)));}
-return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;var childNodes=this.div.childNodes;for(var i=0,len=childNodes.length;i<len;++i){var element=childNodes[i].firstChild||childNodes[i];var lastChild=childNodes[i].lastChild;if(lastChild&&lastChild.nodeName.toLowerCase()==="iframe"){element=lastChild.parentNode;}
-OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}
-if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"});}}},getZIndex:function(){return this.div.style.zIndex;},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){var mapGutter=this.gutter*this.map.getResolution();bounds=new OpenLayers.Bounds(bounds.left-mapGutter,bounds.bottom-mapGutter,bounds.right+mapGutter,bounds.top+mapGutter);}
-if(this.wrapDateLine){var wrappingOptions={'rightTolerance':this.getResolution(),'leftTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
-return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){OpenLayers.Layer.prototype.initialize.apply(this,[name,options]);this.url=url;if(!this.params){this.params=OpenLayers.Util.extend({},params);}},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.getOptions());}
-obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);var ret=this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"params"});}
-return ret;},redraw:function(force){if(force){return this.mergeNewParams({"_olSalt":Math.random()});}else{return OpenLayers.Layer.prototype.redraw.apply(this,[]);}},selectUrl:function(paramString,urls){var product=1;for(var i=0,len=paramString.length;i<len;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
-return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(OpenLayers.Util.isArray(url)){url=this.selectUrl(paramsString,url);}
-var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
-paramsString=OpenLayers.Util.getParameterString(allParams);return OpenLayers.Util.urlAppend(url,paramsString);},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Tile=OpenLayers.Class({events:null,eventListeners:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,initialize:function(layer,position,bounds,url,size,options){this.layer=layer;this.position=position.clone();this.setBounds(bounds);this.url=url;if(size){this.size=size.clone();}
-this.id=OpenLayers.Util.createUniqueID("Tile_");OpenLayers.Util.extend(this,options);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}},unload:function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("unload");}},destroy:function(){this.layer=null;this.bounds=null;this.size=null;this.position=null;if(this.eventListeners){this.events.un(this.eventListeners);}
-this.events.destroy();this.eventListeners=null;this.events=null;},draw:function(force){if(!force){this.clear();}
-var draw=this.shouldDraw();if(draw&&!force&&this.events.triggerEvent("beforedraw")===false){draw=null;}
-return draw;},shouldDraw:function(){var withinMaxExtent=false,maxExtent=this.layer.maxExtent;if(maxExtent){var map=this.layer.map;var worldBounds=map.baseLayer.wrapDateLine&&map.getMaxExtent();if(this.bounds.intersectsBounds(maxExtent,{inclusive:false,worldBounds:worldBounds})){withinMaxExtent=true;}}
-return withinMaxExtent||this.layer.displayOutsideMaxExtent;},setBounds:function(bounds){bounds=bounds.clone();if(this.layer.map.baseLayer.wrapDateLine){var worldExtent=this.layer.map.getMaxExtent(),tolerance=this.layer.map.getResolution();bounds=bounds.wrapDateLine(worldExtent,{leftTolerance:tolerance,rightTolerance:tolerance});}
-this.bounds=bounds;},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
-this.setBounds(bounds);this.position=position.clone();if(redraw){this.draw();}},clear:function(draw){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,maxGetUrlLength:null,canvasContext:null,crossOriginKeyword:null,initialize:function(layer,position,bounds,url,size,options){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();if(this.maxGetUrlLength!=null||this.layer.gutter||this.layerAlphaHack){this.frame=document.createElement("div");this.frame.style.position="absolute";this.frame.style.overflow="hidden";}
-if(this.maxGetUrlLength!=null){OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame);}},destroy:function(){if(this.imgDiv){this.clear();this.imgDiv=null;this.frame=null;}
-this.asyncRequestId=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments);},draw:function(){var shouldDraw=OpenLayers.Tile.prototype.draw.apply(this,arguments);if(shouldDraw){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
-if(this.isLoading){this._loadEvent="reload";}else{this.isLoading=true;this._loadEvent="loadstart";}
-this.renderTile();this.positionTile();}else if(shouldDraw===false){this.unload();}
-return shouldDraw;},renderTile:function(){if(this.layer.async){var id=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,function(url){if(id==this.asyncRequestId){this.url=url;this.initImage();}},this);}else{this.url=this.layer.getURL(this.bounds);this.initImage();}},positionTile:function(){var style=this.getTile().style,size=this.frame?this.size:this.layer.getImageSize(this.bounds),ratio=1;if(this.layer instanceof OpenLayers.Layer.Grid){ratio=this.layer.getServerResolution()/this.layer.map.getResolution();}
-style.left=this.position.x+"px";style.top=this.position.y+"px";style.width=Math.round(ratio*size.w)+"px";style.height=Math.round(ratio*size.h)+"px";},clear:function(){OpenLayers.Tile.prototype.clear.apply(this,arguments);var img=this.imgDiv;if(img){var tile=this.getTile();if(tile.parentNode===this.layer.div){this.layer.div.removeChild(tile);}
-this.setImgSrc();if(this.layerAlphaHack===true){img.style.filter="";}
-OpenLayers.Element.removeClass(img,"olImageLoadError");}
-this.canvasContext=null;},getImage:function(){if(!this.imgDiv){this.imgDiv=OpenLayers.Tile.Image.IMAGE.cloneNode(false);var style=this.imgDiv.style;if(this.frame){var left=0,top=0;if(this.layer.gutter){left=this.layer.gutter/this.layer.tileSize.w*100;top=this.layer.gutter/this.layer.tileSize.h*100;}
-style.left=-left+"%";style.top=-top+"%";style.width=(2*left+100)+"%";style.height=(2*top+100)+"%";}
-style.visibility="hidden";style.opacity=0;if(this.layer.opacity<1){style.filter='alpha(opacity='+
-(this.layer.opacity*100)+')';}
-style.position="absolute";if(this.layerAlphaHack){style.paddingTop=style.height;style.height="0";style.width="100%";}
-if(this.frame){this.frame.appendChild(this.imgDiv);}}
-return this.imgDiv;},setImage:function(img){this.imgDiv=img;},initImage:function(){if(!this.url&&!this.imgDiv){this.isLoading=false;return;}
-this.events.triggerEvent('beforeload');this.layer.div.appendChild(this.getTile());this.events.triggerEvent(this._loadEvent);var img=this.getImage();var src=img.getAttribute('src')||'';if(this.url&&OpenLayers.Util.isEquivalentUrl(src,this.url)){this._loadTimeout=window.setTimeout(OpenLayers.Function.bind(this.onImageLoad,this),0);}else{this.stopLoading();if(this.crossOriginKeyword){img.removeAttribute("crossorigin");}
-OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(this.onImageError,this));this.imageReloadAttempts=0;this.setImgSrc(this.url);}},setImgSrc:function(url){var img=this.imgDiv;if(url){img.style.visibility='hidden';img.style.opacity=0;if(this.crossOriginKeyword){if(url.substr(0,5)!=='data:'){img.setAttribute("crossorigin",this.crossOriginKeyword);}else{img.removeAttribute("crossorigin");}}
-img.src=url;}else{this.stopLoading();this.imgDiv=null;if(img.parentNode){img.parentNode.removeChild(img);}}},getTile:function(){return this.frame?this.frame:this.getImage();},createBackBuffer:function(){if(!this.imgDiv||this.isLoading){return;}
-var backBuffer;if(this.frame){backBuffer=this.frame.cloneNode(false);backBuffer.appendChild(this.imgDiv);}else{backBuffer=this.imgDiv;}
-this.imgDiv=null;return backBuffer;},onImageLoad:function(){var img=this.imgDiv;this.stopLoading();img.style.visibility='inherit';img.style.opacity=this.layer.opacity;this.isLoading=false;this.canvasContext=null;this.events.triggerEvent("loadend");if(this.layerAlphaHack===true){img.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+
-img.src+"', sizingMethod='scale')";}},onImageError:function(){var img=this.imgDiv;if(img.src!=null){this.imageReloadAttempts++;if(this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){this.setImgSrc(this.layer.getURL(this.bounds));}else{OpenLayers.Element.addClass(img,"olImageLoadError");this.events.triggerEvent("loaderror");this.onImageLoad();}}},stopLoading:function(){OpenLayers.Event.stopObservingElement(this.imgDiv);window.clearTimeout(this._loadTimeout);delete this._loadTimeout;},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var canvas=document.createElement("canvas");canvas.width=this.size.w;canvas.height=this.size.h;this.canvasContext=canvas.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0);}
-return this.canvasContext;}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Tile.Image.IMAGE=(function(){var img=new Image();img.className="olTileImage";img.galleryImg="no";return img;}());OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:false,ratio:1.5,buffer:0,transitionEffect:"resize",numLoadingTiles:0,serverResolutions:null,loading:false,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null,className:null,gridLayout:null,rowSign:null,transitionendEvents:['transitionend','webkitTransitionEnd','otransitionend','oTransitionEnd'],initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this._removeBackBuffer=OpenLayers.Function.bind(this.removeBackBuffer,this);this.initProperties();this.rowSign=this.tileOriginCorner.substr(0,1)==="t"?1:-1;},initProperties:function(){if(this.options.removeBackBufferDelay===undefined){this.removeBackBufferDelay=this.singleTile?0:2500;}
-if(this.options.className===undefined){this.className=this.singleTile?'olLayerGridSingleTile':'olLayerGrid';}},setMap:function(map){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this,map);OpenLayers.Element.addClass(this.div,this.className);},removeMap:function(map){this.removeBackBuffer();},destroy:function(){this.removeBackBuffer();this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){if(this.grid){for(var iRow=0,len=this.grid.length;iRow<len;iRow++){var row=this.grid[iRow];for(var iCol=0,clen=row.length;iCol<clen;iCol++){var tile=row[iCol];this.destroyTile(tile);}}
-this.grid=[];this.gridResolution=null;this.gridLayout=null;}},addOptions:function(newOptions,reinitialize){var singleTileChanged=newOptions.singleTile!==undefined&&newOptions.singleTile!==this.singleTile;OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this,arguments);if(this.map&&singleTileChanged){this.initProperties();this.clearGrid();this.tileSize=this.options.tileSize;this.setTileSize();this.moveTo(null,true);}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.getOptions());}
-obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
-obj.grid=[];obj.gridResolution=null;obj.backBuffer=null;obj.backBufferTimerId=null;obj.loading=false;obj.numLoadingTiles=0;return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();var resolution=this.map.getResolution();var serverResolution=this.getServerResolution(resolution);if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){if(zoomChanged&&this.transitionEffect!=='resize'){this.removeBackBuffer();}
-if(!zoomChanged||this.transitionEffect==='resize'){this.applyBackBuffer(resolution);}
-this.initSingleTile(bounds);}}else{forceReTile=forceReTile||!tilesBounds.intersectsBounds(bounds,{worldBounds:this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent()});if(forceReTile){if(zoomChanged&&(this.transitionEffect==='resize'||this.gridResolution===resolution)){this.applyBackBuffer(resolution);}
-this.initGriddedTiles(bounds);}else{this.moveGriddedTiles();}}}},getTileData:function(loc){var data=null,x=loc.lon,y=loc.lat,numRows=this.grid.length;if(this.map&&numRows){var res=this.map.getResolution(),tileWidth=this.tileSize.w,tileHeight=this.tileSize.h,bounds=this.grid[0][0].bounds,left=bounds.left,top=bounds.top;if(x<left){if(this.map.baseLayer.wrapDateLine){var worldWidth=this.map.getMaxExtent().getWidth();var worldsAway=Math.ceil((left-x)/worldWidth);x+=worldWidth*worldsAway;}}
-var dtx=(x-left)/(res*tileWidth);var dty=(top-y)/(res*tileHeight);var col=Math.floor(dtx);var row=Math.floor(dty);if(row>=0&&row<numRows){var tile=this.grid[row][col];if(tile){data={tile:tile,i:Math.floor((dtx-col)*tileWidth),j:Math.floor((dty-row)*tileHeight)};}}}
-return data;},destroyTile:function(tile){this.removeTileMonitoringHooks(tile);tile.destroy();},getServerResolution:function(resolution){var distance=Number.POSITIVE_INFINITY;resolution=resolution||this.map.getResolution();if(this.serverResolutions&&OpenLayers.Util.indexOf(this.serverResolutions,resolution)===-1){var i,newDistance,newResolution,serverResolution;for(i=this.serverResolutions.length-1;i>=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<lenI;i++){for(var j=0,lenJ=this.grid[i].length;j<lenJ;j++){var tile=this.grid[i][j],markup=this.grid[i][j].createBackBuffer();if(markup){markup._i=i;markup._j=j;markup._w=tile.size.w;markup._h=tile.size.h;markup.id=tile.id+'_bb';backBuffer.appendChild(markup);}}}}
-return backBuffer;},removeBackBuffer:function(){if(this._transitionElement){for(var i=this.transitionendEvents.length-1;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<minCols);rowidx+=1;}while((tileBounds.bottom>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows);this.removeExcessTiles(rowidx,colidx);var resolution=this.getServerResolution();this.gridResolution=resolution;tileData.sort(function(a,b){return a.distance-b.distance;});for(var i=0,ii=tileData.length;i<ii;++i){tileData[i].tile.draw();}},getMaxExtent:function(){return this.maxExtent;},addTile:function(bounds,position){var tile=new this.tileClass(this,position,bounds,null,this.tileSize,this.tileOptions);this.events.triggerEvent("addtile",{tile:tile});return tile;},addTileMonitoringHooks:function(tile){var replacingCls='olTileReplacing';tile.onLoadStart=function(){if(this.loading===false){this.loading=true;this.events.triggerEvent("loadstart");}
-this.events.triggerEvent("tileloadstart",{tile:tile});this.numLoadingTiles++;if(!this.singleTile&&this.backBuffer&&this.gridResolution===this.backBufferResolution){OpenLayers.Element.addClass(tile.getTile(),replacingCls);}};tile.onLoadEnd=function(evt){this.numLoadingTiles--;var aborted=evt.type==='unload';this.events.triggerEvent("tileloaded",{tile:tile,aborted:aborted});if(!this.singleTile&&!aborted&&this.backBuffer&&this.gridResolution===this.backBufferResolution){var tileDiv=tile.getTile();if(OpenLayers.Element.getStyle(tileDiv,'display')==='none'){var bufferTile=document.getElementById(tile.id+'_bb');if(bufferTile){bufferTile.parentNode.removeChild(bufferTile);}}
-OpenLayers.Element.removeClass(tileDiv,replacingCls);}
-if(this.numLoadingTiles===0){if(this.backBuffer){if(this.backBuffer.childNodes.length===0){this.removeBackBuffer();}else{this._transitionElement=aborted?this.div.lastChild:tile.imgDiv;var transitionendEvents=this.transitionendEvents;for(var i=transitionendEvents.length-1;i>=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;i<len;i++){var tile=row[i];var position=modelRow[i].position.clone();position.y+=tileSize.h*sign;tile.moveTo(this.getTileBoundsForGridIndex(rowIndex,i),position);}
-grid[prepend?'unshift':'push'](row);},shiftColumn:function(prepend,tileSize){var grid=this.grid;var colIndex=prepend?0:(grid[0].length-1);var sign=prepend?-1:1;var tileLayout=this.gridLayout;tileLayout.startcol+=sign;for(var i=0,len=grid.length;i<len;i++){var row=grid[i];var position=row[colIndex].position.clone();var tile=row[prepend?'pop':'shift']();position.x+=tileSize.w*sign;tile.moveTo(this.getTileBoundsForGridIndex(i,colIndex),position);row[prepend?'unshift':'push'](tile);}},removeExcessTiles:function(rows,columns){var i,l;while(this.grid.length>rows){var row=this.grid.pop();for(i=0,l=row.length;i<l;i++){var tile=row[i];this.destroyTile(tile);}}
-for(i=0,l=this.grid.length;i<l;i++){while(this.grid[i].length>columns){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.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,sphericalMercator:false,zoomOffset:0,serverResolutions:null,initialize:function(name,url,options){if(options&&options.sphericalMercator||this.sphericalMercator){options=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},options);}
-OpenLayers.Layer.Grid.prototype.initialize.apply(this,[name||this.name,url||this.url,{},options]);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions());}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){var xyz=this.getXYZ(bounds);var url=this.url;if(OpenLayers.Util.isArray(url)){var s=''+xyz.x+xyz.y+xyz.z;url=this.selectUrl(s,url);}
-return OpenLayers.String.format(url,xyz);},getXYZ:function(bounds){var res=this.getServerResolution();var x=Math.round((bounds.left-this.maxExtent.left)/(res*this.tileSize.w));var y=Math.round((this.maxExtent.top-bounds.top)/(res*this.tileSize.h));var z=this.getServerZoom();if(this.wrapDateLine){var limit=Math.pow(2,z);x=((x%limit)+limit)%limit;}
-return{'x':x,'y':y,'z':z};},setMap:function(map){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);if(!this.tileOrigin){this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.bottom);}},CLASS_NAME:"OpenLayers.Layer.XYZ"});OpenLayers.Layer.Bing=OpenLayers.Class(OpenLayers.Layer.XYZ,{key:null,serverResolutions:[156543.03390625,78271.516953125,39135.7584765625,19567.87923828125,9783.939619140625,4891.9698095703125,2445.9849047851562,1222.9924523925781,611.4962261962891,305.74811309814453,152.87405654907226,76.43702827453613,38.218514137268066,19.109257068634033,9.554628534317017,4.777314267158508,2.388657133579254,1.194328566789627,0.5971642833948135,0.29858214169740677,0.14929107084870338,0.07464553542435169],attributionTemplate:'<span class="olBingAttribution ${type}">'+'<div><a target="_blank" href="http://www.bing.com/maps/">'+'<img src="${logo}" /></a></div>${copyrights}'+'<a style="white-space: nowrap" target="_blank" '+'href="http://www.microsoft.com/maps/product/terms.html">'+'Terms of Use</a></span>',metadata:null,protocolRegex:/^http:/i,type:"Road",culture:"en-US",metadataParams:null,tileOptions:null,protocol:~window.location.href.indexOf('http')?'':'http:',initialize:function(options){options=OpenLayers.Util.applyDefaults({sphericalMercator:true},options);var name=options.name||"Bing "+(options.type||this.type);var newArgs=[name,null,options];OpenLayers.Layer.XYZ.prototype.initialize.apply(this,newArgs);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:'anonymous'},this.options.tileOptions);this.loadMetadata();},loadMetadata:function(){this._callbackId="_callback_"+this.id.replace(/\./g,"_");window[this._callbackId]=OpenLayers.Function.bind(OpenLayers.Layer.Bing.processMetadata,this);var params=OpenLayers.Util.applyDefaults({key:this.key,jsonp:this._callbackId,include:"ImageryProviders"},this.metadataParams);var url=this.protocol+"//dev.virtualearth.net/REST/v1/Imagery/Metadata/"+
-this.type+"?"+OpenLayers.Util.getParameterString(params);var script=document.createElement("script");script.type="text/javascript";script.src=url;script.id=this._callbackId;document.getElementsByTagName("head")[0].appendChild(script);},initLayer:function(){var res=this.metadata.resourceSets[0].resources[0];var url=res.imageUrl.replace("{quadkey}","${quadkey}");url=url.replace("{culture}",this.culture);url=url.replace(this.protocolRegex,this.protocol);this.url=[];for(var i=0;i<res.imageUrlSubdomains.length;++i){this.url.push(url.replace("{subdomain}",res.imageUrlSubdomains[i]));}
-this.addOptions({maxResolution:Math.min(this.serverResolutions[res.zoomMin],this.maxResolution||Number.POSITIVE_INFINITY),numZoomLevels:Math.min(res.zoomMax+1-res.zoomMin,this.numZoomLevels)},true);if(!this.isBaseLayer){this.redraw();}
-this.updateAttribution();},getURL:function(bounds){if(!this.url){return;}
-var xyz=this.getXYZ(bounds),x=xyz.x,y=xyz.y,z=xyz.z;var quadDigits=[];for(var i=z;i>0;--i){var digit='0';var mask=1<<(i-1);if((x&mask)!=0){digit++;}
-if((y&mask)!=0){digit++;digit++;}
-quadDigits.push(digit);}
-var quadKey=quadDigits.join("");var url=this.selectUrl(''+x+y+z,this.url);return OpenLayers.String.format(url,{'quadkey':quadKey});},updateAttribution:function(){var metadata=this.metadata;if(!metadata.resourceSets||!this.map||!this.map.center){return;}
-var res=metadata.resourceSets[0].resources[0];var extent=this.map.getExtent().transform(this.map.getProjectionObject(),new OpenLayers.Projection("EPSG:4326"));var providers=res.imageryProviders||[],zoom=OpenLayers.Util.indexOf(this.serverResolutions,this.getServerResolution()),copyrights="",provider,i,ii,j,jj,bbox,coverage;for(i=0,ii=providers.length;i<ii;++i){provider=providers[i];for(j=0,jj=provider.coverageAreas.length;j<jj;++j){coverage=provider.coverageAreas[j];bbox=OpenLayers.Bounds.fromArray(coverage.bbox,true);if(extent.intersectsBounds(bbox)&&zoom<=coverage.zoomMax&&zoom>=coverage.zoomMin){copyrights+=provider.attribution+" ";}}}
-var logo=metadata.brandLogoUri.replace(this.protocolRegex,this.protocol);this.attribution=OpenLayers.String.format(this.attributionTemplate,{type:this.type.toLowerCase(),logo:logo,copyrights:copyrights});this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"attribution"});},setMap:function(){OpenLayers.Layer.XYZ.prototype.setMap.apply(this,arguments);this.map.events.register("moveend",this,this.updateAttribution);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Bing(this.options);}
-obj=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[obj]);return obj;},destroy:function(){this.map&&this.map.events.unregister("moveend",this,this.updateAttribution);OpenLayers.Layer.XYZ.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.Bing"});OpenLayers.Layer.Bing.processMetadata=function(metadata){this.metadata=metadata;this.initLayer();var script=document.getElementById(this._callbackId);script.parentNode.removeChild(script);window[this._callbackId]=undefined;delete this._callbackId;};OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],split:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,sourceLine,sourceLines,sourceSplit,targetSplit;var sourceParts=[];var targetParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){sourceLine=this.components[i];sourceSplit=false;for(var j=0;j<targetParts.length;++j){splits=sourceLine.split(targetParts[j],options);if(splits){if(mutual){sourceLines=splits[0];for(var k=0,klen=sourceLines.length;k<klen;++k){if(k===0&&sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLines[k]);}else{sourceParts.push(new OpenLayers.Geometry.MultiLineString([sourceLines[k]]));}}
-sourceSplit=true;splits=splits[1];}
-if(splits.length){splits.unshift(j,1);Array.prototype.splice.apply(targetParts,splits);break;}}}
-if(!sourceSplit){if(sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLine.clone());}else{sourceParts=[new OpenLayers.Geometry.MultiLineString(sourceLine.clone())];}}}
-if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
-if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
-if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
-return results;},splitWith:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,targetLine,sourceLines,sourceSplit,targetSplit,sourceParts,targetParts;if(geometry instanceof OpenLayers.Geometry.LineString){targetParts=[];sourceParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){targetSplit=false;targetLine=this.components[i];for(var j=0;j<sourceParts.length;++j){splits=sourceParts[j].split(targetLine,options);if(splits){if(mutual){sourceLines=splits[0];if(sourceLines.length){sourceLines.unshift(j,1);Array.prototype.splice.apply(sourceParts,sourceLines);j+=sourceLines.length-2;}
-splits=splits[1];if(splits.length===0){splits=[targetLine.clone()];}}
-for(var k=0,klen=splits.length;k<klen;++k){if(k===0&&targetParts.length){targetParts[targetParts.length-1].addComponent(splits[k]);}else{targetParts.push(new OpenLayers.Geometry.MultiLineString([splits[k]]));}}
-targetSplit=true;}}
-if(!targetSplit){if(targetParts.length){targetParts[targetParts.length-1].addComponent(targetLine.clone());}else{targetParts=[new OpenLayers.Geometry.MultiLineString([targetLine.clone()])];}}}}else{results=geometry.split(this);}
-if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
-if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
-if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
-return results;},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});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.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;i<this.level;++i){pieces.push(this.indent);}}
-return pieces.join('');},writeNewline:function(){return(this.pretty)?this.newline:'';},writeSpace:function(){return(this.pretty)?this.space:'';},serialize:{'object':function(object){if(object==null){return"null";}
-if(object.constructor==Date){return this.serialize.date.apply(this,[object]);}
-if(object.constructor==Array){return this.serialize.array.apply(this,[object]);}
-var pieces=['{'];this.level+=1;var key,keyJSON,valueJSON;var addComma=false;for(key in object){if(object.hasOwnProperty(key)){keyJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[key,this.pretty]);valueJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[object[key],this.pretty]);if(keyJSON!=null&&valueJSON!=null){if(addComma){pieces.push(',');}
-pieces.push(this.writeNewline(),this.writeIndent(),keyJSON,':',this.writeSpace(),valueJSON);addComma=true;}}}
-this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),'}');return pieces.join('');},'array':function(array){var json;var pieces=['['];this.level+=1;for(var i=0,len=array.length;i<len;++i){json=OpenLayers.Format.JSON.prototype.write.apply(this,[array[i],this.pretty]);if(json!=null){if(i>0){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.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;i<len;++i){potentialNode=allNodes[i];fullName=(potentialNode.prefix)?(potentialNode.prefix+":"+name):name;if((name=="*")||(fullName==potentialNode.nodeName)){if((uri=="*")||(uri==potentialNode.namespaceURI)){elements.push(potentialNode);}}}}
-return elements;},getAttributeNodeNS:function(node,uri,name){var attributeNode=null;if(node.getAttributeNodeNS){attributeNode=node.getAttributeNodeNS(uri,name);}else{var attributes=node.attributes;var potentialNode,fullName;for(var i=0,len=attributes.length;i<len;++i){potentialNode=attributes[i];if(potentialNode.namespaceURI==uri){fullName=(potentialNode.prefix)?(potentialNode.prefix+":"+name):name;if(fullName==potentialNode.nodeName){attributeNode=potentialNode;break;}}}}
-return attributeNode;},getAttributeNS:function(node,uri,name){var attributeValue="";if(node.getAttributeNS){attributeValue=node.getAttributeNS(uri,name)||"";}else{var attributeNode=this.getAttributeNodeNS(node,uri,name);if(attributeNode){attributeValue=attributeNode.nodeValue;}}
-return attributeValue;},getChildValue:function(node,def){var value=def||"";if(node){for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 3:case 4:value+=child.nodeValue;}}}
-return value;},isSimpleContent:function(node){var simple=true;for(var child=node.firstChild;child;child=child.nextSibling){if(child.nodeType===1){simple=false;break;}}
-return simple;},contentType:function(node){var simple=false,complex=false;var type=OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 1:complex=true;break;case 8:break;default:simple=true;}
-if(complex&&simple){break;}}
-if(complex&&simple){type=OpenLayers.Format.XML.CONTENT_TYPE.MIXED;}else if(complex){return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;}else if(simple){return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;}
-return type;},hasAttributeNS:function(node,uri,name){var found=false;if(node.hasAttributeNS){found=node.hasAttributeNS(uri,name);}else{found=!!this.getAttributeNodeNS(node,uri,name);}
-return found;},setAttributeNS:function(node,uri,name,value){if(node.setAttributeNS){node.setAttributeNS(uri,name,value);}else{if(this.xmldom){if(uri){var attribute=node.ownerDocument.createNode(2,name,uri);attribute.nodeValue=value;node.setAttributeNode(attribute);}else{node.setAttribute(name,value);}}else{throw"setAttributeNS not implemented";}}},createElementNSPlus:function(name,options){options=options||{};var uri=options.uri||this.namespaces[options.prefix];if(!uri){var loc=name.indexOf(":");uri=this.namespaces[name.substring(0,loc)];}
-if(!uri){uri=this.namespaces[this.defaultPrefix];}
-var node=this.createElementNS(uri,name);if(options.attributes){this.setAttributes(node,options.attributes);}
-var value=options.value;if(value!=null){node.appendChild(this.createTextNode(value));}
-return node;},setAttributes:function(node,obj){var value,uri;for(var name in obj){if(obj[name]!=null&&obj[name].toString){value=obj[name].toString();uri=this.namespaces[name.substring(0,name.indexOf(":"))]||null;this.setAttributeNS(node,uri,name,value);}}},readNode:function(node,obj){if(!obj){obj={};}
-var group=this.readers[node.namespaceURI?this.namespaceAlias[node.namespaceURI]:this.defaultPrefix];if(group){var local=node.localName||node.nodeName.split(":").pop();var reader=group[local]||group["*"];if(reader){reader.apply(this,[node,obj]);}}
-return obj;},readChildNodes:function(node,obj){if(!obj){obj={};}
-var children=node.childNodes;var child;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){this.readNode(child,obj);}}
-return obj;},writeNode:function(name,obj,parent){var prefix,local;var split=name.indexOf(":");if(split>0){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<len;++i){attr=node.attributes[i];if(attr.prefix==="xmlns"&&attr.name==="xmlns:"+prefix){uri=attr.value||null;break outer;}else if(attr.name==="xmlns"&&prefix===null){uri=attr.value||null;break outer;}}}
-uri=this.lookupNamespaceURI(node.parentNode,prefix);break outer;case 2:uri=this.lookupNamespaceURI(node.ownerElement,prefix);break outer;case 9:uri=this.lookupNamespaceURI(node.documentElement,prefix);break outer;case 6:case 12:case 10:case 11:break outer;default:uri=this.lookupNamespaceURI(node.parentNode,prefix);break outer;}}}
-return uri;},getXMLDoc:function(){if(!OpenLayers.Format.XML.document&&!this.xmldom){if(document.implementation&&document.implementation.createDocument){OpenLayers.Format.XML.document=document.implementation.createDocument("","",null);}else if(!this.xmldom&&window.ActiveXObject){this.xmldom=new ActiveXObject("Microsoft.XMLDOM");}}
-return OpenLayers.Format.XML.document||this.xmldom;},CLASS_NAME:"OpenLayers.Format.XML"});OpenLayers.Format.XML.CONTENT_TYPE={EMPTY:0,SIMPLE:1,COMPLEX:2,MIXED:3};OpenLayers.Format.XML.lookupNamespaceURI=OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI,OpenLayers.Format.XML.prototype);OpenLayers.Format.XML.document=null;OpenLayers.Format.OGCExceptionReport=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc"},regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)},defaultPrefix:"ogc",read:function(data){var result;if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-var root=data.documentElement;var exceptionInfo={exceptionReport:null};if(root){this.readChildNodes(data,exceptionInfo);if(exceptionInfo.exceptionReport===null){exceptionInfo=new OpenLayers.Format.OWSCommon().read(data);}}
-return exceptionInfo;},readers:{"ogc":{"ServiceExceptionReport":function(node,obj){obj.exceptionReport={exceptions:[]};this.readChildNodes(node,obj.exceptionReport);},"ServiceException":function(node,exceptionReport){var exception={code:node.getAttribute("code"),locator:node.getAttribute("locator"),text:this.getChildValue(node)};exceptionReport.exceptions.push(exception);}}},CLASS_NAME:"OpenLayers.Format.OGCExceptionReport"});OpenLayers.Format.XML.VersionedOGC=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:null,version:null,profile:null,allowFallback:false,name:null,stringifyOutput:false,parser:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);var className=this.CLASS_NAME;this.name=className.substring(className.lastIndexOf(".")+1);},getVersion:function(root,options){var version;if(root){version=this.version;if(!version){version=root.getAttribute("version");if(!version){version=this.defaultVersion;}}}else{version=(options&&options.version)||this.version||this.defaultVersion;}
-return version;},getParser:function(version){version=version||this.defaultVersion;var profile=this.profile?"_"+this.profile:"";if(!this.parser||this.parser.VERSION!=version){var format=OpenLayers.Format[this.name]["v"+version.replace(/\./g,"_")+profile];if(!format){if(profile!==""&&this.allowFallback){profile="";format=OpenLayers.Format[this.name]["v"+version.replace(/\./g,"_")];}
-if(!format){throw"Can't find a "+this.name+" parser for version "+
-version+profile;}}
-this.parser=new format(this.options);}
-return this.parser;},write:function(obj,options){var version=this.getVersion(null,options);this.parser=this.getParser(version);var root=this.parser.write(obj,options);if(this.stringifyOutput===false){return root;}else{return OpenLayers.Format.XML.prototype.write.apply(this,[root]);}},read:function(data,options){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-var root=data.documentElement;var version=this.getVersion(root);this.parser=this.getParser(version);var obj=this.parser.read(data,options);var errorProperty=this.parser.errorProperty||null;if(errorProperty!==null&&obj[errorProperty]===undefined){var format=new OpenLayers.Format.OGCExceptionReport();obj.error=format.read(data);}
-obj.version=version;return obj;},CLASS_NAME:"OpenLayers.Format.XML.VersionedOGC"});OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:null,popup:null,initialize:function(layer,lonlat,data){this.layer=layer;this.lonlat=lonlat;this.data=(data!=null)?data:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if((this.layer!=null)&&(this.layer.map!=null)){if(this.popup!=null){this.layer.map.removePopup(this.popup);}}
-if(this.layer!=null&&this.marker!=null){this.layer.removeMarker(this.marker);}
-this.layer=null;this.id=null;this.lonlat=null;this.data=null;if(this.marker!=null){this.destroyMarker(this.marker);this.marker=null;}
-if(this.popup!=null){this.destroyPopup(this.popup);this.popup=null;}},onScreen:function(){var onScreen=false;if((this.layer!=null)&&(this.layer.map!=null)){var screenBounds=this.layer.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
-return onScreen;},createMarker:function(){if(this.lonlat!=null){this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon);}
-return this.marker;},destroyMarker:function(){this.marker.destroy();},createPopup:function(closeBox){if(this.lonlat!=null){if(!this.popup){var anchor=(this.marker)?this.marker.icon:null;var popupClass=this.popupClass?this.popupClass:OpenLayers.Popup.Anchored;this.popup=new popupClass(this.id+"_popup",this.lonlat,this.data.popupSize,this.data.popupContentHTML,anchor,closeBox);}
-if(this.data.overflow!=null){this.popup.contentDiv.style.overflow=this.data.overflow;}
-this.popup.feature=this;}
-return this.popup;},destroyPopup:function(){if(this.popup){this.popup.feature=null;this.popup.destroy();this.popup=null;}},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.State={UNKNOWN:'Unknown',INSERT:'Insert',UPDATE:'Update',DELETE:'Delete'};OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",modified:null,initialize:function(geometry,attributes,style){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,attributes]);this.lonlat=null;this.geometry=geometry?geometry:null;this.state=null;this.attributes={};if(attributes){this.attributes=OpenLayers.Util.extend(this.attributes,attributes);}
-this.style=style?style:null;},destroy:function(){if(this.layer){this.layer.removeFeatures(this);this.layer=null;}
-this.geometry=null;this.modified=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments);},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style);},onScreen:function(boundsOnly){var onScreen=false;if(this.layer&&this.layer.map){var screenBounds=this.layer.map.getExtent();if(boundsOnly){var featureBounds=this.geometry.getBounds();onScreen=screenBounds.intersectsBounds(featureBounds);}else{var screenPoly=screenBounds.toGeometry();onScreen=screenPoly.intersects(this.geometry);}}
-return onScreen;},getVisibility:function(){return!(this.style&&this.style.display=='none'||!this.layer||this.layer&&this.layer.styleMap&&this.layer.styleMap.createSymbolizer(this,this.renderIntent).display=='none'||this.layer&&!this.layer.getVisibility());},createMarker:function(){return null;},destroyMarker:function(){},createPopup:function(){return null;},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;if(this.geometry){atPoint=this.geometry.atPoint(lonlat,toleranceLon,toleranceLat);}
-return atPoint;},destroyPopup:function(){},move:function(location){if(!this.layer||!this.geometry.move){return undefined;}
-var pixel;if(location.CLASS_NAME=="OpenLayers.LonLat"){pixel=this.layer.getViewPortPxFromLonLat(location);}else{pixel=location;}
-var lastPixel=this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());var res=this.layer.map.getResolution();this.geometry.move(res*(pixel.x-lastPixel.x),res*(lastPixel.y-pixel.y));this.layer.drawFeature(this);return lastPixel;},toState:function(state){if(state==OpenLayers.State.UPDATE){switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=state;break;case OpenLayers.State.UPDATE:case OpenLayers.State.INSERT:break;}}else if(state==OpenLayers.State.INSERT){switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=state;break;}}else if(state==OpenLayers.State.DELETE){switch(this.state){case OpenLayers.State.INSERT:break;case OpenLayers.State.DELETE:break;case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state=state;break;}}else if(state==OpenLayers.State.UNKNOWN){this.state=state;}},CLASS_NAME:"OpenLayers.Feature.Vector"});OpenLayers.Feature.Vector.style={'default':{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},'select':{fillColor:"blue",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},'temporary':{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1,strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},'delete':{display:"none"}};OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:false,propertyStyles:null,initialize:function(style,options){OpenLayers.Util.extend(this,options);this.rules=[];if(options&&options.rules){this.addRules(options.rules);}
-this.setDefaultStyle(style||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i=0,len=this.rules.length;i<len;i++){this.rules[i].destroy();this.rules[i]=null;}
-this.rules=null;this.defaultStyle=null;},createSymbolizer:function(feature){var style=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),feature);var rules=this.rules;var rule,context;var elseRules=[];var appliedRules=false;for(var i=0,len=rules.length;i<len;i++){rule=rules[i];var applies=rule.evaluate(feature);if(applies){if(rule instanceof OpenLayers.Rule&&rule.elseFilter){elseRules.push(rule);}else{appliedRules=true;this.applySymbolizer(rule,style,feature);}}}
-if(appliedRules==false&&elseRules.length>0){appliedRules=true;for(var i=0,len=elseRules.length;i<len;i++){this.applySymbolizer(elseRules[i],style,feature);}}
-if(rules.length>0&&appliedRules==false){style.display="none";}
-if(style.label!=null&&typeof style.label!=="string"){style.label=String(style.label);}
-return style;},applySymbolizer:function(rule,style,feature){var symbolizerPrefix=feature.geometry?this.getSymbolizerPrefix(feature.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];var symbolizer=rule.symbolizer[symbolizerPrefix]||rule.symbolizer;if(this.defaultsPerSymbolizer===true){var defaults=this.defaultStyle;OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:defaults.pointRadius});if(symbolizer.stroke===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{strokeWidth:defaults.strokeWidth,strokeColor:defaults.strokeColor,strokeOpacity:defaults.strokeOpacity,strokeDashstyle:defaults.strokeDashstyle,strokeLinecap:defaults.strokeLinecap});}
-if(symbolizer.fill===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{fillColor:defaults.fillColor,fillOpacity:defaults.fillOpacity});}
-if(symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset});}}
-return this.createLiterals(OpenLayers.Util.extend(style,symbolizer),feature);},createLiterals:function(style,feature){var context=OpenLayers.Util.extend({},feature.attributes||feature.data);OpenLayers.Util.extend(context,this.context);for(var i in this.propertyStyles){style[i]=OpenLayers.Style.createLiteral(style[i],context,feature,i);}
-return style;},findPropertyStyles:function(){var propertyStyles={};var style=this.defaultStyle;this.addPropertyStyles(propertyStyles,style);var rules=this.rules;var symbolizer,value;for(var i=0,len=rules.length;i<len;i++){symbolizer=rules[i].symbolizer;for(var key in symbolizer){value=symbolizer[key];if(typeof value=="object"){this.addPropertyStyles(propertyStyles,value);}else{this.addPropertyStyles(propertyStyles,symbolizer);break;}}}
-return propertyStyles;},addPropertyStyles:function(propertyStyles,symbolizer){var property;for(var key in symbolizer){property=symbolizer[key];if(typeof property=="string"&&property.match(/\$\{\w+\}/)){propertyStyles[key]=true;}}
-return propertyStyles;},addRules:function(rules){Array.prototype.push.apply(this.rules,rules);this.propertyStyles=this.findPropertyStyles();},setDefaultStyle:function(style){this.defaultStyle=style;this.propertyStyles=this.findPropertyStyles();},getSymbolizerPrefix:function(geometry){var prefixes=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var i=0,len=prefixes.length;i<len;i++){if(geometry.CLASS_NAME.indexOf(prefixes[i])!=-1){return prefixes[i];}}},clone:function(){var options=OpenLayers.Util.extend({},this);if(this.rules){options.rules=[];for(var i=0,len=this.rules.length;i<len;++i){options.rules.push(this.rules[i].clone());}}
-options.context=this.context&&OpenLayers.Util.extend({},this.context);var defaultStyle=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(defaultStyle,options);},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(value,context,feature,property){if(typeof value=="string"&&value.indexOf("${")!=-1){value=OpenLayers.String.format(value,context,[feature,property]);value=(isNaN(value)||!value)?value:parseFloat(value);}
-return value;};OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon','Text','Raster'];OpenLayers.Filter=OpenLayers.Class({initialize:function(options){OpenLayers.Util.extend(this,options);},destroy:function(){},evaluate:function(context){return true;},clone:function(){return null;},toString:function(){var string;if(OpenLayers.Format&&OpenLayers.Format.CQL){string=OpenLayers.Format.CQL.prototype.write(this);}else{string=Object.prototype.toString.call(this);}
-return string;},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Filter.FeatureId=OpenLayers.Class(OpenLayers.Filter,{fids:null,type:"FID",initialize:function(options){this.fids=[];OpenLayers.Filter.prototype.initialize.apply(this,[options]);},evaluate:function(feature){for(var i=0,len=this.fids.length;i<len;i++){var fid=feature.fid||feature.id;if(fid==this.fids[i]){return true;}}
-return false;},clone:function(){var filter=new OpenLayers.Filter.FeatureId();OpenLayers.Util.extend(filter,this);filter.fids=this.fids.slice();return filter;},CLASS_NAME:"OpenLayers.Filter.FeatureId"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(options){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[options]);},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this);},evaluate:function(context){var i,len;switch(this.type){case OpenLayers.Filter.Logical.AND:for(i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==false){return false;}}
-return true;case OpenLayers.Filter.Logical.OR:for(i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==true){return true;}}
-return false;case OpenLayers.Filter.Logical.NOT:return(!this.filters[0].evaluate(context));}
-return undefined;},clone:function(){var filters=[];for(var i=0,len=this.filters.length;i<len;++i){filters.push(this.filters[i].clone());}
-return new OpenLayers.Filter.Logical({type:this.type,filters:filters});},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:true,lowerBoundary:null,upperBoundary:null,initialize:function(options){OpenLayers.Filter.prototype.initialize.apply(this,[options]);if(this.type===OpenLayers.Filter.Comparison.LIKE&&options.matchCase===undefined){this.matchCase=null;}},evaluate:function(context){if(context instanceof OpenLayers.Feature.Vector){context=context.attributes;}
-var result=false;var got=context[this.property];var exp;switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()==exp.toUpperCase());}else{result=(got==exp);}
-break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()!=exp.toUpperCase());}else{result=(got!=exp);}
-break;case OpenLayers.Filter.Comparison.LESS_THAN:result=got<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:result=got>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:result=got<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:result=got>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:result=(got>=this.lowerBoundary)&&(got<=this.upperBoundary);break;case OpenLayers.Filter.Comparison.LIKE:var regexp=new RegExp(this.value,"gi");result=regexp.test(got);break;case OpenLayers.Filter.Comparison.IS_NULL:result=(got===null);break;}
-return result;},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){throw new Error("'.' is an unsupported wildCard character for "+"OpenLayers.Filter.Comparison");}
-wildCard=wildCard?wildCard:"*";singleChar=singleChar?singleChar:".";escapeChar=escapeChar?escapeChar:"!";this.value=this.value.replace(new RegExp("\\"+escapeChar+"(.|$)","g"),"\\$1");this.value=this.value.replace(new RegExp("\\"+singleChar,"g"),".");this.value=this.value.replace(new RegExp("\\"+wildCard,"g"),".*");this.value=this.value.replace(new RegExp("\\\\.\\*","g"),"\\"+wildCard);this.value=this.value.replace(new RegExp("\\\\\\.","g"),"\\"+singleChar);return this.value;},regex2value:function(){var value=this.value;value=value.replace(/!/g,"!!");value=value.replace(/(\\)?\\\./g,function($0,$1){return $1?$0:"!.";});value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"!*";});value=value.replace(/\\\\/g,"\\");value=value.replace(/\.\*/g,"*");return value;},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(),this);},CLASS_NAME:"OpenLayers.Filter.Comparison"});OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Filter.Comparison.IS_NULL="NULL";OpenLayers.Format.Filter=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Format.WFST=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Format.WFST.DEFAULTS);var cls=OpenLayers.Format.WFST["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported WFST version: "+options.version;}
-return new cls(options);};OpenLayers.Format.WFST.DEFAULTS={"version":"1.0.0"};OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,evaluate:function(feature){var intersect=false;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(feature.geometry){var geom=this.value;if(this.value.CLASS_NAME=="OpenLayers.Bounds"){geom=this.value.toGeometry();}
-if(feature.geometry.intersects(geom)){intersect=true;}}
-break;default:throw new Error('evaluate is not implemented for this filter type.');}
-return intersect;},clone:function(){var options=OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(options);},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Format.WFST.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs",gml:"http://www.opengis.net/gml",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows"},defaultPrefix:"wfs",version:null,schemaLocations:null,srsName:null,extractAttributes:true,xy:true,stateName:null,initialize:function(options){this.stateName={};this.stateName[OpenLayers.State.INSERT]="wfs:Insert";this.stateName[OpenLayers.State.UPDATE]="wfs:Update";this.stateName[OpenLayers.State.DELETE]="wfs:Delete";OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},getSrsName:function(feature,options){var srsName=options&&options.srsName;if(!srsName){if(feature&&feature.layer){srsName=feature.layer.projection.getCode();}else{srsName=this.srsName;}}
-return srsName;},read:function(data,options){options=options||{};OpenLayers.Util.applyDefaults(options,{output:"features"});if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-if(data&&data.nodeType==9){data=data.documentElement;}
-var obj={};if(data){this.readNode(data,obj,true);}
-if(obj.features&&options.output==="features"){obj=obj.features;}
-return obj;},readers:{"wfs":{"FeatureCollection":function(node,obj){obj.features=[];this.readChildNodes(node,obj);}}},write:function(features,options){var node=this.writeNode("wfs:Transaction",{features:features,options:options});var value=this.schemaLocationAttr();if(value){this.setAttributeNS(node,this.namespaces["xsi"],"xsi:schemaLocation",value);}
-return OpenLayers.Format.XML.prototype.write.apply(this,[node]);},writers:{"wfs":{"GetFeature":function(options){var node=this.createElementNSPlus("wfs:GetFeature",{attributes:{service:"WFS",version:this.version,handle:options&&options.handle,outputFormat:options&&options.outputFormat,maxFeatures:options&&options.maxFeatures,"xsi:schemaLocation":this.schemaLocationAttr(options)}});if(typeof this.featureType=="string"){this.writeNode("Query",options,node);}else{for(var i=0,len=this.featureType.length;i<len;i++){options.featureType=this.featureType[i];this.writeNode("Query",options,node);}}
-return node;},"Transaction":function(obj){obj=obj||{};var options=obj.options||{};var node=this.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version,handle:options.handle}});var i,len;var features=obj.features;if(features){if(options.multi===true){OpenLayers.Util.extend(this.geometryTypes,{"OpenLayers.Geometry.Point":"MultiPoint","OpenLayers.Geometry.LineString":(this.multiCurve===true)?"MultiCurve":"MultiLineString","OpenLayers.Geometry.Polygon":(this.multiSurface===true)?"MultiSurface":"MultiPolygon"});}
-var name,feature;for(i=0,len=features.length;i<len;++i){feature=features[i];name=this.stateName[feature.state];if(name){this.writeNode(name,{feature:feature,options:options},node);}}
-if(options.multi===true){this.setGeometryTypes();}}
-if(options.nativeElements){for(i=0,len=options.nativeElements.length;i<len;++i){this.writeNode("wfs:Native",options.nativeElements[i],node);}}
-return node;},"Native":function(nativeElement){var node=this.createElementNSPlus("wfs:Native",{attributes:{vendorId:nativeElement.vendorId,safeToIgnore:nativeElement.safeToIgnore},value:nativeElement.value});return node;},"Insert":function(obj){var feature=obj.feature;var options=obj.options;var node=this.createElementNSPlus("wfs:Insert",{attributes:{handle:options&&options.handle}});this.srsName=this.getSrsName(feature);this.writeNode("feature:_typeName",feature,node);return node;},"Update":function(obj){var feature=obj.feature;var options=obj.options;var node=this.createElementNSPlus("wfs:Update",{attributes:{handle:options&&options.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+
-this.featureType}});if(this.featureNS){node.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);}
-var modified=feature.modified;if(this.geometryName!==null&&(!modified||modified.geometry!==undefined)){this.srsName=this.getSrsName(feature);this.writeNode("Property",{name:this.geometryName,value:feature.geometry},node);}
-for(var key in feature.attributes){if(feature.attributes[key]!==undefined&&(!modified||!modified.attributes||(modified.attributes&&modified.attributes[key]!==undefined))){this.writeNode("Property",{name:key,value:feature.attributes[key]},node);}}
-this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[feature.fid]}),node);return node;},"Property":function(obj){var node=this.createElementNSPlus("wfs:Property");this.writeNode("Name",obj.name,node);if(obj.value!==null){this.writeNode("Value",obj.value,node);}
-return node;},"Name":function(name){return this.createElementNSPlus("wfs:Name",{value:name});},"Value":function(obj){var node;if(obj instanceof OpenLayers.Geometry){node=this.createElementNSPlus("wfs:Value");var geom=this.writeNode("feature:_geometry",obj).firstChild;node.appendChild(geom);}else{node=this.createElementNSPlus("wfs:Value",{value:obj});}
-return node;},"Delete":function(obj){var feature=obj.feature;var options=obj.options;var node=this.createElementNSPlus("wfs:Delete",{attributes:{handle:options&&options.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+
-this.featureType}});if(this.featureNS){node.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);}
-this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[feature.fid]}),node);return node;}}},schemaLocationAttr:function(options){options=OpenLayers.Util.extend({featurePrefix:this.featurePrefix,schema:this.schema},options);var schemaLocations=OpenLayers.Util.extend({},this.schemaLocations);if(options.schema){schemaLocations[options.featurePrefix]=options.schema;}
-var parts=[];var uri;for(var key in schemaLocations){uri=this.namespaces[key];if(uri){parts.push(uri+" "+schemaLocations[key]);}}
-var value=parts.join(" ")||undefined;return value;},setFilterProperty:function(filter){if(filter.filters){for(var i=0,len=filter.filters.length;i<len;++i){OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this,filter.filters[i]);}}else{if(filter instanceof OpenLayers.Filter.Spatial&&!filter.property){filter.property=this.geometryName;}}},CLASS_NAME:"OpenLayers.Format.WFST.v1"});OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Format.GML=OpenLayers.Class(OpenLayers.Format.XML,{featureNS:"http://mapserver.gis.umn.edu/mapserver",featurePrefix:"feature",featureName:"featureMember",layerName:"features",geometryName:"geometry",collectionName:"FeatureCollection",gmlns:"http://www.opengis.net/gml",extractAttributes:true,xy:true,initialize:function(options){this.regExes={trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g)};OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-var featureNodes=this.getElementsByTagNameNS(data.documentElement,this.gmlns,this.featureName);var features=[];for(var i=0;i<featureNodes.length;i++){var feature=this.parseFeature(featureNodes[i]);if(feature){features.push(feature);}}
-return features;},parseFeature:function(node){var order=["MultiPolygon","Polygon","MultiLineString","LineString","MultiPoint","Point","Envelope"];var type,nodeList,geometry,parser;for(var i=0;i<order.length;++i){type=order[i];nodeList=this.getElementsByTagNameNS(node,this.gmlns,type);if(nodeList.length>0){parser=this.parseGeometry[type.toLowerCase()];if(parser){geometry=parser.apply(this,[nodeList[0]]);if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}}else{throw new TypeError("Unsupported geometry type: "+type);}
-break;}}
-var bounds;var boxNodes=this.getElementsByTagNameNS(node,this.gmlns,"Box");for(i=0;i<boxNodes.length;++i){var boxNode=boxNodes[i];var box=this.parseGeometry["box"].apply(this,[boxNode]);var parentNode=boxNode.parentNode;var parentName=parentNode.localName||parentNode.nodeName.split(":").pop();if(parentName==="boundedBy"){bounds=box;}else{geometry=box.toGeometry();}}
-var attributes;if(this.extractAttributes){attributes=this.parseAttributes(node);}
-var feature=new OpenLayers.Feature.Vector(geometry,attributes);feature.bounds=bounds;feature.gml={featureType:node.firstChild.nodeName.split(":")[1],featureNS:node.firstChild.namespaceURI,featureNSPrefix:node.firstChild.prefix};var childNode=node.firstChild;var fid;while(childNode){if(childNode.nodeType==1){fid=childNode.getAttribute("fid")||childNode.getAttribute("id");if(fid){break;}}
-childNode=childNode.nextSibling;}
-feature.fid=fid;return feature;},parseGeometry:{point:function(node){var nodeList,coordString;var coords=[];var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"pos");if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);}
-if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.removeSpace,"");coords=coordString.split(",");}}
-if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coord");if(nodeList.length>0){var xList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"X");var yList=this.getElementsByTagNameNS(nodeList[0],this.gmlns,"Y");if(xList.length>0&&yList.length>0){coords=[xList[0].firstChild.nodeValue,yList[0].firstChild.nodeValue];}}}
-if(coords.length==2){coords[2]=null;}
-if(this.xy){return new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}
-else{return new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}},multipoint:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"Point");var components=[];if(nodeList.length>0){var point;for(var i=0;i<nodeList.length;++i){point=this.parseGeometry.point.apply(this,[nodeList[i]]);if(point){components.push(point);}}}
-return new OpenLayers.Geometry.MultiPoint(components);},linestring:function(node,ring){var nodeList,coordString;var coords=[];var points=[];nodeList=this.getElementsByTagNameNS(node,this.gmlns,"posList");if(nodeList.length>0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);var dim=parseInt(nodeList[0].getAttribute("dimension"));var j,x,y,z;for(var i=0;i<coords.length/dim;++i){j=i*dim;x=coords[j];y=coords[j+1];z=(dim==2)?null:coords[j+2];if(this.xy){points.push(new OpenLayers.Geometry.Point(x,y,z));}else{points.push(new OpenLayers.Geometry.Point(y,x,z));}}}
-if(coords.length==0){nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");if(nodeList.length>0){coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coordString=coordString.replace(this.regExes.trimComma,",");var pointList=coordString.split(this.regExes.splitSpace);for(var i=0;i<pointList.length;++i){coords=pointList[i].split(",");if(coords.length==2){coords[2]=null;}
-if(this.xy){points.push(new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]));}else{points.push(new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]));}}}}
-var line=null;if(points.length!=0){if(ring){line=new OpenLayers.Geometry.LinearRing(points);}else{line=new OpenLayers.Geometry.LineString(points);}}
-return line;},multilinestring:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"LineString");var components=[];if(nodeList.length>0){var line;for(var i=0;i<nodeList.length;++i){line=this.parseGeometry.linestring.apply(this,[nodeList[i]]);if(line){components.push(line);}}}
-return new OpenLayers.Geometry.MultiLineString(components);},polygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"LinearRing");var components=[];if(nodeList.length>0){var ring;for(var i=0;i<nodeList.length;++i){ring=this.parseGeometry.linestring.apply(this,[nodeList[i],true]);if(ring){components.push(ring);}}}
-return new OpenLayers.Geometry.Polygon(components);},multipolygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"Polygon");var components=[];if(nodeList.length>0){var polygon;for(var i=0;i<nodeList.length;++i){polygon=this.parseGeometry.polygon.apply(this,[nodeList[i]]);if(polygon){components.push(polygon);}}}
-return new OpenLayers.Geometry.MultiPolygon(components);},envelope:function(node){var components=[];var coordString;var envelope;var lpoint=this.getElementsByTagNameNS(node,this.gmlns,"lowerCorner");if(lpoint.length>0){var coords=[];if(lpoint.length>0){coordString=lpoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);}
-if(coords.length==2){coords[2]=null;}
-if(this.xy){var lowerPoint=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{var lowerPoint=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}}
-var upoint=this.getElementsByTagNameNS(node,this.gmlns,"upperCorner");if(upoint.length>0){var coords=[];if(upoint.length>0){coordString=upoint[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.trimSpace,"");coords=coordString.split(this.regExes.splitSpace);}
-if(coords.length==2){coords[2]=null;}
-if(this.xy){var upperPoint=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{var upperPoint=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}}
-if(lowerPoint&&upperPoint){components.push(new OpenLayers.Geometry.Point(lowerPoint.x,lowerPoint.y));components.push(new OpenLayers.Geometry.Point(upperPoint.x,lowerPoint.y));components.push(new OpenLayers.Geometry.Point(upperPoint.x,upperPoint.y));components.push(new OpenLayers.Geometry.Point(lowerPoint.x,upperPoint.y));components.push(new OpenLayers.Geometry.Point(lowerPoint.x,lowerPoint.y));var ring=new OpenLayers.Geometry.LinearRing(components);envelope=new OpenLayers.Geometry.Polygon([ring]);}
-return envelope;},box:function(node){var nodeList=this.getElementsByTagNameNS(node,this.gmlns,"coordinates");var coordString;var coords,beginPoint=null,endPoint=null;if(nodeList.length>0){coordString=nodeList[0].firstChild.nodeValue;coords=coordString.split(" ");if(coords.length==2){beginPoint=coords[0].split(",");endPoint=coords[1].split(",");}}
-if(beginPoint!==null&&endPoint!==null){return new OpenLayers.Bounds(parseFloat(beginPoint[0]),parseFloat(beginPoint[1]),parseFloat(endPoint[0]),parseFloat(endPoint[1]));}}},parseAttributes:function(node){var attributes={};var childNode=node.firstChild;var children,i,child,grandchildren,grandchild,name,value;while(childNode){if(childNode.nodeType==1){children=childNode.childNodes;for(i=0;i<children.length;++i){child=children[i];if(child.nodeType==1){grandchildren=child.childNodes;if(grandchildren.length==1){grandchild=grandchildren[0];if(grandchild.nodeType==3||grandchild.nodeType==4){name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;value=grandchild.nodeValue.replace(this.regExes.trimSpace,"");attributes[name]=value;}}else{attributes[child.nodeName.split(":").pop()]=null;}}}
-break;}
-childNode=childNode.nextSibling;}
-return attributes;},write:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
-var gml=this.createElementNS("http://www.opengis.net/wfs","wfs:"+this.collectionName);for(var i=0;i<features.length;i++){gml.appendChild(this.createFeatureXML(features[i]));}
-return OpenLayers.Format.XML.prototype.write.apply(this,[gml]);},createFeatureXML:function(feature){var geometry=feature.geometry;var geometryNode=this.buildGeometryNode(geometry);var geomContainer=this.createElementNS(this.featureNS,this.featurePrefix+":"+
-this.geometryName);geomContainer.appendChild(geometryNode);var featureNode=this.createElementNS(this.gmlns,"gml:"+this.featureName);var featureContainer=this.createElementNS(this.featureNS,this.featurePrefix+":"+
-this.layerName);var fid=feature.fid||feature.id;featureContainer.setAttribute("fid",fid);featureContainer.appendChild(geomContainer);for(var attr in feature.attributes){var attrText=this.createTextNode(feature.attributes[attr]);var nodename=attr.substring(attr.lastIndexOf(":")+1);var attrContainer=this.createElementNS(this.featureNS,this.featurePrefix+":"+
-nodename);attrContainer.appendChild(attrText);featureContainer.appendChild(attrContainer);}
-featureNode.appendChild(featureContainer);return featureNode;},buildGeometryNode:function(geometry){if(this.externalProjection&&this.internalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
-var className=geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);var builder=this.buildGeometry[type.toLowerCase()];return builder.apply(this,[geometry]);},buildGeometry:{point:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:Point");gml.appendChild(this.buildCoordinatesNode(geometry));return gml;},multipoint:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:MultiPoint");var points=geometry.components;var pointMember,pointGeom;for(var i=0;i<points.length;i++){pointMember=this.createElementNS(this.gmlns,"gml:pointMember");pointGeom=this.buildGeometry.point.apply(this,[points[i]]);pointMember.appendChild(pointGeom);gml.appendChild(pointMember);}
-return gml;},linestring:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:LineString");gml.appendChild(this.buildCoordinatesNode(geometry));return gml;},multilinestring:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:MultiLineString");var lines=geometry.components;var lineMember,lineGeom;for(var i=0;i<lines.length;++i){lineMember=this.createElementNS(this.gmlns,"gml:lineStringMember");lineGeom=this.buildGeometry.linestring.apply(this,[lines[i]]);lineMember.appendChild(lineGeom);gml.appendChild(lineMember);}
-return gml;},linearring:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:LinearRing");gml.appendChild(this.buildCoordinatesNode(geometry));return gml;},polygon:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:Polygon");var rings=geometry.components;var ringMember,ringGeom,type;for(var i=0;i<rings.length;++i){type=(i==0)?"outerBoundaryIs":"innerBoundaryIs";ringMember=this.createElementNS(this.gmlns,"gml:"+type);ringGeom=this.buildGeometry.linearring.apply(this,[rings[i]]);ringMember.appendChild(ringGeom);gml.appendChild(ringMember);}
-return gml;},multipolygon:function(geometry){var gml=this.createElementNS(this.gmlns,"gml:MultiPolygon");var polys=geometry.components;var polyMember,polyGeom;for(var i=0;i<polys.length;++i){polyMember=this.createElementNS(this.gmlns,"gml:polygonMember");polyGeom=this.buildGeometry.polygon.apply(this,[polys[i]]);polyMember.appendChild(polyGeom);gml.appendChild(polyMember);}
-return gml;},bounds:function(bounds){var gml=this.createElementNS(this.gmlns,"gml:Box");gml.appendChild(this.buildCoordinatesNode(bounds));return gml;}},buildCoordinatesNode:function(geometry){var coordinatesNode=this.createElementNS(this.gmlns,"gml:coordinates");coordinatesNode.setAttribute("decimal",".");coordinatesNode.setAttribute("cs",",");coordinatesNode.setAttribute("ts"," ");var parts=[];if(geometry instanceof OpenLayers.Bounds){parts.push(geometry.left+","+geometry.bottom);parts.push(geometry.right+","+geometry.top);}else{var points=(geometry.components)?geometry.components:[geometry];for(var i=0;i<points.length;i++){parts.push(points[i].x+","+points[i].y);}}
-var txtNode=this.createTextNode(parts.join(" "));coordinatesNode.appendChild(txtNode);return coordinatesNode;},CLASS_NAME:"OpenLayers.Format.GML"});if(!OpenLayers.Format.GML){OpenLayers.Format.GML={};}
-OpenLayers.Format.GML.Base=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs"},defaultPrefix:"gml",schemaLocation:null,featureType:null,featureNS:null,geometryName:"geometry",extractAttributes:true,srsName:null,xy:true,geometryTypes:null,singleFeatureType:null,regExes:{trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g),featureMember:(/^(.*:)?featureMembers?$/)},initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);this.setGeometryTypes();if(options&&options.featureNS){this.setNamespace("feature",options.featureNS);}
-this.singleFeatureType=!options||(typeof options.featureType==="string");},read:function(data){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-if(data&&data.nodeType==9){data=data.documentElement;}
-var features=[];this.readNode(data,{features:features},true);if(features.length==0){var elements=this.getElementsByTagNameNS(data,this.namespaces.gml,"featureMember");if(elements.length){for(var i=0,len=elements.length;i<len;++i){this.readNode(elements[i],{features:features},true);}}else{var elements=this.getElementsByTagNameNS(data,this.namespaces.gml,"featureMembers");if(elements.length){this.readNode(elements[0],{features:features},true);}}}
-return features;},readNode:function(node,obj,first){if(first===true&&this.autoConfig===true){this.featureType=null;delete this.namespaceAlias[this.featureNS];delete this.namespaces["feature"];this.featureNS=null;}
-if(!this.featureNS&&(!(node.prefix in this.namespaces)&&node.parentNode.namespaceURI==this.namespaces["gml"]&&this.regExes.featureMember.test(node.parentNode.nodeName))){this.featureType=node.nodeName.split(":").pop();this.setNamespace("feature",node.namespaceURI);this.featureNS=node.namespaceURI;this.autoConfig=true;}
-return OpenLayers.Format.XML.prototype.readNode.apply(this,[node,obj]);},readers:{"gml":{"_inherit":function(node,obj,container){},"featureMember":function(node,obj){this.readChildNodes(node,obj);},"featureMembers":function(node,obj){this.readChildNodes(node,obj);},"name":function(node,obj){obj.name=this.getChildValue(node);},"boundedBy":function(node,obj){var container={};this.readChildNodes(node,container);if(container.components&&container.components.length>0){obj.bounds=container.components[0];}},"Point":function(node,container){var obj={points:[]};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
-container.components.push(obj.points[0]);},"coordinates":function(node,obj){var str=this.getChildValue(node).replace(this.regExes.trimSpace,"");str=str.replace(this.regExes.trimComma,",");var pointList=str.split(this.regExes.splitSpace);var coords;var numPoints=pointList.length;var points=new Array(numPoints);for(var i=0;i<numPoints;++i){coords=pointList[i].split(",");if(this.xy){points[i]=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{points[i]=new OpenLayers.Geometry.Point(coords[1],coords[0],coords[2]);}}
-obj.points=points;},"coord":function(node,obj){var coord={};this.readChildNodes(node,coord);if(!obj.points){obj.points=[];}
-obj.points.push(new OpenLayers.Geometry.Point(coord.x,coord.y,coord.z));},"X":function(node,coord){coord.x=this.getChildValue(node);},"Y":function(node,coord){coord.y=this.getChildValue(node);},"Z":function(node,coord){coord.z=this.getChildValue(node);},"MultiPoint":function(node,container){var obj={components:[]};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.MultiPoint(obj.components)];},"pointMember":function(node,obj){this.readChildNodes(node,obj);},"LineString":function(node,container){var obj={};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);if(!container.components){container.components=[];}
-container.components.push(new OpenLayers.Geometry.LineString(obj.points));},"MultiLineString":function(node,container){var obj={components:[]};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.MultiLineString(obj.components)];},"lineStringMember":function(node,obj){this.readChildNodes(node,obj);},"Polygon":function(node,container){var obj={outer:null,inner:[]};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);obj.inner.unshift(obj.outer);if(!container.components){container.components=[];}
-container.components.push(new OpenLayers.Geometry.Polygon(obj.inner));},"LinearRing":function(node,obj){var container={};this.readers.gml._inherit.apply(this,[node,container]);this.readChildNodes(node,container);obj.components=[new OpenLayers.Geometry.LinearRing(container.points)];},"MultiPolygon":function(node,container){var obj={components:[]};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.MultiPolygon(obj.components)];},"polygonMember":function(node,obj){this.readChildNodes(node,obj);},"GeometryCollection":function(node,container){var obj={components:[]};this.readers.gml._inherit.apply(this,[node,obj,container]);this.readChildNodes(node,obj);container.components=[new OpenLayers.Geometry.Collection(obj.components)];},"geometryMember":function(node,obj){this.readChildNodes(node,obj);}},"feature":{"*":function(node,obj){var name;var local=node.localName||node.nodeName.split(":").pop();if(obj.features){if(!this.singleFeatureType&&(OpenLayers.Util.indexOf(this.featureType,local)!==-1)){name="_typeName";}else if(local===this.featureType){name="_typeName";}}else{if(node.childNodes.length==0||(node.childNodes.length==1&&node.firstChild.nodeType==3)){if(this.extractAttributes){name="_attribute";}}else{name="_geometry";}}
-if(name){this.readers.feature[name].apply(this,[node,obj]);}},"_typeName":function(node,obj){var container={components:[],attributes:{}};this.readChildNodes(node,container);if(container.name){container.attributes.name=container.name;}
-var feature=new OpenLayers.Feature.Vector(container.components[0],container.attributes);if(!this.singleFeatureType){feature.type=node.nodeName.split(":").pop();feature.namespace=node.namespaceURI;}
-var fid=node.getAttribute("fid")||this.getAttributeNS(node,this.namespaces["gml"],"id");if(fid){feature.fid=fid;}
-if(this.internalProjection&&this.externalProjection&&feature.geometry){feature.geometry.transform(this.externalProjection,this.internalProjection);}
-if(container.bounds){feature.bounds=container.bounds;}
-obj.features.push(feature);},"_geometry":function(node,obj){if(!this.geometryName){this.geometryName=node.nodeName.split(":").pop();}
-this.readChildNodes(node,obj);},"_attribute":function(node,obj){var local=node.localName||node.nodeName.split(":").pop();var value=this.getChildValue(node);obj.attributes[local]=value;}},"wfs":{"FeatureCollection":function(node,obj){this.readChildNodes(node,obj);}}},write:function(features){var name;if(OpenLayers.Util.isArray(features)){name="featureMembers";}else{name="featureMember";}
-var root=this.writeNode("gml:"+name,features);this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},writers:{"gml":{"featureMember":function(feature){var node=this.createElementNSPlus("gml:featureMember");this.writeNode("feature:_typeName",feature,node);return node;},"MultiPoint":function(geometry){var node=this.createElementNSPlus("gml:MultiPoint");var components=geometry.components||[geometry];for(var i=0,ii=components.length;i<ii;++i){this.writeNode("pointMember",components[i],node);}
-return node;},"pointMember":function(geometry){var node=this.createElementNSPlus("gml:pointMember");this.writeNode("Point",geometry,node);return node;},"MultiLineString":function(geometry){var node=this.createElementNSPlus("gml:MultiLineString");var components=geometry.components||[geometry];for(var i=0,ii=components.length;i<ii;++i){this.writeNode("lineStringMember",components[i],node);}
-return node;},"lineStringMember":function(geometry){var node=this.createElementNSPlus("gml:lineStringMember");this.writeNode("LineString",geometry,node);return node;},"MultiPolygon":function(geometry){var node=this.createElementNSPlus("gml:MultiPolygon");var components=geometry.components||[geometry];for(var i=0,ii=components.length;i<ii;++i){this.writeNode("polygonMember",components[i],node);}
-return node;},"polygonMember":function(geometry){var node=this.createElementNSPlus("gml:polygonMember");this.writeNode("Polygon",geometry,node);return node;},"GeometryCollection":function(geometry){var node=this.createElementNSPlus("gml:GeometryCollection");for(var i=0,len=geometry.components.length;i<len;++i){this.writeNode("geometryMember",geometry.components[i],node);}
-return node;},"geometryMember":function(geometry){var node=this.createElementNSPlus("gml:geometryMember");var child=this.writeNode("feature:_geometry",geometry);node.appendChild(child.firstChild);return node;}},"feature":{"_typeName":function(feature){var node=this.createElementNSPlus("feature:"+this.featureType,{attributes:{fid:feature.fid}});if(feature.geometry){this.writeNode("feature:_geometry",feature.geometry,node);}
-for(var name in feature.attributes){var value=feature.attributes[name];if(value!=null){this.writeNode("feature:_attribute",{name:name,value:value},node);}}
-return node;},"_geometry":function(geometry){if(this.externalProjection&&this.internalProjection){geometry=geometry.clone().transform(this.internalProjection,this.externalProjection);}
-var node=this.createElementNSPlus("feature:"+this.geometryName);var type=this.geometryTypes[geometry.CLASS_NAME];var child=this.writeNode("gml:"+type,geometry,node);if(this.srsName){child.setAttribute("srsName",this.srsName);}
-return node;},"_attribute":function(obj){return this.createElementNSPlus("feature:"+obj.name,{value:obj.value});}},"wfs":{"FeatureCollection":function(features){var node=this.createElementNSPlus("wfs:FeatureCollection");for(var i=0,len=features.length;i<len;++i){this.writeNode("gml:featureMember",features[i],node);}
-return node;}}},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":"LineString","OpenLayers.Geometry.MultiLineString":"MultiLineString","OpenLayers.Geometry.Polygon":"Polygon","OpenLayers.Geometry.MultiPolygon":"MultiPolygon","OpenLayers.Geometry.Collection":"GeometryCollection"};},CLASS_NAME:"OpenLayers.Format.GML.Base"});OpenLayers.Format.GML.v2=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",initialize:function(options){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[options]);},readers:{"gml":OpenLayers.Util.applyDefaults({"outerBoundaryIs":function(node,container){var obj={};this.readChildNodes(node,obj);container.outer=obj.components[0];},"innerBoundaryIs":function(node,container){var obj={};this.readChildNodes(node,obj);container.inner.push(obj.components[0]);},"Box":function(node,container){var obj={};this.readChildNodes(node,obj);if(!container.components){container.components=[];}
-var min=obj.points[0];var max=obj.points[1];container.components.push(new OpenLayers.Bounds(min.x,min.y,max.x,max.y));}},OpenLayers.Format.GML.Base.prototype.readers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.readers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.readers["wfs"]},write:function(features){var name;if(OpenLayers.Util.isArray(features)){name="wfs:FeatureCollection";}else{name="gml:featureMember";}
-var root=this.writeNode(name,features);this.setAttributeNS(root,this.namespaces["xsi"],"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[root]);},writers:{"gml":OpenLayers.Util.applyDefaults({"Point":function(geometry){var node=this.createElementNSPlus("gml:Point");this.writeNode("coordinates",[geometry],node);return node;},"coordinates":function(points){var numPoints=points.length;var parts=new Array(numPoints);var point;for(var i=0;i<numPoints;++i){point=points[i];if(this.xy){parts[i]=point.x+","+point.y;}else{parts[i]=point.y+","+point.x;}
-if(point.z!=undefined){parts[i]+=","+point.z;}}
-return this.createElementNSPlus("gml:coordinates",{attributes:{decimal:".",cs:",",ts:" "},value:(numPoints==1)?parts[0]:parts.join(" ")});},"LineString":function(geometry){var node=this.createElementNSPlus("gml:LineString");this.writeNode("coordinates",geometry.components,node);return node;},"Polygon":function(geometry){var node=this.createElementNSPlus("gml:Polygon");this.writeNode("outerBoundaryIs",geometry.components[0],node);for(var i=1;i<geometry.components.length;++i){this.writeNode("innerBoundaryIs",geometry.components[i],node);}
-return node;},"outerBoundaryIs":function(ring){var node=this.createElementNSPlus("gml:outerBoundaryIs");this.writeNode("LinearRing",ring,node);return node;},"innerBoundaryIs":function(ring){var node=this.createElementNSPlus("gml:innerBoundaryIs");this.writeNode("LinearRing",ring,node);return node;},"LinearRing":function(ring){var node=this.createElementNSPlus("gml:LinearRing");this.writeNode("coordinates",ring.components,node);return node;},"Box":function(bounds){var node=this.createElementNSPlus("gml:Box");this.writeNode("coordinates",[{x:bounds.left,y:bounds.bottom},{x:bounds.right,y:bounds.top}],node);if(this.srsName){node.setAttribute("srsName",this.srsName);}
-return node;}},OpenLayers.Format.GML.Base.prototype.writers["gml"]),"feature":OpenLayers.Format.GML.Base.prototype.writers["feature"],"wfs":OpenLayers.Format.GML.Base.prototype.writers["wfs"]},CLASS_NAME:"OpenLayers.Format.GML.v2"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Date={dateRegEx:/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/,toISOString:(function(){if("toISOString"in Date.prototype){return function(date){return date.toISOString();};}else{return function(date){var str;if(isNaN(date.getTime())){str="Invalid Date";}else{str=date.getUTCFullYear()+"-"+
-OpenLayers.Number.zeroPad(date.getUTCMonth()+1,2)+"-"+
-OpenLayers.Number.zeroPad(date.getUTCDate(),2)+"T"+
-OpenLayers.Number.zeroPad(date.getUTCHours(),2)+":"+
-OpenLayers.Number.zeroPad(date.getUTCMinutes(),2)+":"+
-OpenLayers.Number.zeroPad(date.getUTCSeconds(),2)+"."+
-OpenLayers.Number.zeroPad(date.getUTCMilliseconds(),3)+"Z";}
-return str;};}})(),parse:function(str){var date;var match=str.match(this.dateRegEx);if(match&&(match[1]||match[7])){var year=parseInt(match[1],10)||0;var month=(parseInt(match[2],10)-1)||0;var day=parseInt(match[3],10)||1;date=new Date(Date.UTC(year,month,day));var type=match[7];if(type){var hours=parseInt(match[4],10);var minutes=parseInt(match[5],10);var secFrac=parseFloat(match[6]);var seconds=secFrac|0;var milliseconds=Math.round(1000*(secFrac-seconds));date.setUTCHours(hours,minutes,seconds,milliseconds);if(type!=="Z"){var hoursOffset=parseInt(type,10);var minutesOffset=parseInt(match[8],10)||0;var offset=-1000*(60*(hoursOffset*60)+minutesOffset*60);date=new Date(date.getTime()+offset);}}}else{date=new Date("invalid");}
-return date;}};OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(options){OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){var obj={};this.readers.ogc["Filter"].apply(this,[data,obj]);return obj.filter;},readers:{"ogc":{"_expression":function(node){var obj,value="";for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 1:obj=this.readNode(child);if(obj.property){value+="${"+obj.property+"}";}else if(obj.value!==undefined){value+=obj.value;}
-break;case 3:case 4:value+=child.nodeValue;}}
-return value;},"Filter":function(node,parent){var obj={fids:[],filters:[]};this.readChildNodes(node,obj);if(obj.fids.length>0){parent.filter=new OpenLayers.Filter.FeatureId({fids:obj.fids});}else if(obj.filters.length>0){parent.filter=obj.filters[0];}},"FeatureId":function(node,obj){var fid=node.getAttribute("fid");if(fid){obj.fids.push(fid);}},"And":function(node,obj){var filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND});this.readChildNodes(node,filter);obj.filters.push(filter);},"Or":function(node,obj){var filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(node,filter);obj.filters.push(filter);},"Not":function(node,obj){var filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLessThan":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsGreaterThan":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLessThanOrEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsGreaterThanOrEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsBetween":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(node,filter);obj.filters.push(filter);},"Literal":function(node,obj){obj.value=OpenLayers.String.numericIf(this.getChildValue(node),true);},"PropertyName":function(node,filter){filter.property=this.getChildValue(node);},"LowerBoundary":function(node,filter){filter.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,node),true);},"UpperBoundary":function(node,filter){filter.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,node),true);},"Intersects":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.INTERSECTS);},"Within":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.WITHIN);},"Contains":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.CONTAINS);},"DWithin":function(node,obj){this.readSpatial(node,obj,OpenLayers.Filter.Spatial.DWITHIN);},"Distance":function(node,obj){obj.distance=parseInt(this.getChildValue(node));obj.distanceUnits=node.getAttribute("units");},"Function":function(node,obj){return;},"PropertyIsNull":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.IS_NULL});this.readChildNodes(node,filter);obj.filters.push(filter);}}},readSpatial:function(node,obj,type){var filter=new OpenLayers.Filter.Spatial({type:type});this.readChildNodes(node,filter);filter.value=filter.components[0];delete filter.components;obj.filters.push(filter);},encodeLiteral:function(value){if(value instanceof Date){value=OpenLayers.Date.toISOString(value);}
-return value;},writeOgcExpression:function(value,node){if(value instanceof OpenLayers.Filter.Function){this.writeNode("Function",value,node);}else{this.writeNode("Literal",value,node);}
-return node;},write:function(filter){return this.writers.ogc["Filter"].apply(this,[filter]);},writers:{"ogc":{"Filter":function(filter){var node=this.createElementNSPlus("ogc:Filter");this.writeNode(this.getFilterType(filter),filter,node);return node;},"_featureIds":function(filter){var node=this.createDocumentFragment();for(var i=0,ii=filter.fids.length;i<ii;++i){this.writeNode("ogc:FeatureId",filter.fids[i],node);}
-return node;},"FeatureId":function(fid){return this.createElementNSPlus("ogc:FeatureId",{attributes:{fid:fid}});},"And":function(filter){var node=this.createElementNSPlus("ogc:And");var childFilter;for(var i=0,ii=filter.filters.length;i<ii;++i){childFilter=filter.filters[i];this.writeNode(this.getFilterType(childFilter),childFilter,node);}
-return node;},"Or":function(filter){var node=this.createElementNSPlus("ogc:Or");var childFilter;for(var i=0,ii=filter.filters.length;i<ii;++i){childFilter=filter.filters[i];this.writeNode(this.getFilterType(childFilter),childFilter,node);}
-return node;},"Not":function(filter){var node=this.createElementNSPlus("ogc:Not");var childFilter=filter.filters[0];this.writeNode(this.getFilterType(childFilter),childFilter,node);return node;},"PropertyIsLessThan":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLessThan");this.writeNode("PropertyName",filter,node);this.writeOgcExpression(filter.value,node);return node;},"PropertyIsGreaterThan":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsGreaterThan");this.writeNode("PropertyName",filter,node);this.writeOgcExpression(filter.value,node);return node;},"PropertyIsLessThanOrEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");this.writeNode("PropertyName",filter,node);this.writeOgcExpression(filter.value,node);return node;},"PropertyIsGreaterThanOrEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");this.writeNode("PropertyName",filter,node);this.writeOgcExpression(filter.value,node);return node;},"PropertyIsBetween":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsBetween");this.writeNode("PropertyName",filter,node);this.writeNode("LowerBoundary",filter,node);this.writeNode("UpperBoundary",filter,node);return node;},"PropertyName":function(filter){return this.createElementNSPlus("ogc:PropertyName",{value:filter.property});},"Literal":function(value){var encode=this.encodeLiteral||OpenLayers.Format.Filter.v1.prototype.encodeLiteral;return this.createElementNSPlus("ogc:Literal",{value:encode(value)});},"LowerBoundary":function(filter){var node=this.createElementNSPlus("ogc:LowerBoundary");this.writeOgcExpression(filter.lowerBoundary,node);return node;},"UpperBoundary":function(filter){var node=this.createElementNSPlus("ogc:UpperBoundary");this.writeNode("Literal",filter.upperBoundary,node);return node;},"INTERSECTS":function(filter){return this.writeSpatial(filter,"Intersects");},"WITHIN":function(filter){return this.writeSpatial(filter,"Within");},"CONTAINS":function(filter){return this.writeSpatial(filter,"Contains");},"DWITHIN":function(filter){var node=this.writeSpatial(filter,"DWithin");this.writeNode("Distance",filter,node);return node;},"Distance":function(filter){return this.createElementNSPlus("ogc:Distance",{attributes:{units:filter.distanceUnits},value:filter.distance});},"Function":function(filter){var node=this.createElementNSPlus("ogc:Function",{attributes:{name:filter.name}});var params=filter.params;for(var i=0,len=params.length;i<len;i++){this.writeOgcExpression(params[i],node);}
-return node;},"PropertyIsNull":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsNull");this.writeNode("PropertyName",filter,node);return node;}}},getFilterType:function(filter){var filterType=this.filterMap[filter.type];if(!filterType){throw"Filter writing not supported for rule type: "+filter.type;}
-return filterType;},filterMap:{"&&":"And","||":"Or","!":"Not","==":"PropertyIsEqualTo","!=":"PropertyIsNotEqualTo","<":"PropertyIsLessThan",">":"PropertyIsGreaterThan","<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike","NULL":"PropertyIsNull","BBOX":"BBOX","DWITHIN":"DWITHIN","WITHIN":"WITHIN","CONTAINS":"CONTAINS","INTERSECTS":"INTERSECTS","FID":"_featureIds"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Format.Filter.v1_0_0=OpenLayers.Class(OpenLayers.Format.GML.v2,OpenLayers.Format.Filter.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",initialize:function(options){OpenLayers.Format.GML.v2.prototype.initialize.apply(this,[options]);},readers:{"ogc":OpenLayers.Util.applyDefaults({"PropertyIsEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsNotEqualTo":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO});this.readChildNodes(node,filter);obj.filters.push(filter);},"PropertyIsLike":function(node,obj){var filter=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(node,filter);var wildCard=node.getAttribute("wildCard");var singleChar=node.getAttribute("singleChar");var esc=node.getAttribute("escape");filter.value2regex(wildCard,singleChar,esc);obj.filters.push(filter);}},OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),"gml":OpenLayers.Format.GML.v2.prototype.readers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.readers["feature"]},writers:{"ogc":OpenLayers.Util.applyDefaults({"PropertyIsEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsEqualTo");this.writeNode("PropertyName",filter,node);this.writeOgcExpression(filter.value,node);return node;},"PropertyIsNotEqualTo":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsNotEqualTo");this.writeNode("PropertyName",filter,node);this.writeOgcExpression(filter.value,node);return node;},"PropertyIsLike":function(filter){var node=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{wildCard:"*",singleChar:".",escape:"!"}});this.writeNode("PropertyName",filter,node);this.writeNode("Literal",filter.regex2value(),node);return node;},"BBOX":function(filter){var node=this.createElementNSPlus("ogc:BBOX");filter.property&&this.writeNode("PropertyName",filter,node);var box=this.writeNode("gml:Box",filter.value,node);if(filter.projection){box.setAttribute("srsName",filter.projection);}
-return node;}},OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),"gml":OpenLayers.Format.GML.v2.prototype.writers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.writers["feature"]},writeSpatial:function(filter,name){var node=this.createElementNSPlus("ogc:"+name);this.writeNode("PropertyName",filter,node);if(filter.value instanceof OpenLayers.Filter.Function){this.writeNode("Function",filter.value,node);}else{var child;if(filter.value instanceof OpenLayers.Geometry){child=this.writeNode("feature:_geometry",filter.value).firstChild;}else{child=this.writeNode("gml:Box",filter.value);}
-if(filter.projection){child.setAttribute("srsName",filter.projection);}
-node.appendChild(child);}
-return node;},CLASS_NAME:"OpenLayers.Format.Filter.v1_0_0"});OpenLayers.Format.WFST.v1_0_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,OpenLayers.Format.WFST.v1,{version:"1.0.0",srsNameInQuery:false,schemaLocations:{"wfs":"http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"},initialize:function(options){OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this,[options]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[options]);},readNode:function(node,obj,first){return OpenLayers.Format.GML.v2.prototype.readNode.apply(this,arguments);},readers:{"wfs":OpenLayers.Util.applyDefaults({"WFS_TransactionResponse":function(node,obj){obj.insertIds=[];obj.success=false;this.readChildNodes(node,obj);},"InsertResult":function(node,container){var obj={fids:[]};this.readChildNodes(node,obj);container.insertIds=container.insertIds.concat(obj.fids);},"TransactionResult":function(node,obj){this.readChildNodes(node,obj);},"Status":function(node,obj){this.readChildNodes(node,obj);},"SUCCESS":function(node,obj){obj.success=true;}},OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),"gml":OpenLayers.Format.GML.v2.prototype.readers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.readers["feature"],"ogc":OpenLayers.Format.Filter.v1_0_0.prototype.readers["ogc"]},writers:{"wfs":OpenLayers.Util.applyDefaults({"Query":function(options){options=OpenLayers.Util.extend({featureNS:this.featureNS,featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName,srsNameInQuery:this.srsNameInQuery},options);var prefix=options.featurePrefix;var node=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(prefix?prefix+":":"")+
-options.featureType}});if(options.srsNameInQuery&&options.srsName){node.setAttribute("srsName",options.srsName);}
-if(options.featureNS){node.setAttribute("xmlns:"+prefix,options.featureNS);}
-if(options.propertyNames){for(var i=0,len=options.propertyNames.length;i<len;i++){this.writeNode("ogc:PropertyName",{property:options.propertyNames[i]},node);}}
-if(options.filter){this.setFilterProperty(options.filter);this.writeNode("ogc:Filter",options.filter,node);}
-return node;}},OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),"gml":OpenLayers.Format.GML.v2.prototype.writers["gml"],"feature":OpenLayers.Format.GML.v2.prototype.writers["feature"],"ogc":OpenLayers.Format.Filter.v1_0_0.prototype.writers["ogc"]},CLASS_NAME:"OpenLayers.Format.WFST.v1_0_0"});OpenLayers.ElementsIndexer=OpenLayers.Class({maxZIndex:null,order:null,indices:null,compare:null,initialize:function(yOrdering){this.compare=yOrdering?OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER:OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;this.clear();},insert:function(newNode){if(this.exists(newNode)){this.remove(newNode);}
-var nodeId=newNode.id;this.determineZIndex(newNode);var leftIndex=-1;var rightIndex=this.order.length;var middle;while(rightIndex-leftIndex>1){middle=parseInt((leftIndex+rightIndex)/2);var placement=this.compare(this,newNode,OpenLayers.Util.getElement(this.order[middle]));if(placement>0){leftIndex=middle;}else{rightIndex=middle;}}
-this.order.splice(rightIndex,0,nodeId);this.indices[nodeId]=this.getZIndex(newNode);return this.getNextElement(rightIndex);},remove:function(node){var nodeId=node.id;var arrayIndex=OpenLayers.Util.indexOf(this.order,nodeId);if(arrayIndex>=0){this.order.splice(arrayIndex,1);delete this.indices[nodeId];if(this.order.length>0){var lastId=this.order[this.order.length-1];this.maxZIndex=this.indices[lastId];}else{this.maxZIndex=0;}}},clear:function(){this.order=[];this.indices={};this.maxZIndex=0;},exists:function(node){return(this.indices[node.id]!=null);},getZIndex:function(node){return node._style.graphicZIndex;},determineZIndex:function(node){var zIndex=node._style.graphicZIndex;if(zIndex==null){zIndex=this.maxZIndex;node._style.graphicZIndex=zIndex;}else if(zIndex>this.maxZIndex){this.maxZIndex=zIndex;}},getNextElement:function(index){var nextIndex=index+1;if(nextIndex<this.order.length){var nextElement=OpenLayers.Util.getElement(this.order[nextIndex]);if(nextElement==undefined){nextElement=this.getNextElement(nextIndex);}
-return nextElement;}else{return null;}},CLASS_NAME:"OpenLayers.ElementsIndexer"});OpenLayers.ElementsIndexer.IndexingMethods={Z_ORDER:function(indexer,newNode,nextNode){var newZIndex=indexer.getZIndex(newNode);var returnVal=0;if(nextNode){var nextZIndex=indexer.getZIndex(nextNode);returnVal=newZIndex-nextZIndex;}
-return returnVal;},Z_ORDER_DRAWING_ORDER:function(indexer,newNode,nextNode){var returnVal=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer,newNode,nextNode);if(nextNode&&returnVal==0){returnVal=1;}
-return returnVal;},Z_ORDER_Y_ORDER:function(indexer,newNode,nextNode){var returnVal=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer,newNode,nextNode);if(nextNode&&returnVal===0){var result=nextNode._boundsBottom-newNode._boundsBottom;returnVal=(result===0)?1:result;}
-return returnVal;}};OpenLayers.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,vectorRoot:null,textRoot:null,xmlns:null,xOffset:0,indexer:null,BACKGROUND_ID_SUFFIX:"_background",LABEL_ID_SUFFIX:"_label",LABEL_OUTLINE_SUFFIX:"_outline",initialize:function(containerID,options){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot("_root");this.vectorRoot=this.createRoot("_vroot");this.textRoot=this.createRoot("_troot");this.root.appendChild(this.vectorRoot);this.root.appendChild(this.textRoot);this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);if(options&&(options.zIndexing||options.yOrdering)){this.indexer=new OpenLayers.ElementsIndexer(options.yOrdering);}},destroy:function(){this.clear();this.rendererRoot=null;this.root=null;this.xmlns=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments);},clear:function(){var child;var root=this.vectorRoot;if(root){while(child=root.firstChild){root.removeChild(child);}}
-root=this.textRoot;if(root){while(child=root.firstChild){root.removeChild(child);}}
-if(this.indexer){this.indexer.clear();}},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var rightOfDateLine,ratio=extent.getWidth()/this.map.getExtent().getWidth(),extent=extent.scale(1/ratio),world=this.map.getMaxExtent();if(world.right>extent.left&&world.right<extent.right){rightOfDateLine=true;}else if(world.left>extent.left&&world.left<extent.right){rightOfDateLine=false;}
-if(rightOfDateLine!==this.rightOfDateLine||resolutionChanged){coordSysUnchanged=false;this.xOffset=rightOfDateLine===true?world.getWidth()/resolution:0;}
-this.rightOfDateLine=rightOfDateLine;}
-return coordSysUnchanged;},getNodeType:function(geometry,style){},drawGeometry:function(geometry,style,featureId){var className=geometry.CLASS_NAME;var rendered=true;if((className=="OpenLayers.Geometry.Collection")||(className=="OpenLayers.Geometry.MultiPoint")||(className=="OpenLayers.Geometry.MultiLineString")||(className=="OpenLayers.Geometry.MultiPolygon")){for(var i=0,len=geometry.components.length;i<len;i++){rendered=this.drawGeometry(geometry.components[i],style,featureId)&&rendered;}
-return rendered;}
-rendered=false;var removeBackground=false;if(style.display!="none"){if(style.backgroundGraphic){this.redrawBackgroundNode(geometry.id,geometry,style,featureId);}else{removeBackground=true;}
-rendered=this.redrawNode(geometry.id,geometry,style,featureId);}
-if(rendered==false){var node=document.getElementById(geometry.id);if(node){if(node._style.backgroundGraphic){removeBackground=true;}
-node.parentNode.removeChild(node);}}
-if(removeBackground){var node=document.getElementById(geometry.id+this.BACKGROUND_ID_SUFFIX);if(node){node.parentNode.removeChild(node);}}
-return rendered;},redrawNode:function(id,geometry,style,featureId){style=this.applyDefaultSymbolizer(style);var node=this.nodeFactory(id,this.getNodeType(geometry,style));node._featureId=featureId;node._boundsBottom=geometry.getBounds().bottom;node._geometryClass=geometry.CLASS_NAME;node._style=style;var drawResult=this.drawGeometryNode(node,geometry,style);if(drawResult===false){return false;}
-node=drawResult.node;if(this.indexer){var insert=this.indexer.insert(node);if(insert){this.vectorRoot.insertBefore(node,insert);}else{this.vectorRoot.appendChild(node);}}else{if(node.parentNode!==this.vectorRoot){this.vectorRoot.appendChild(node);}}
-this.postDraw(node);return drawResult.complete;},redrawBackgroundNode:function(id,geometry,style,featureId){var backgroundStyle=OpenLayers.Util.extend({},style);backgroundStyle.externalGraphic=backgroundStyle.backgroundGraphic;backgroundStyle.graphicXOffset=backgroundStyle.backgroundXOffset;backgroundStyle.graphicYOffset=backgroundStyle.backgroundYOffset;backgroundStyle.graphicZIndex=backgroundStyle.backgroundGraphicZIndex;backgroundStyle.graphicWidth=backgroundStyle.backgroundWidth||backgroundStyle.graphicWidth;backgroundStyle.graphicHeight=backgroundStyle.backgroundHeight||backgroundStyle.graphicHeight;backgroundStyle.backgroundGraphic=null;backgroundStyle.backgroundXOffset=null;backgroundStyle.backgroundYOffset=null;backgroundStyle.backgroundGraphicZIndex=null;return this.redrawNode(id+this.BACKGROUND_ID_SUFFIX,geometry,backgroundStyle,null);},drawGeometryNode:function(node,geometry,style){style=style||node._style;var options={'isFilled':style.fill===undefined?true:style.fill,'isStroked':style.stroke===undefined?!!style.strokeWidth:style.stroke};var drawn;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.graphic===false){options.isFilled=false;options.isStroked=false;}
-drawn=this.drawPoint(node,geometry);break;case"OpenLayers.Geometry.LineString":options.isFilled=false;drawn=this.drawLineString(node,geometry);break;case"OpenLayers.Geometry.LinearRing":drawn=this.drawLinearRing(node,geometry);break;case"OpenLayers.Geometry.Polygon":drawn=this.drawPolygon(node,geometry);break;case"OpenLayers.Geometry.Rectangle":drawn=this.drawRectangle(node,geometry);break;default:break;}
-node._options=options;if(drawn!=false){return{node:this.setStyle(node,style,options,geometry),complete:drawn};}else{return false;}},postDraw:function(node){},drawPoint:function(node,geometry){},drawLineString:function(node,geometry){},drawLinearRing:function(node,geometry){},drawPolygon:function(node,geometry){},drawRectangle:function(node,geometry){},drawCircle:function(node,geometry){},removeText:function(featureId){var label=document.getElementById(featureId+this.LABEL_ID_SUFFIX);if(label){this.textRoot.removeChild(label);}
-var outline=document.getElementById(featureId+this.LABEL_OUTLINE_SUFFIX);if(outline){this.textRoot.removeChild(outline);}},getFeatureIdFromEvent:function(evt){var target=evt.target;var useElement=target&&target.correspondingUseElement;var node=useElement?useElement:(target||evt.srcElement);return node._featureId;},eraseGeometry:function(geometry,featureId){if((geometry.CLASS_NAME=="OpenLayers.Geometry.MultiPoint")||(geometry.CLASS_NAME=="OpenLayers.Geometry.MultiLineString")||(geometry.CLASS_NAME=="OpenLayers.Geometry.MultiPolygon")||(geometry.CLASS_NAME=="OpenLayers.Geometry.Collection")){for(var i=0,len=geometry.components.length;i<len;i++){this.eraseGeometry(geometry.components[i],featureId);}}else{var element=OpenLayers.Util.getElement(geometry.id);if(element&&element.parentNode){if(element.geometry){element.geometry.destroy();element.geometry=null;}
-element.parentNode.removeChild(element);if(this.indexer){this.indexer.remove(element);}
-if(element._style.backgroundGraphic){var backgroundId=geometry.id+this.BACKGROUND_ID_SUFFIX;var bElem=OpenLayers.Util.getElement(backgroundId);if(bElem&&bElem.parentNode){bElem.parentNode.removeChild(bElem);}}}}},nodeFactory:function(id,type){var node=OpenLayers.Util.getElement(id);if(node){if(!this.nodeTypeCompare(node,type)){node.parentNode.removeChild(node);node=this.nodeFactory(id,type);}}else{node=this.createNode(type,id);}
-return node;},nodeTypeCompare:function(node,type){},createNode:function(type,id){},moveRoot:function(renderer){var root=this.root;if(renderer.root.parentNode==this.rendererRoot){root=renderer.root;}
-root.parentNode.removeChild(root);renderer.rendererRoot.appendChild(root);},getRenderLayerId:function(){return this.root.parentNode.parentNode.id;},isComplexSymbol:function(graphicName){return(graphicName!="circle")&&!!graphicName;},CLASS_NAME:"OpenLayers.Renderer.Elements"});OpenLayers.Control.Panel=OpenLayers.Class(OpenLayers.Control,{controls:null,autoActivate:true,defaultControl:null,saveState:false,allowDepress:false,activeState:null,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.controls=[];this.activeState={};},destroy:function(){if(this.map){this.map.events.unregister("buttonclick",this,this.onButtonClick);}
-OpenLayers.Control.prototype.destroy.apply(this,arguments);for(var ctl,i=this.controls.length-1;i>=0;i--){ctl=this.controls[i];if(ctl.events){ctl.events.un({activate:this.iconOn,deactivate:this.iconOff});}
-ctl.panel_div=null;}
-this.activeState=null;},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){var control;for(var i=0,len=this.controls.length;i<len;i++){control=this.controls[i];if(control===this.defaultControl||(this.saveState&&this.activeState[control.id])){control.activate();}}
-if(this.saveState===true){this.defaultControl=null;}
-this.redraw();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){var control;for(var i=0,len=this.controls.length;i<len;i++){control=this.controls[i];this.activeState[control.id]=control.deactivate();}
-this.redraw();return true;}else{return false;}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(this.outsideViewport){this.events.attachToElement(this.div);this.events.register("buttonclick",this,this.onButtonClick);}else{this.map.events.register("buttonclick",this,this.onButtonClick);}
-this.addControlsToMap(this.controls);return this.div;},redraw:function(){for(var l=this.div.childNodes.length,i=l-1;i>=0;i--){this.div.removeChild(this.div.childNodes[i]);}
-this.div.innerHTML="";if(this.active){for(var i=0,len=this.controls.length;i<len;i++){this.div.appendChild(this.controls[i].panel_div);}}},activateControl:function(control){if(!this.active){return false;}
-if(control.type==OpenLayers.Control.TYPE_BUTTON){control.trigger();return;}
-if(control.type==OpenLayers.Control.TYPE_TOGGLE){if(control.active){control.deactivate();}else{control.activate();}
-return;}
-if(this.allowDepress&&control.active){control.deactivate();}else{var c;for(var i=0,len=this.controls.length;i<len;i++){c=this.controls[i];if(c!=control&&(c.type===OpenLayers.Control.TYPE_TOOL||c.type==null)){c.deactivate();}}
-control.activate();}},addControls:function(controls){if(!(OpenLayers.Util.isArray(controls))){controls=[controls];}
-this.controls=this.controls.concat(controls);for(var i=0,len=controls.length;i<len;i++){var control=controls[i],element=this.createControlMarkup(control);OpenLayers.Element.addClass(element,control.displayClass+"ItemInactive");OpenLayers.Element.addClass(element,"olButton");if(control.title!=""&&!element.title){element.title=control.title;}
-control.panel_div=element;}
-if(this.map){this.addControlsToMap(controls);this.redraw();}},createControlMarkup:function(control){return document.createElement("div");},addControlsToMap:function(controls){var control;for(var i=0,len=controls.length;i<len;i++){control=controls[i];if(control.autoActivate===true){control.autoActivate=false;this.map.addControl(control);control.autoActivate=true;}else{this.map.addControl(control);control.deactivate();}
-control.events.on({activate:this.iconOn,deactivate:this.iconOff});}},iconOn:function(){var d=this.panel_div;var re=new RegExp("\\b("+this.displayClass+"Item)Inactive\\b");d.className=d.className.replace(re,"$1Active");},iconOff:function(){var d=this.panel_div;var re=new RegExp("\\b("+this.displayClass+"Item)Active\\b");d.className=d.className.replace(re,"$1Inactive");},onButtonClick:function(evt){var controls=this.controls,button=evt.buttonElement;for(var i=controls.length-1;i>=0;--i){if(controls[i].panel_div===button){this.activateControl(controls[i]);break;}}},getControlsBy:function(property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this.controls,function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getControlsByName:function(match){return this.getControlsBy("name",match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},CLASS_NAME:"OpenLayers.Control.Panel"});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<len;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
-break;}}
-if(i==this.map.controls.length){var args=this.getParameters();if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}
-if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseFloat(args.zoom);}
-this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);if(this.displayProjection){this.center.transform(this.displayProjection,this.map.getProjectionObject());}
-this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0,len=this.layers.length;i<len;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.Permalink=OpenLayers.Class(OpenLayers.Control,{argParserClass:OpenLayers.Control.ArgParser,element:null,anchor:false,base:'',displayProjection:null,initialize:function(element,base,options){if(element!==null&&typeof element=='object'&&!OpenLayers.Util.isElement(element)){options=element;this.base=document.location.href;OpenLayers.Control.prototype.initialize.apply(this,[options]);if(this.element!=null){this.element=OpenLayers.Util.getElement(this.element);}}
-else{OpenLayers.Control.prototype.initialize.apply(this,[options]);this.element=OpenLayers.Util.getElement(element);this.base=base||document.location.href;}},destroy:function(){if(this.element&&this.element.parentNode==this.div){this.div.removeChild(this.element);this.element=null;}
-if(this.map){this.map.events.unregister('moveend',this,this.updateLink);}
-OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0,len=this.map.controls.length;i<len;i++){var control=this.map.controls[i];if(control.CLASS_NAME==this.argParserClass.CLASS_NAME){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
-break;}}
-if(i==this.map.controls.length){this.map.addControl(new this.argParserClass({'displayProjection':this.displayProjection}));}},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.element&&!this.anchor){this.element=document.createElement("a");this.element.innerHTML=OpenLayers.i18n("Permalink");this.element.href="";this.div.appendChild(this.element);}
-this.map.events.on({'moveend':this.updateLink,'changelayer':this.updateLink,'changebaselayer':this.updateLink,scope:this});this.updateLink();return this.div;},updateLink:function(){var separator=this.anchor?'#':'?';var href=this.base;var anchor=null;if(href.indexOf("#")!=-1&&this.anchor==false){anchor=href.substring(href.indexOf("#"),href.length);}
-if(href.indexOf(separator)!=-1){href=href.substring(0,href.indexOf(separator));}
-var splits=href.split("#");href=splits[0]+separator+OpenLayers.Util.getParameterString(this.createParams());if(anchor){href+=anchor;}
-if(this.anchor&&!this.element){window.location.href=href;}
-else{this.element.href=href;}},createParams:function(center,zoom,layers){center=center||this.map.getCenter();var params=OpenLayers.Util.getParameters(this.base);if(center){params.zoom=zoom||this.map.getZoom();var lat=center.lat;var lon=center.lon;if(this.displayProjection){var mapPosition=OpenLayers.Projection.transform({x:lon,y:lat},this.map.getProjectionObject(),this.displayProjection);lon=mapPosition.x;lat=mapPosition.y;}
-params.lat=Math.round(lat*100000)/100000;params.lon=Math.round(lon*100000)/100000;layers=layers||this.map.layers;params.layers='';for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];if(layer.isBaseLayer){params.layers+=(layer==this.map.baseLayer)?"B":"0";}else{params.layers+=(layer.getVisibility())?"T":"F";}}}
-return params;},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:true,autoDestroy:true,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;this.active=false;},destroy:function(){this.deactivate();this.layer=null;this.options=null;},setLayer:function(layer){this.layer=layer;},activate:function(){if(!this.active){this.active=true;return true;}
-return false;},deactivate:function(){if(this.active){this.active=false;return true;}
-return false;},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.Fixed=OpenLayers.Class(OpenLayers.Strategy,{preload:false,activate:function(){var activated=OpenLayers.Strategy.prototype.activate.apply(this,arguments);if(activated){this.layer.events.on({"refresh":this.load,scope:this});if(this.layer.visibility==true||this.preload){this.load();}else{this.layer.events.on({"visibilitychanged":this.load,scope:this});}}
-return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"refresh":this.load,"visibilitychanged":this.load,scope:this});}
-return deactivated;},load:function(options){var layer=this.layer;layer.events.triggerEvent("loadstart",{filter:layer.filter});layer.protocol.read(OpenLayers.Util.applyDefaults({callback:this.merge,filter:layer.filter,scope:this},options));layer.events.un({"visibilitychanged":this.load,scope:this});},merge:function(resp){var layer=this.layer;layer.destroyFeatures();var features=resp.features;if(features&&features.length>0){var remote=layer.projection;var local=layer.map.getProjectionObject();if(!local.equals(remote)){var geom;for(var i=0,len=features.length;i<len;++i){geom=features[i].geometry;if(geom){geom.transform(remote,local);}}}
-layer.addFeatures(features);}
-layer.events.triggerEvent("loadend",{response:resp});},CLASS_NAME:"OpenLayers.Strategy.Fixed"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"\u2212",zoomOutId:"olZoomOutLink",draw:function(){var div=OpenLayers.Control.prototype.draw.apply(this),links=this.getOrCreateLinks(div),zoomIn=links.zoomIn,zoomOut=links.zoomOut,eventsInstance=this.map.events;if(zoomOut.parentNode!==div){eventsInstance=this.events;eventsInstance.attachToElement(zoomOut.parentNode);}
-eventsInstance.register("buttonclick",this,this.onZoomClick);this.zoomInLink=zoomIn;this.zoomOutLink=zoomOut;return div;},getOrCreateLinks:function(el){var zoomIn=document.getElementById(this.zoomInId),zoomOut=document.getElementById(this.zoomOutId);if(!zoomIn){zoomIn=document.createElement("a");zoomIn.href="#zoomIn";zoomIn.appendChild(document.createTextNode(this.zoomInText));zoomIn.className="olControlZoomIn";el.appendChild(zoomIn);}
-OpenLayers.Element.addClass(zoomIn,"olButton");if(!zoomOut){zoomOut=document.createElement("a");zoomOut.href="#zoomOut";zoomOut.appendChild(document.createTextNode(this.zoomOutText));zoomOut.className="olControlZoomOut";el.appendChild(zoomOut);}
-OpenLayers.Element.addClass(zoomOut,"olButton");return{zoomIn:zoomIn,zoomOut:zoomOut};},onZoomClick:function(evt){var button=evt.buttonElement;if(button===this.zoomInLink){this.map.zoomIn();}else if(button===this.zoomOutLink){this.map.zoomOut();}},destroy:function(){if(this.map){this.map.events.unregister("buttonclick",this,this.onZoomClick);}
-delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this);},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Protocol=OpenLayers.Class({format:null,options:null,autoDestroy:true,defaultFilter:null,initialize:function(options){options=options||{};OpenLayers.Util.extend(this,options);this.options=options;},mergeWithDefaultFilter:function(filter){var merged;if(filter&&this.defaultFilter){merged=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.defaultFilter,filter]});}else{merged=filter||this.defaultFilter||undefined;}
-return merged;},destroy:function(){this.options=null;this.format=null;},read:function(options){options=options||{};options.filter=this.mergeWithDefaultFilter(options.filter);},create:function(){},update:function(){},"delete":function(){},commit:function(){},abort:function(response){},createCallback:function(method,response,options){return OpenLayers.Function.bind(function(){method.apply(this,[response,options]);},this);},CLASS_NAME:"OpenLayers.Protocol"});OpenLayers.Protocol.Response=OpenLayers.Class({code:null,requestType:null,last:true,features:null,data:null,reqFeatures:null,priv:null,error:null,initialize:function(options){OpenLayers.Util.extend(this,options);},success:function(){return this.code>0;},CLASS_NAME:"OpenLayers.Protocol.Response"});OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Protocol.WFS=function(options){options=OpenLayers.Util.applyDefaults(options,OpenLayers.Protocol.WFS.DEFAULTS);var cls=OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g,"_")];if(!cls){throw"Unsupported WFS version: "+options.version;}
-return new cls(options);};OpenLayers.Protocol.WFS.fromWMSLayer=function(layer,options){var typeName,featurePrefix;var param=layer.params["LAYERS"];var parts=(OpenLayers.Util.isArray(param)?param[0]:param).split(":");if(parts.length>1){featurePrefix=parts[0];}
-typeName=parts.pop();var protocolOptions={url:layer.url,featureType:typeName,featurePrefix:featurePrefix,srsName:layer.projection&&layer.projection.getCode()||layer.map&&layer.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(options,protocolOptions));};OpenLayers.Protocol.WFS.DEFAULTS={"version":"1.0.0"};OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,markers:null,drawn:false,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[];},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0,len=this.markers.length;i<len;i++){this.markers[i].setOpacity(this.opacity);}}},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);if(zoomChanged||!this.drawn){for(var i=0,len=this.markers.length;i<len;i++){this.drawMarker(this.markers[i]);}
-this.drawn=true;}},addMarker:function(marker){this.markers.push(marker);if(this.opacity<1){marker.setOpacity(this.opacity);}
-if(this.map&&this.map.getExtent()){marker.map=this.map;this.drawMarker(marker);}},removeMarker:function(marker){if(this.markers&&this.markers.length){OpenLayers.Util.removeItem(this.markers,marker);marker.erase();}},clearMarkers:function(){if(this.markers!=null){while(this.markers.length>0){this.removeMarker(this.markers[0]);}}},drawMarker:function(marker){var px=this.map.getLayerPxFromLonLat(marker.lonlat);if(px==null){marker.display(false);}else{if(!marker.isDrawn()){var markerImg=marker.draw(px);this.div.appendChild(markerImg);}else if(marker.icon){marker.icon.moveTo(px);}}},getDataExtent:function(){var maxExtent=null;if(this.markers&&(this.markers.length>0)){var maxExtent=new OpenLayers.Bounds();for(var i=0,len=this.markers.length;i<len;i++){var marker=this.markers[i];maxExtent.extend(marker.lonlat);}}
-return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Markers"});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);}});(function(){var oXMLHttpRequest=window.XMLHttpRequest;var bGecko=!!window.controllers,bIE=window.document.all&&!window.opera,bIE7=bIE&&window.navigator.userAgent.match(/MSIE 7.0/);function fXMLHttpRequest(){this._object=oXMLHttpRequest&&!bIE7?new oXMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[];};function cXMLHttpRequest(){return new fXMLHttpRequest;};cXMLHttpRequest.prototype=fXMLHttpRequest.prototype;if(bGecko&&oXMLHttpRequest.wrapped)
-cXMLHttpRequest.wrapped=oXMLHttpRequest.wrapped;cXMLHttpRequest.UNSENT=0;cXMLHttpRequest.OPENED=1;cXMLHttpRequest.HEADERS_RECEIVED=2;cXMLHttpRequest.LOADING=3;cXMLHttpRequest.DONE=4;cXMLHttpRequest.prototype.readyState=cXMLHttpRequest.UNSENT;cXMLHttpRequest.prototype.responseText='';cXMLHttpRequest.prototype.responseXML=null;cXMLHttpRequest.prototype.status=0;cXMLHttpRequest.prototype.statusText='';cXMLHttpRequest.prototype.priority="NORMAL";cXMLHttpRequest.prototype.onreadystatechange=null;cXMLHttpRequest.onreadystatechange=null;cXMLHttpRequest.onopen=null;cXMLHttpRequest.onsend=null;cXMLHttpRequest.onabort=null;cXMLHttpRequest.prototype.open=function(sMethod,sUrl,bAsync,sUser,sPassword){delete this._headers;if(arguments.length<3)
-bAsync=true;this._async=bAsync;var oRequest=this,nState=this.readyState,fOnUnload;if(bIE&&bAsync){fOnUnload=function(){if(nState!=cXMLHttpRequest.DONE){fCleanTransport(oRequest);oRequest.abort();}};window.attachEvent("onunload",fOnUnload);}
-if(cXMLHttpRequest.onopen)
-cXMLHttpRequest.onopen.apply(this,arguments);if(arguments.length>4)
-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.readyState<cXMLHttpRequest.DONE){oRequest.readyState++;fReadyStateChange(oRequest);if(oRequest._aborted)
-return;}}};cXMLHttpRequest.prototype.send=function(vData){if(cXMLHttpRequest.onsend)
-cXMLHttpRequest.onsend.apply(this,arguments);if(!arguments.length)
-vData=null;if(vData&&vData.nodeType){vData=window.XMLSerializer?new window.XMLSerializer().serializeToString(vData):vData.xml;if(!this._headers["Content-Type"])
-this._object.setRequestHeader("Content-Type","application/xml");}
-this._data=vData;fXMLHttpRequest_send(this);};cXMLHttpRequest.prototype.abort=function(){if(cXMLHttpRequest.onabort)
-cXMLHttpRequest.onabort.apply(this,arguments);if(this.readyState>cXMLHttpRequest.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.Format.KML=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{kml:"http://www.opengis.net/kml/2.2",gx:"http://www.google.com/kml/ext/2.2"},kmlns:"http://earth.google.com/kml/2.0",placemarksDesc:"No description available",foldersName:"OpenLayers export",foldersDesc:"Exported on "+new Date(),extractAttributes:true,kvpAttributes:false,extractStyles:false,extractTracks:false,trackAttributes:null,internalns:null,features:null,styles:null,styleBaseUrl:"",fetched:null,maxDepth:0,initialize:function(options){this.regExes={trimSpace:(/^\s*|\s*$/g),removeSpace:(/\s*/g),splitSpace:(/\s+/),trimComma:(/\s*,\s*/g),kmlColor:(/(\w{2})(\w{2})(\w{2})(\w{2})/),kmlIconPalette:(/root:\/\/icons\/palette-(\d+)(\.\w+)/),straightBracket:(/\$\[(.*?)\]/g)};this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[options]);},read:function(data){this.features=[];this.styles={};this.fetched={};var options={depth:0,styleBaseUrl:this.styleBaseUrl};return this.parseData(data,options);},parseData:function(data,options){if(typeof data=="string"){data=OpenLayers.Format.XML.prototype.read.apply(this,[data]);}
-var types=["Link","NetworkLink","Style","StyleMap","Placemark"];for(var i=0,len=types.length;i<len;++i){var type=types[i];var nodes=this.getElementsByTagNameNS(data,"*",type);if(nodes.length==0){continue;}
-switch(type.toLowerCase()){case"link":case"networklink":this.parseLinks(nodes,options);break;case"style":if(this.extractStyles){this.parseStyles(nodes,options);}
-break;case"stylemap":if(this.extractStyles){this.parseStyleMaps(nodes,options);}
-break;case"placemark":this.parseFeatures(nodes,options);break;}}
-return this.features;},parseLinks:function(nodes,options){if(options.depth>=this.maxDepth){return false;}
-var newOptions=OpenLayers.Util.extend({},options);newOptions.depth++;for(var i=0,len=nodes.length;i<len;i++){var href=this.parseProperty(nodes[i],"*","href");if(href&&!this.fetched[href]){this.fetched[href]=true;var data=this.fetchLink(href);if(data){this.parseData(data,newOptions);}}}},fetchLink:function(href){var request=OpenLayers.Request.GET({url:href,async:false});if(request){return request.responseText;}},parseStyles:function(nodes,options){for(var i=0,len=nodes.length;i<len;i++){var style=this.parseStyle(nodes[i]);if(style){var styleName=(options.styleBaseUrl||"")+"#"+style.id;this.styles[styleName]=style;}}},parseKmlColor:function(kmlColor){var color=null;if(kmlColor){var matches=kmlColor.match(this.regExes.kmlColor);if(matches){color={color:'#'+matches[4]+matches[3]+matches[2],opacity:parseInt(matches[1],16)/255};}}
-return color;},parseStyle:function(node){var style={};var types=["LineStyle","PolyStyle","IconStyle","BalloonStyle","LabelStyle"];var type,styleTypeNode,nodeList,geometry,parser;for(var i=0,len=types.length;i<len;++i){type=types[i];styleTypeNode=this.getElementsByTagNameNS(node,"*",type)[0];if(!styleTypeNode){continue;}
-switch(type.toLowerCase()){case"linestyle":var kmlColor=this.parseProperty(styleTypeNode,"*","color");var color=this.parseKmlColor(kmlColor);if(color){style["strokeColor"]=color.color;style["strokeOpacity"]=color.opacity;}
-var width=this.parseProperty(styleTypeNode,"*","width");if(width){style["strokeWidth"]=width;}
-break;case"polystyle":var kmlColor=this.parseProperty(styleTypeNode,"*","color");var color=this.parseKmlColor(kmlColor);if(color){style["fillOpacity"]=color.opacity;style["fillColor"]=color.color;}
-var fill=this.parseProperty(styleTypeNode,"*","fill");if(fill=="0"){style["fillColor"]="none";}
-var outline=this.parseProperty(styleTypeNode,"*","outline");if(outline=="0"){style["strokeWidth"]="0";}
-break;case"iconstyle":var scale=parseFloat(this.parseProperty(styleTypeNode,"*","scale")||1);var width=32*scale;var height=32*scale;var iconNode=this.getElementsByTagNameNS(styleTypeNode,"*","Icon")[0];if(iconNode){var href=this.parseProperty(iconNode,"*","href");if(href){var w=this.parseProperty(iconNode,"*","w");var h=this.parseProperty(iconNode,"*","h");var google="http://maps.google.com/mapfiles/kml";if(OpenLayers.String.startsWith(href,google)&&!w&&!h){w=64;h=64;scale=scale/2;}
-w=w||h;h=h||w;if(w){width=parseInt(w)*scale;}
-if(h){height=parseInt(h)*scale;}
-var matches=href.match(this.regExes.kmlIconPalette);if(matches){var palette=matches[1];var file_extension=matches[2];var x=this.parseProperty(iconNode,"*","x");var y=this.parseProperty(iconNode,"*","y");var posX=x?x/32:0;var posY=y?(7-y/32):7;var pos=posY*8+posX;href="http://maps.google.com/mapfiles/kml/pal"
-+palette+"/icon"+pos+file_extension;}
-style["graphicOpacity"]=1;style["externalGraphic"]=href;}}
-var hotSpotNode=this.getElementsByTagNameNS(styleTypeNode,"*","hotSpot")[0];if(hotSpotNode){var x=parseFloat(hotSpotNode.getAttribute("x"));var y=parseFloat(hotSpotNode.getAttribute("y"));var xUnits=hotSpotNode.getAttribute("xunits");if(xUnits=="pixels"){style["graphicXOffset"]=-x*scale;}
-else if(xUnits=="insetPixels"){style["graphicXOffset"]=-width+(x*scale);}
-else if(xUnits=="fraction"){style["graphicXOffset"]=-width*x;}
-var yUnits=hotSpotNode.getAttribute("yunits");if(yUnits=="pixels"){style["graphicYOffset"]=-height+(y*scale)+1;}
-else if(yUnits=="insetPixels"){style["graphicYOffset"]=-(y*scale)+1;}
-else if(yUnits=="fraction"){style["graphicYOffset"]=-height*(1-y)+1;}}
-style["graphicWidth"]=width;style["graphicHeight"]=height;break;case"balloonstyle":var balloonStyle=OpenLayers.Util.getXmlNodeValue(styleTypeNode);if(balloonStyle){style["balloonStyle"]=balloonStyle.replace(this.regExes.straightBracket,"${$1}");}
-break;case"labelstyle":var kmlColor=this.parseProperty(styleTypeNode,"*","color");var color=this.parseKmlColor(kmlColor);if(color){style["fontColor"]=color.color;style["fontOpacity"]=color.opacity;}
-break;default:}}
-if(!style["strokeColor"]&&style["fillColor"]){style["strokeColor"]=style["fillColor"];}
-var id=node.getAttribute("id");if(id&&style){style.id=id;}
-return style;},parseStyleMaps:function(nodes,options){for(var i=0,len=nodes.length;i<len;i++){var node=nodes[i];var pairs=this.getElementsByTagNameNS(node,"*","Pair");var id=node.getAttribute("id");for(var j=0,jlen=pairs.length;j<jlen;j++){var pair=pairs[j];var key=this.parseProperty(pair,"*","key");var styleUrl=this.parseProperty(pair,"*","styleUrl");if(styleUrl&&key=="normal"){this.styles[(options.styleBaseUrl||"")+"#"+id]=this.styles[(options.styleBaseUrl||"")+styleUrl];}}}},parseFeatures:function(nodes,options){var features=[];for(var i=0,len=nodes.length;i<len;i++){var featureNode=nodes[i];var feature=this.parseFeature.apply(this,[featureNode]);if(feature){if(this.extractStyles&&feature.attributes&&feature.attributes.styleUrl){feature.style=this.getStyle(feature.attributes.styleUrl,options);}
-if(this.extractStyles){var inlineStyleNode=this.getElementsByTagNameNS(featureNode,"*","Style")[0];if(inlineStyleNode){var inlineStyle=this.parseStyle(inlineStyleNode);if(inlineStyle){feature.style=OpenLayers.Util.extend(feature.style,inlineStyle);}}}
-if(this.extractTracks){var tracks=this.getElementsByTagNameNS(featureNode,this.namespaces.gx,"Track");if(tracks&&tracks.length>0){var track=tracks[0];var container={features:[],feature:feature};this.readNode(track,container);if(container.features.length>0){features.push.apply(features,container.features);}}}else{features.push(feature);}}else{throw"Bad Placemark: "+i;}}
-this.features=this.features.concat(features);},readers:{"kml":{"when":function(node,container){container.whens.push(OpenLayers.Date.parse(this.getChildValue(node)));},"_trackPointAttribute":function(node,container){var name=node.nodeName.split(":").pop();container.attributes[name].push(this.getChildValue(node));}},"gx":{"Track":function(node,container){var obj={whens:[],points:[],angles:[]};if(this.trackAttributes){var name;obj.attributes={};for(var i=0,ii=this.trackAttributes.length;i<ii;++i){name=this.trackAttributes[i];obj.attributes[name]=[];if(!(name in this.readers.kml)){this.readers.kml[name]=this.readers.kml._trackPointAttribute;}}}
-this.readChildNodes(node,obj);if(obj.whens.length!==obj.points.length){throw new Error("gx:Track with unequal number of when ("+
-obj.whens.length+") and gx:coord ("+
-obj.points.length+") elements.");}
-var hasAngles=obj.angles.length>0;if(hasAngles&&obj.whens.length!==obj.angles.length){throw new Error("gx:Track with unequal number of when ("+
-obj.whens.length+") and gx:angles ("+
-obj.angles.length+") elements.");}
-var feature,point,angles;for(var i=0,ii=obj.whens.length;i<ii;++i){feature=container.feature.clone();feature.fid=container.feature.fid||container.feature.id;point=obj.points[i];feature.geometry=point;if("z"in point){feature.attributes.altitude=point.z;}
-if(this.internalProjection&&this.externalProjection){feature.geometry.transform(this.externalProjection,this.internalProjection);}
-if(this.trackAttributes){for(var j=0,jj=this.trackAttributes.length;j<jj;++j){var name=this.trackAttributes[j];feature.attributes[name]=obj.attributes[name][i];}}
-feature.attributes.when=obj.whens[i];feature.attributes.trackId=container.feature.id;if(hasAngles){angles=obj.angles[i];feature.attributes.heading=parseFloat(angles[0]);feature.attributes.tilt=parseFloat(angles[1]);feature.attributes.roll=parseFloat(angles[2]);}
-container.features.push(feature);}},"coord":function(node,container){var str=this.getChildValue(node);var coords=str.replace(this.regExes.trimSpace,"").split(/\s+/);var point=new OpenLayers.Geometry.Point(coords[0],coords[1]);if(coords.length>2){point.z=parseFloat(coords[2]);}
-container.points.push(point);},"angles":function(node,container){var str=this.getChildValue(node);var parts=str.replace(this.regExes.trimSpace,"").split(/\s+/);container.angles.push(parts);}}},parseFeature:function(node){var order=["MultiGeometry","Polygon","LineString","Point"];var type,nodeList,geometry,parser;for(var i=0,len=order.length;i<len;++i){type=order[i];this.internalns=node.namespaceURI?node.namespaceURI:this.kmlns;nodeList=this.getElementsByTagNameNS(node,this.internalns,type);if(nodeList.length>0){var parser=this.parseGeometry[type.toLowerCase()];if(parser){geometry=parser.apply(this,[nodeList[0]]);if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}}else{throw new TypeError("Unsupported geometry type: "+type);}
-break;}}
-var attributes;if(this.extractAttributes){attributes=this.parseAttributes(node);}
-var feature=new OpenLayers.Feature.Vector(geometry,attributes);var fid=node.getAttribute("id")||node.getAttribute("name");if(fid!=null){feature.fid=fid;}
-return feature;},getStyle:function(styleUrl,options){var styleBaseUrl=OpenLayers.Util.removeTail(styleUrl);var newOptions=OpenLayers.Util.extend({},options);newOptions.depth++;newOptions.styleBaseUrl=styleBaseUrl;if(!this.styles[styleUrl]&&!OpenLayers.String.startsWith(styleUrl,"#")&&newOptions.depth<=this.maxDepth&&!this.fetched[styleBaseUrl]){var data=this.fetchLink(styleBaseUrl);if(data){this.parseData(data,newOptions);}}
-var style=OpenLayers.Util.extend({},this.styles[styleUrl]);return style;},parseGeometry:{point:function(node){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"coordinates");var coords=[];if(nodeList.length>0){var coordString=nodeList[0].firstChild.nodeValue;coordString=coordString.replace(this.regExes.removeSpace,"");coords=coordString.split(",");}
-var point=null;if(coords.length>1){if(coords.length==2){coords[2]=null;}
-point=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{throw"Bad coordinate string: "+coordString;}
-return point;},linestring:function(node,ring){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"coordinates");var line=null;if(nodeList.length>0){var coordString=this.getChildValue(nodeList[0]);coordString=coordString.replace(this.regExes.trimSpace,"");coordString=coordString.replace(this.regExes.trimComma,",");var pointList=coordString.split(this.regExes.splitSpace);var numPoints=pointList.length;var points=new Array(numPoints);var coords,numCoords;for(var i=0;i<numPoints;++i){coords=pointList[i].split(",");numCoords=coords.length;if(numCoords>1){if(coords.length==2){coords[2]=null;}
-points[i]=new OpenLayers.Geometry.Point(coords[0],coords[1],coords[2]);}else{throw"Bad LineString point coordinates: "+
-pointList[i];}}
-if(numPoints){if(ring){line=new OpenLayers.Geometry.LinearRing(points);}else{line=new OpenLayers.Geometry.LineString(points);}}else{throw"Bad LineString coordinates: "+coordString;}}
-return line;},polygon:function(node){var nodeList=this.getElementsByTagNameNS(node,this.internalns,"LinearRing");var numRings=nodeList.length;var components=new Array(numRings);if(numRings>0){var ring;for(var i=0,len=nodeList.length;i<len;++i){ring=this.parseGeometry.linestring.apply(this,[nodeList[i],true]);if(ring){components[i]=ring;}else{throw"Bad LinearRing geometry: "+i;}}}
-return new OpenLayers.Geometry.Polygon(components);},multigeometry:function(node){var child,parser;var parts=[];var children=node.childNodes;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){var type=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var parser=this.parseGeometry[type.toLowerCase()];if(parser){parts.push(parser.apply(this,[child]));}}}
-return new OpenLayers.Geometry.Collection(parts);}},parseAttributes:function(node){var attributes={};var edNodes=node.getElementsByTagName("ExtendedData");if(edNodes.length){attributes=this.parseExtendedData(edNodes[0]);}
-var child,grandchildren,grandchild;var children=node.childNodes;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){grandchildren=child.childNodes;if(grandchildren.length>=1&&grandchildren.length<=3){var grandchild;switch(grandchildren.length){case 1:grandchild=grandchildren[0];break;case 2:var c1=grandchildren[0];var c2=grandchildren[1];grandchild=(c1.nodeType==3||c1.nodeType==4)?c1:c2;break;case 3:default:grandchild=grandchildren[1];break;}
-if(grandchild.nodeType==3||grandchild.nodeType==4){var name=(child.prefix)?child.nodeName.split(":")[1]:child.nodeName;var value=OpenLayers.Util.getXmlNodeValue(grandchild);if(value){value=value.replace(this.regExes.trimSpace,"");attributes[name]=value;}}}}}
-return attributes;},parseExtendedData:function(node){var attributes={};var i,len,data,key;var dataNodes=node.getElementsByTagName("Data");for(i=0,len=dataNodes.length;i<len;i++){data=dataNodes[i];key=data.getAttribute("name");var ed={};var valueNode=data.getElementsByTagName("value");if(valueNode.length){ed['value']=this.getChildValue(valueNode[0]);}
-if(this.kvpAttributes){attributes[key]=ed['value'];}else{var nameNode=data.getElementsByTagName("displayName");if(nameNode.length){ed['displayName']=this.getChildValue(nameNode[0]);}
-attributes[key]=ed;}}
-var simpleDataNodes=node.getElementsByTagName("SimpleData");for(i=0,len=simpleDataNodes.length;i<len;i++){var ed={};data=simpleDataNodes[i];key=data.getAttribute("name");ed['value']=this.getChildValue(data);if(this.kvpAttributes){attributes[key]=ed['value'];}else{ed['displayName']=key;attributes[key]=ed;}}
-return attributes;},parseProperty:function(xmlNode,namespace,tagName){var value;var nodeList=this.getElementsByTagNameNS(xmlNode,namespace,tagName);try{value=OpenLayers.Util.getXmlNodeValue(nodeList[0]);}catch(e){value=null;}
-return value;},write:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
-var kml=this.createElementNS(this.kmlns,"kml");var folder=this.createFolderXML();for(var i=0,len=features.length;i<len;++i){folder.appendChild(this.createPlacemarkXML(features[i]));}
-kml.appendChild(folder);return OpenLayers.Format.XML.prototype.write.apply(this,[kml]);},createFolderXML:function(){var folder=this.createElementNS(this.kmlns,"Folder");if(this.foldersName){var folderName=this.createElementNS(this.kmlns,"name");var folderNameText=this.createTextNode(this.foldersName);folderName.appendChild(folderNameText);folder.appendChild(folderName);}
-if(this.foldersDesc){var folderDesc=this.createElementNS(this.kmlns,"description");var folderDescText=this.createTextNode(this.foldersDesc);folderDesc.appendChild(folderDescText);folder.appendChild(folderDesc);}
-return folder;},createPlacemarkXML:function(feature){var placemarkName=this.createElementNS(this.kmlns,"name");var label=(feature.style&&feature.style.label)?feature.style.label:feature.id;var name=feature.attributes.name||label;placemarkName.appendChild(this.createTextNode(name));var placemarkDesc=this.createElementNS(this.kmlns,"description");var desc=feature.attributes.description||this.placemarksDesc;placemarkDesc.appendChild(this.createTextNode(desc));var placemarkNode=this.createElementNS(this.kmlns,"Placemark");if(feature.fid!=null){placemarkNode.setAttribute("id",feature.fid);}
-placemarkNode.appendChild(placemarkName);placemarkNode.appendChild(placemarkDesc);var geometryNode=this.buildGeometryNode(feature.geometry);placemarkNode.appendChild(geometryNode);if(feature.attributes){var edNode=this.buildExtendedData(feature.attributes);if(edNode){placemarkNode.appendChild(edNode);}}
-return placemarkNode;},buildGeometryNode:function(geometry){var className=geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);var builder=this.buildGeometry[type.toLowerCase()];var node=null;if(builder){node=builder.apply(this,[geometry]);}
-return node;},buildGeometry:{point:function(geometry){var kml=this.createElementNS(this.kmlns,"Point");kml.appendChild(this.buildCoordinatesNode(geometry));return kml;},multipoint:function(geometry){return this.buildGeometry.collection.apply(this,[geometry]);},linestring:function(geometry){var kml=this.createElementNS(this.kmlns,"LineString");kml.appendChild(this.buildCoordinatesNode(geometry));return kml;},multilinestring:function(geometry){return this.buildGeometry.collection.apply(this,[geometry]);},linearring:function(geometry){var kml=this.createElementNS(this.kmlns,"LinearRing");kml.appendChild(this.buildCoordinatesNode(geometry));return kml;},polygon:function(geometry){var kml=this.createElementNS(this.kmlns,"Polygon");var rings=geometry.components;var ringMember,ringGeom,type;for(var i=0,len=rings.length;i<len;++i){type=(i==0)?"outerBoundaryIs":"innerBoundaryIs";ringMember=this.createElementNS(this.kmlns,type);ringGeom=this.buildGeometry.linearring.apply(this,[rings[i]]);ringMember.appendChild(ringGeom);kml.appendChild(ringMember);}
-return kml;},multipolygon:function(geometry){return this.buildGeometry.collection.apply(this,[geometry]);},collection:function(geometry){var kml=this.createElementNS(this.kmlns,"MultiGeometry");var child;for(var i=0,len=geometry.components.length;i<len;++i){child=this.buildGeometryNode.apply(this,[geometry.components[i]]);if(child){kml.appendChild(child);}}
-return kml;}},buildCoordinatesNode:function(geometry){var coordinatesNode=this.createElementNS(this.kmlns,"coordinates");var path;var points=geometry.components;if(points){var point;var numPoints=points.length;var parts=new Array(numPoints);for(var i=0;i<numPoints;++i){point=points[i];parts[i]=this.buildCoordinates(point);}
-path=parts.join(" ");}else{path=this.buildCoordinates(geometry);}
-var txtNode=this.createTextNode(path);coordinatesNode.appendChild(txtNode);return coordinatesNode;},buildCoordinates:function(point){if(this.internalProjection&&this.externalProjection){point=point.clone();point.transform(this.internalProjection,this.externalProjection);}
-return point.x+","+point.y;},buildExtendedData:function(attributes){var extendedData=this.createElementNS(this.kmlns,"ExtendedData");for(var attributeName in attributes){if(attributes[attributeName]&&attributeName!="name"&&attributeName!="description"&&attributeName!="styleUrl"){var data=this.createElementNS(this.kmlns,"Data");data.setAttribute("name",attributeName);var value=this.createElementNS(this.kmlns,"value");if(typeof attributes[attributeName]=="object"){if(attributes[attributeName].value){value.appendChild(this.createTextNode(attributes[attributeName].value));}
-if(attributes[attributeName].displayName){var displayName=this.createElementNS(this.kmlns,"displayName");displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName));data.appendChild(displayName);}}else{value.appendChild(this.createTextNode(attributes[attributeName]));}
-data.appendChild(value);extendedData.appendChild(data);}}
-if(this.isSimpleContent(extendedData)){return null;}else{return extendedData;}},CLASS_NAME:"OpenLayers.Format.KML"});OpenLayers.Protocol.WFS.v1=OpenLayers.Class(OpenLayers.Protocol,{version:null,srsName:"EPSG:4326",featureType:null,featureNS:null,geometryName:"the_geom",schema:null,featurePrefix:"feature",formatOptions:null,readFormat:null,readOptions:null,initialize:function(options){OpenLayers.Protocol.prototype.initialize.apply(this,[options]);if(!options.format){this.format=OpenLayers.Format.WFST(OpenLayers.Util.extend({version:this.version,featureType:this.featureType,featureNS:this.featureNS,featurePrefix:this.featurePrefix,geometryName:this.geometryName,srsName:this.srsName,schema:this.schema},this.formatOptions));}
-if(!options.geometryName&&parseFloat(this.format.version)>1.0){this.setGeometryName(null);}},destroy:function(){if(this.options&&!this.options.format){this.format.destroy();}
-this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this);},read:function(options){OpenLayers.Protocol.prototype.read.apply(this,arguments);options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options||{});var response=new OpenLayers.Protocol.Response({requestType:"read"});var data=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",options)]);response.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleRead,response,options),params:options.params,headers:options.headers,data:data});return response;},setFeatureType:function(featureType){this.featureType=featureType;this.format.featureType=featureType;},setGeometryName:function(geometryName){this.geometryName=geometryName;this.format.geometryName=geometryName;},handleRead:function(response,options){options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options);if(options.callback){var request=response.priv;if(request.status>=200&&request.status<300){var result=this.parseResponse(request,options.readOptions);if(result&&result.success!==false){if(options.readOptions&&options.readOptions.output=="object"){OpenLayers.Util.extend(response,result);}else{response.features=result;}
-response.code=OpenLayers.Protocol.Response.SUCCESS;}else{response.code=OpenLayers.Protocol.Response.FAILURE;response.error=result;}}else{response.code=OpenLayers.Protocol.Response.FAILURE;}
-options.callback.call(options.scope,response);}},parseResponse:function(request,options){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
-if(!doc||doc.length<=0){return null;}
-var result=(this.readFormat!==null)?this.readFormat.read(doc):this.format.read(doc,options);if(!this.featureNS){var format=this.readFormat||this.format;this.featureNS=format.featureNS;format.autoConfig=false;if(!this.geometryName){this.setGeometryName(format.geometryName);}}
-return result;},commit:function(features,options){options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options);var response=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:features});response.priv=OpenLayers.Request.POST({url:options.url,headers:options.headers,data:this.format.write(features,options),callback:this.createCallback(this.handleCommit,response,options)});return response;},handleCommit:function(response,options){if(options.callback){var request=response.priv;var data=request.responseXML;if(!data||!data.documentElement){data=request.responseText;}
-var obj=this.format.read(data)||{};response.insertIds=obj.insertIds||[];if(obj.success){response.code=OpenLayers.Protocol.Response.SUCCESS;}else{response.code=OpenLayers.Protocol.Response.FAILURE;response.error=obj;}
-options.callback.call(options.scope,response);}},filterDelete:function(filter,options){options=OpenLayers.Util.extend({},options);OpenLayers.Util.applyDefaults(options,this.options);var response=new OpenLayers.Protocol.Response({requestType:"commit"});var root=this.format.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version}});var deleteNode=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(options.featureNS?this.featurePrefix+":":"")+
-options.featureType}});if(options.featureNS){deleteNode.setAttribute("xmlns:"+this.featurePrefix,options.featureNS);}
-var filterNode=this.format.writeNode("ogc:Filter",filter);deleteNode.appendChild(filterNode);root.appendChild(deleteNode);var data=OpenLayers.Format.XML.prototype.write.apply(this.format,[root]);return OpenLayers.Request.POST({url:this.url,callback:options.callback||function(){},data:data});},abort:function(response){if(response){response.priv.abort();}},CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{'click':{'in':'click','out':'clickout'},'mousemove':{'in':'over','out':'out'},'dblclick':{'in':'dblclick','out':null},'mousedown':{'in':null,'out':null},'mouseup':{'in':null,'out':null},'touchstart':{'in':'click','out':'clickout'}},feature:null,lastFeature:null,down:null,up:null,clickTolerance:4,geometryTypes:null,stopClick:true,stopDown:true,stopUp:false,initialize:function(control,layer,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,[control,callbacks,options]);this.layer=layer;},touchstart:function(evt){this.startTouch();return OpenLayers.Event.isMultiTouch(evt)?true:this.mousedown(evt);},touchmove:function(evt){OpenLayers.Event.preventDefault(evt);},mousedown:function(evt){if(OpenLayers.Event.isLeftClick(evt)||OpenLayers.Event.isSingleTouch(evt)){this.down=evt.xy;}
-return this.handle(evt)?!this.stopDown:true;},mouseup:function(evt){this.up=evt.xy;return this.handle(evt)?!this.stopUp:true;},click:function(evt){return this.handle(evt)?!this.stopClick:true;},mousemove:function(evt){if(!this.callbacks['over']&&!this.callbacks['out']){return true;}
-this.handle(evt);return true;},dblclick:function(evt){return!this.handle(evt);},geometryTypeMatches:function(feature){return this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1;},handle:function(evt){if(this.feature&&!this.feature.layer){this.feature=null;}
-var type=evt.type;var handled=false;var previouslyIn=!!(this.feature);var click=(type=="click"||type=="dblclick"||type=="touchstart");this.feature=this.layer.getFeatureFromEvent(evt);if(this.feature&&!this.feature.layer){this.feature=null;}
-if(this.lastFeature&&!this.lastFeature.layer){this.lastFeature=null;}
-if(this.feature){if(type==="touchstart"){OpenLayers.Event.preventDefault(evt);}
-var inNew=(this.feature!=this.lastFeature);if(this.geometryTypeMatches(this.feature)){if(previouslyIn&&inNew){if(this.lastFeature){this.triggerCallback(type,'out',[this.lastFeature]);}
-this.triggerCallback(type,'in',[this.feature]);}else if(!previouslyIn||click){this.triggerCallback(type,'in',[this.feature]);}
-this.lastFeature=this.feature;handled=true;}else{if(this.lastFeature&&(previouslyIn&&inNew||click)){this.triggerCallback(type,'out',[this.lastFeature]);}
-this.feature=null;}}else if(this.lastFeature&&(previouslyIn||click)){this.triggerCallback(type,'out',[this.lastFeature]);}
-return handled;},triggerCallback:function(type,mode,args){var key=this.EVENTMAP[type][mode];if(key){if(type=='click'&&this.up&&this.down){var dpx=Math.sqrt(Math.pow(this.up.x-this.down.x,2)+
-Math.pow(this.up.y-this.down.y,2));if(dpx<=this.clickTolerance){this.callback(key,args);}
-this.up=this.down=null;}else{this.callback(key,args);}}},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});activated=true;}
-return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.feature=null;this.lastFeature=null;this.down=null;this.up=null;this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});deactivated=true;}
-return deactivated;},handleMapEvents:function(evt){if(evt.type=="removelayer"||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},moveLayerBack:function(){var index=this.layer.getZIndex()-1;if(index>=this.map.Z_INDEX_BASE['Feature']){this.layer.setZIndex(index);}else{this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer));}},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(style,options){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),"select":new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]),"temporary":new OpenLayers.Style(OpenLayers.Feature.Vector.style["temporary"]),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(style instanceof OpenLayers.Style){this.styles["default"]=style;this.styles["select"]=style;this.styles["temporary"]=style;this.styles["delete"]=style;}else if(typeof style=="object"){for(var key in style){if(style[key]instanceof OpenLayers.Style){this.styles[key]=style[key];}else if(typeof style[key]=="object"){this.styles[key]=new OpenLayers.Style(style[key]);}else{this.styles["default"]=new OpenLayers.Style(style);this.styles["select"]=new OpenLayers.Style(style);this.styles["temporary"]=new OpenLayers.Style(style);this.styles["delete"]=new OpenLayers.Style(style);break;}}}
-OpenLayers.Util.extend(this,options);},destroy:function(){for(var key in this.styles){this.styles[key].destroy();}
-this.styles=null;},createSymbolizer:function(feature,intent){if(!feature){feature=new OpenLayers.Feature.Vector();}
-if(!this.styles[intent]){intent="default";}
-feature.renderIntent=intent;var defaultSymbolizer={};if(this.extendDefault&&intent!="default"){defaultSymbolizer=this.styles["default"].createSymbolizer(feature);}
-return OpenLayers.Util.extend(defaultSymbolizer,this.styles[intent].createSymbolizer(feature));},addUniqueValueRules:function(renderIntent,property,symbolizers,context){var rules=[];for(var value in symbolizers){rules.push(new OpenLayers.Rule({symbolizer:symbolizers[value],context:context,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:property,value:value})}));}
-this.styles[renderIntent].addRules(rules);},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,isFixed:false,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:true,style:null,styleMap:null,strategies:null,protocol:null,renderers:['SVG','VML','Canvas'],renderer:null,rendererOptions:null,geometryType:null,drawn:false,ratio:1,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(!this.renderer||!this.renderer.supported()){this.assignRenderer();}
-if(!this.renderer||!this.renderer.supported()){this.renderer=null;this.displayError();}
-if(!this.styleMap){this.styleMap=new OpenLayers.StyleMap();}
-this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies){for(var i=0,len=this.strategies.length;i<len;i++){this.strategies[i].setLayer(this);}}},destroy:function(){if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoDestroy){strategy.destroy();}}
-this.strategies=null;}
-if(this.protocol){if(this.protocol.autoDestroy){this.protocol.destroy();}
-this.protocol=null;}
-this.destroyFeatures();this.features=null;this.selectedFeatures=null;this.unrenderedFeatures=null;if(this.renderer){this.renderer.destroy();}
-this.renderer=null;this.geometryType=null;this.drawn=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Vector(this.name,this.getOptions());}
-obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);var features=this.features;var len=features.length;var clonedFeatures=new Array(len);for(var i=0;i<len;++i){clonedFeatures[i]=features[i].clone();}
-obj.features=clonedFeatures;return obj;},refresh:function(obj){if(this.calculateInRange()&&this.visibility){this.events.triggerEvent("refresh",obj);}},assignRenderer:function(){for(var i=0,len=this.renderers.length;i<len;i++){var rendererClass=this.renderers[i];var renderer=(typeof rendererClass=="function")?rendererClass:OpenLayers.Renderer[rendererClass];if(renderer&&renderer.prototype.supported()){this.renderer=new renderer(this.div,this.rendererOptions);break;}}},displayError:function(){if(this.reportError){OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",{renderers:this.renderers.join('\n')}));}},setMap:function(map){OpenLayers.Layer.prototype.setMap.apply(this,arguments);if(!this.renderer){this.map.removeLayer(this);}else{this.renderer.map=this.map;var newSize=this.map.getSize();newSize.w=newSize.w*this.ratio;newSize.h=newSize.h*this.ratio;this.renderer.setSize(newSize);}},afterAdd:function(){if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoActivate){strategy.activate();}}}},removeMap:function(map){this.drawn=false;if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoActivate){strategy.deactivate();}}}},onMapResize:function(){OpenLayers.Layer.prototype.onMapResize.apply(this,arguments);var newSize=this.map.getSize();newSize.w=newSize.w*this.ratio;newSize.h=newSize.h*this.ratio;this.renderer.setSize(newSize);},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var coordSysUnchanged=true;if(!dragging){this.renderer.root.style.visibility='hidden';var viewSize=this.map.getSize(),viewWidth=viewSize.w,viewHeight=viewSize.h,offsetLeft=(viewWidth/2*this.ratio)-viewWidth/2,offsetTop=(viewHeight/2*this.ratio)-viewHeight/2;offsetLeft+=this.map.layerContainerOriginPx.x;offsetLeft=-Math.round(offsetLeft);offsetTop+=this.map.layerContainerOriginPx.y;offsetTop=-Math.round(offsetTop);this.div.style.left=offsetLeft+'px';this.div.style.top=offsetTop+'px';var extent=this.map.getExtent().scale(this.ratio);coordSysUnchanged=this.renderer.setExtent(extent,zoomChanged);this.renderer.root.style.visibility='visible';if(OpenLayers.IS_GECKO===true){this.div.scrollLeft=this.div.scrollLeft;}
-if(!zoomChanged&&coordSysUnchanged){for(var i in this.unrenderedFeatures){var feature=this.unrenderedFeatures[i];this.drawFeature(feature);}}}
-if(!this.drawn||zoomChanged||!coordSysUnchanged){this.drawn=true;var feature;for(var i=0,len=this.features.length;i<len;i++){this.renderer.locked=(i!==(len-1));feature=this.features[i];this.drawFeature(feature);}}},display:function(display){OpenLayers.Layer.prototype.display.apply(this,arguments);var currentDisplay=this.div.style.display;if(currentDisplay!=this.renderer.root.style.display){this.renderer.root.style.display=currentDisplay;}},addFeatures:function(features,options){if(!(OpenLayers.Util.isArray(features))){features=[features];}
-var notify=!options||!options.silent;if(notify){var event={features:features};var ret=this.events.triggerEvent("beforefeaturesadded",event);if(ret===false){return;}
-features=event.features;}
-var featuresAdded=[];for(var i=0,len=features.length;i<len;i++){if(i!=(features.length-1)){this.renderer.locked=true;}else{this.renderer.locked=false;}
-var feature=features[i];if(this.geometryType&&!(feature.geometry instanceof this.geometryType)){throw new TypeError('addFeatures: component should be an '+
-this.geometryType.prototype.CLASS_NAME);}
-feature.layer=this;if(!feature.style&&this.style){feature.style=OpenLayers.Util.extend({},this.style);}
-if(notify){if(this.events.triggerEvent("beforefeatureadded",{feature:feature})===false){continue;}
-this.preFeatureInsert(feature);}
-featuresAdded.push(feature);this.features.push(feature);this.drawFeature(feature);if(notify){this.events.triggerEvent("featureadded",{feature:feature});this.onFeatureInsert(feature);}}
-if(notify){this.events.triggerEvent("featuresadded",{features:featuresAdded});}},removeFeatures:function(features,options){if(!features||features.length===0){return;}
-if(features===this.features){return this.removeAllFeatures(options);}
-if(!(OpenLayers.Util.isArray(features))){features=[features];}
-if(features===this.selectedFeatures){features=features.slice();}
-var notify=!options||!options.silent;if(notify){this.events.triggerEvent("beforefeaturesremoved",{features:features});}
-for(var i=features.length-1;i>=0;i--){if(i!=0&&features[i-1].geometry){this.renderer.locked=true;}else{this.renderer.locked=false;}
-var feature=features[i];delete this.unrenderedFeatures[feature.id];if(notify){this.events.triggerEvent("beforefeatureremoved",{feature:feature});}
-this.features=OpenLayers.Util.removeItem(this.features,feature);feature.layer=null;if(feature.geometry){this.renderer.eraseFeatures(feature);}
-if(OpenLayers.Util.indexOf(this.selectedFeatures,feature)!=-1){OpenLayers.Util.removeItem(this.selectedFeatures,feature);}
-if(notify){this.events.triggerEvent("featureremoved",{feature:feature});}}
-if(notify){this.events.triggerEvent("featuresremoved",{features:features});}},removeAllFeatures:function(options){var notify=!options||!options.silent;var features=this.features;if(notify){this.events.triggerEvent("beforefeaturesremoved",{features:features});}
-var feature;for(var i=features.length-1;i>=0;i--){feature=features[i];if(notify){this.events.triggerEvent("beforefeatureremoved",{feature:feature});}
-feature.layer=null;if(notify){this.events.triggerEvent("featureremoved",{feature:feature});}}
-this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures=[];if(notify){this.events.triggerEvent("featuresremoved",{features:features});}},destroyFeatures:function(features,options){var all=(features==undefined);if(all){features=this.features;}
-if(features){this.removeFeatures(features,options);for(var i=features.length-1;i>=0;i--){features[i].destroy();}}},drawFeature:function(feature,style){if(!this.drawn){return;}
-if(typeof style!="object"){if(!style&&feature.state===OpenLayers.State.DELETE){style="delete";}
-var renderIntent=style||feature.renderIntent;style=feature.style||this.style;if(!style){style=this.styleMap.createSymbolizer(feature,renderIntent);}}
-var drawn=this.renderer.drawFeature(feature,style);if(drawn===false||drawn===null){this.unrenderedFeatures[feature.id]=feature;}else{delete this.unrenderedFeatures[feature.id];}},eraseFeatures:function(features){this.renderer.eraseFeatures(features);},getFeatureFromEvent:function(evt){if(!this.renderer){throw new Error('getFeatureFromEvent called on layer with no '+'renderer. This usually means you destroyed a '+'layer, but not some handler which is associated '+'with it.');}
-var feature=null;var featureId=this.renderer.getFeatureIdFromEvent(evt);if(featureId){if(typeof featureId==="string"){feature=this.getFeatureById(featureId);}else{feature=featureId;}}
-return feature;},getFeatureBy:function(property,value){var feature=null;for(var i=0,len=this.features.length;i<len;++i){if(this.features[i][property]==value){feature=this.features[i];break;}}
-return feature;},getFeatureById:function(featureId){return this.getFeatureBy('id',featureId);},getFeatureByFid:function(featureFid){return this.getFeatureBy('fid',featureFid);},getFeaturesByAttribute:function(attrName,attrValue){var i,feature,len=this.features.length,foundFeatures=[];for(i=0;i<len;i++){feature=this.features[i];if(feature&&feature.attributes){if(feature.attributes[attrName]===attrValue){foundFeatures.push(feature);}}}
-return foundFeatures;},onFeatureInsert:function(feature){},preFeatureInsert:function(feature){},getDataExtent:function(){var maxExtent=null;var features=this.features;if(features&&(features.length>0)){var geometry=null;for(var i=0,len=features.length;i<len;i++){geometry=features[i].geometry;if(geometry){if(maxExtent===null){maxExtent=new OpenLayers.Bounds();}
-maxExtent.extend(geometry.getBounds());}}}
-return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.Vector.RootContainer=OpenLayers.Class(OpenLayers.Layer.Vector,{displayInLayerSwitcher:false,layers:null,display:function(){},getFeatureFromEvent:function(evt){var layers=this.layers;var feature;for(var i=0;i<layers.length;i++){feature=layers[i].getFeatureFromEvent(evt);if(feature){return feature;}}},setMap:function(map){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);this.collectRoots();map.events.register("changelayer",this,this.handleChangeLayer);},removeMap:function(map){map.events.unregister("changelayer",this,this.handleChangeLayer);this.resetRoots();OpenLayers.Layer.Vector.prototype.removeMap.apply(this,arguments);},collectRoots:function(){var layer;for(var i=0;i<this.map.layers.length;++i){layer=this.map.layers[i];if(OpenLayers.Util.indexOf(this.layers,layer)!=-1){layer.renderer.moveRoot(this.renderer);}}},resetRoots:function(){var layer;for(var i=0;i<this.layers.length;++i){layer=this.layers[i];if(this.renderer&&layer.renderer.getRenderLayerId()==this.id){this.renderer.moveRoot(layer.renderer);}}},handleChangeLayer:function(evt){var layer=evt.layer;if(evt.property=="order"&&OpenLayers.Util.indexOf(this.layers,layer)!=-1){this.resetRoots();this.collectRoots();}},CLASS_NAME:"OpenLayers.Layer.Vector.RootContainer"});OpenLayers.Control.SelectFeature=OpenLayers.Class(OpenLayers.Control,{multipleKey:null,toggleKey:null,multiple:false,clickout:true,toggle:false,hover:false,highlightOnly:false,box:false,onBeforeSelect:function(){},onSelect:function(){},onUnselect:function(){},scope:null,geometryTypes:null,layer:null,layers:null,callbacks:null,selectStyle:null,renderIntent:"select",handlers:null,initialize:function(layers,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);if(this.scope===null){this.scope=this;}
-this.initLayer(layers);var callbacks={click:this.clickFeature,clickout:this.clickoutFeature};if(this.hover){callbacks.over=this.overFeature;callbacks.out=this.outFeature;}
-this.callbacks=OpenLayers.Util.extend(callbacks,this.callbacks);this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};if(this.box){this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"});}},initLayer:function(layers){if(OpenLayers.Util.isArray(layers)){this.layers=layers;this.layer=new OpenLayers.Layer.Vector.RootContainer(this.id+"_container",{layers:layers});}else{this.layer=layers;}},destroy:function(){if(this.active&&this.layers){this.map.removeLayer(this.layer);}
-OpenLayers.Control.prototype.destroy.apply(this,arguments);if(this.layers){this.layer.destroy();}},activate:function(){if(!this.active){if(this.layers){this.map.addLayer(this.layer);}
-this.handlers.feature.activate();if(this.box&&this.handlers.box){this.handlers.box.activate();}}
-return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){if(this.active){this.handlers.feature.deactivate();if(this.handlers.box){this.handlers.box.deactivate();}
-if(this.layers){this.map.removeLayer(this.layer);}}
-return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},unselectAll:function(options){var layers=this.layers||[this.layer],layer,feature,l,numExcept;for(l=0;l<layers.length;++l){layer=layers[l];numExcept=0;if(layer.selectedFeatures!=null){while(layer.selectedFeatures.length>numExcept){feature=layer.selectedFeatures[numExcept];if(!options||options.except!=feature){this.unselect(feature);}else{++numExcept;}}}}},clickFeature:function(feature){if(!this.hover){var selected=(OpenLayers.Util.indexOf(feature.layer.selectedFeatures,feature)>-1);if(selected){if(this.toggleSelect()){this.unselect(feature);}else if(!this.multipleSelect()){this.unselectAll({except:feature});}}else{if(!this.multipleSelect()){this.unselectAll({except:feature});}
-this.select(feature);}}},multipleSelect:function(){return this.multiple||(this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]);},toggleSelect:function(){return this.toggle||(this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]);},clickoutFeature:function(feature){if(!this.hover&&this.clickout){this.unselectAll();}},overFeature:function(feature){var layer=feature.layer;if(this.hover){if(this.highlightOnly){this.highlight(feature);}else if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}},outFeature:function(feature){if(this.hover){if(this.highlightOnly){if(feature._lastHighlighter==this.id){if(feature._prevHighlighter&&feature._prevHighlighter!=this.id){delete feature._lastHighlighter;var control=this.map.getControl(feature._prevHighlighter);if(control){control.highlight(feature);}}else{this.unhighlight(feature);}}}else{this.unselect(feature);}}},highlight:function(feature){var layer=feature.layer;var cont=this.events.triggerEvent("beforefeaturehighlighted",{feature:feature});if(cont!==false){feature._prevHighlighter=feature._lastHighlighter;feature._lastHighlighter=this.id;var style=this.selectStyle||this.renderIntent;layer.drawFeature(feature,style);this.events.triggerEvent("featurehighlighted",{feature:feature});}},unhighlight:function(feature){var layer=feature.layer;if(feature._prevHighlighter==undefined){delete feature._lastHighlighter;}else if(feature._prevHighlighter==this.id){delete feature._prevHighlighter;}else{feature._lastHighlighter=feature._prevHighlighter;delete feature._prevHighlighter;}
-layer.drawFeature(feature,feature.style||feature.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:feature});},select:function(feature){var cont=this.onBeforeSelect.call(this.scope,feature);var layer=feature.layer;if(cont!==false){cont=layer.events.triggerEvent("beforefeatureselected",{feature:feature});if(cont!==false){layer.selectedFeatures.push(feature);this.highlight(feature);if(!this.handlers.feature.lastFeature){this.handlers.feature.lastFeature=layer.selectedFeatures[0];}
-layer.events.triggerEvent("featureselected",{feature:feature});this.onSelect.call(this.scope,feature);}}},unselect:function(feature){var layer=feature.layer;this.unhighlight(feature);OpenLayers.Util.removeItem(layer.selectedFeatures,feature);layer.events.triggerEvent("featureunselected",{feature:feature});this.onUnselect.call(this.scope,feature);},selectBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);if(!this.multipleSelect()){this.unselectAll();}
-var prevMultiple=this.multiple;this.multiple=true;var layers=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:layers});var layer;for(var l=0;l<layers.length;++l){layer=layers[l];for(var i=0,len=layer.features.length;i<len;++i){var feature=layer.features[i];if(!feature.getVisibility()){continue;}
-if(this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1){if(bounds.toGeometry().intersects(feature.geometry)){if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}}}}
-this.multiple=prevMultiple;this.events.triggerEvent("boxselectionend",{layers:layers});}},setMap:function(map){this.handlers.feature.setMap(map);if(this.box){this.handlers.box.setMap(map);}
-OpenLayers.Control.prototype.setMap.apply(this,arguments);},setLayer:function(layers){var isActive=this.active;this.unselectAll();this.deactivate();if(this.layers){this.layer.destroy();this.layers=null;}
-this.initLayer(layers);this.handlers.feature.layer=this.layer;if(isActive){this.activate();}},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({"removelayer":this.updateAttribution,"addlayer":this.updateAttribution,"changelayer":this.updateAttribution,"changebaselayer":this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({'changebaselayer':this.updateAttribution,'changelayer':this.updateAttribution,'addlayer':this.updateAttribution,'removelayer':this.updateAttribution,scope:this});this.updateAttribution();return this.div;},updateAttribution:function(){var attributions=[];if(this.map&&this.map.layers){for(var i=0,len=this.map.layers.length;i<len;i++){var layer=this.map.layers[i];if(layer.attribution&&layer.getVisibility()){if(OpenLayers.Util.indexOf(attributions,layer.attribution)===-1){attributions.push(layer.attribution);}}}
-this.div.innerHTML=OpenLayers.String.format(this.template,{layers:attributions.join(this.separator)});}},CLASS_NAME:"OpenLayers.Control.Attribution"});OpenLayers.Kinetic=OpenLayers.Class({threshold:0,deceleration:0.0035,nbPoints:100,delay:200,points:undefined,timerId:undefined,initialize:function(options){OpenLayers.Util.extend(this,options);},begin:function(){OpenLayers.Animation.stop(this.timerId);this.timerId=undefined;this.points=[];},update:function(xy){this.points.unshift({xy:xy,tick:new Date().getTime()});if(this.points.length>this.nbPoints){this.points.pop();}},end:function(xy){var last,now=new Date().getTime();for(var i=0,l=this.points.length,point;i<l;i++){point=this.points[i];if(now-point.tick>this.delay){break;}
-last=point;}
-if(!last){return;}
-var time=new Date().getTime()-last.tick;var dist=Math.sqrt(Math.pow(xy.x-last.xy.x,2)+
-Math.pow(xy.y-last.xy.y,2));var speed=dist/time;if(speed==0||speed<this.threshold){return;}
-var theta=Math.asin((xy.y-last.xy.y)/dist);if(last.xy.x<=xy.x){theta=Math.PI-theta;}
-return{speed:speed,theta:theta};},move:function(info,callback){var v0=info.speed;var fx=Math.cos(info.theta);var fy=-Math.sin(info.theta);var initialTime=new Date().getTime();var lastX=0;var lastY=0;var timerCallback=function(){if(this.timerId==null){return;}
-var t=new Date().getTime()-initialTime;var p=(-this.deceleration*Math.pow(t,2))/2.0+v0*t;var x=p*fx;var y=p*fy;var args={};args.end=false;var v=-this.deceleration*t+v0;if(v<=0){OpenLayers.Animation.stop(this.timerId);this.timerId=null;args.end=true;}
-args.x=x-lastX;args.y=y-lastY;lastX=x;lastY=y;callback(args.x,args.y,args.end);};this.timerId=OpenLayers.Animation.start(OpenLayers.Function.bind(timerCallback,this));},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:true,encodeBBOX:false,noMagic:false,yx:{},initialize:function(name,url,params,options){var newArguments=[];params=OpenLayers.Util.upperCaseObject(params);if(parseFloat(params.VERSION)>=1.3&&!params.EXCEPTIONS){params.EXCEPTIONS="INIMAGE";}
-newArguments.push(name,url,params,options);OpenLayers.Layer.Grid.prototype.initialize.apply(this,newArguments);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(!this.noMagic&&this.params.TRANSPARENT&&this.params.TRANSPARENT.toString().toLowerCase()=="true"){if((options==null)||(!options.isBaseLayer)){this.isBaseLayer=false;}
-if(this.params.FORMAT=="image/jpeg"){this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png";}}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions());}
-obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},reverseAxisOrder:function(){var projCode=this.projection.getCode();return parseFloat(this.params.VERSION)>=1.3&&!!(this.yx[projCode]||(OpenLayers.Projection.defaults[projCode]&&OpenLayers.Projection.defaults[projCode].yx));},getURL:function(bounds){bounds=this.adjustBounds(bounds);var imageSize=this.getImageSize();var newParams={};var reverseAxisOrder=this.reverseAxisOrder();newParams.BBOX=this.encodeBBOX?bounds.toBBOX(null,reverseAxisOrder):bounds.toArray(reverseAxisOrder);newParams.WIDTH=imageSize.w;newParams.HEIGHT=imageSize.h;var requestString=this.getFullRequestString(newParams);return requestString;},mergeNewParams:function(newParams){var upperParams=OpenLayers.Util.upperCaseObject(newParams);var newArguments=[upperParams];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,newArguments);},getFullRequestString:function(newParams,altUrl){var mapProjection=this.map.getProjectionObject();var projectionCode=this.projection&&this.projection.equals(mapProjection)?this.projection.getCode():mapProjection.getCode();var value=(projectionCode=="none")?null:projectionCode;if(parseFloat(this.params.VERSION)>=1.3){this.params.CRS=value;}else{this.params.SRS=value;}
-if(typeof this.params.TRANSPARENT=="boolean"){newParams.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE";}
-return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments);},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15000,translationParameters:null,symbolMetrics:null,initialize:function(containerID){if(!this.supported()){return;}
-OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);this.translationParameters={x:0,y:0};this.symbolMetrics={};},supported:function(){var svgFeature="http://www.w3.org/TR/SVG11/feature#";return(document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature(svgFeature+"SVG","1.1")||document.implementation.hasFeature(svgFeature+"BasicStructure","1.1")));},inValidRange:function(x,y,xyOnly){var left=x+(xyOnly?0:this.translationParameters.x);var top=y+(xyOnly?0:this.translationParameters.y);return(left>=-this.MAX_PIXEL&&left<=this.MAX_PIXEL&&top>=-this.MAX_PIXEL&&top<=this.MAX_PIXEL);},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution(),left=-extent.left/resolution,top=extent.top/resolution;if(resolutionChanged){this.left=left;this.top=top;var extentString="0 0 "+this.size.w+" "+this.size.h;this.rendererRoot.setAttributeNS(null,"viewBox",extentString);this.translate(this.xOffset,0);return true;}else{var inRange=this.translate(left-this.left+this.xOffset,top-this.top);if(!inRange){this.setExtent(extent,true);}
-return coordSysUnchanged&&inRange;}},translate:function(x,y){if(!this.inValidRange(x,y,true)){return false;}else{var transformString="";if(x||y){transformString="translate("+x+","+y+")";}
-this.root.setAttributeNS(null,"transform",transformString);this.translationParameters={x:x,y:y};return true;}},setSize:function(size){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w);this.rendererRoot.setAttributeNS(null,"height",this.size.h);},getNodeType:function(geometry,style){var nodeType=null;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.externalGraphic){nodeType="image";}else if(this.isComplexSymbol(style.graphicName)){nodeType="svg";}else{nodeType="circle";}
-break;case"OpenLayers.Geometry.Rectangle":nodeType="rect";break;case"OpenLayers.Geometry.LineString":nodeType="polyline";break;case"OpenLayers.Geometry.LinearRing":nodeType="polygon";break;case"OpenLayers.Geometry.Polygon":case"OpenLayers.Geometry.Curve":nodeType="path";break;default:break;}
-return nodeType;},setStyle:function(node,style,options){style=style||node._style;options=options||node._options;var title=style.title||style.graphicTitle;if(title){node.setAttributeNS(null,"title",title);var titleNode=node.getElementsByTagName("title");if(titleNode.length>0){titleNode[0].firstChild.textContent=title;}else{var label=this.nodeFactory(null,"title");label.textContent=title;node.appendChild(label);}}
-var r=parseFloat(node.getAttributeNS(null,"r"));var widthFactor=1;var pos;if(node._geometryClass=="OpenLayers.Geometry.Point"&&r){node.style.visibility="";if(style.graphic===false){node.style.visibility="hidden";}else if(style.externalGraphic){pos=this.getPosition(node);if(style.graphicWidth&&style.graphicHeight){node.setAttributeNS(null,"preserveAspectRatio","none");}
-var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);var opacity=style.graphicOpacity||style.fillOpacity;node.setAttributeNS(null,"x",(pos.x+xOffset).toFixed());node.setAttributeNS(null,"y",(pos.y+yOffset).toFixed());node.setAttributeNS(null,"width",width);node.setAttributeNS(null,"height",height);node.setAttributeNS(this.xlinkns,"xlink:href",style.externalGraphic);node.setAttributeNS(null,"style","opacity: "+opacity);node.onclick=OpenLayers.Event.preventDefault;}else if(this.isComplexSymbol(style.graphicName)){var offset=style.pointRadius*3;var size=offset*2;var src=this.importSymbol(style.graphicName);pos=this.getPosition(node);widthFactor=this.symbolMetrics[src.id][0]*3/size;var parent=node.parentNode;var nextSibling=node.nextSibling;if(parent){parent.removeChild(node);}
-node.firstChild&&node.removeChild(node.firstChild);node.appendChild(src.firstChild.cloneNode(true));node.setAttributeNS(null,"viewBox",src.getAttributeNS(null,"viewBox"));node.setAttributeNS(null,"width",size);node.setAttributeNS(null,"height",size);node.setAttributeNS(null,"x",pos.x-offset);node.setAttributeNS(null,"y",pos.y-offset);if(nextSibling){parent.insertBefore(node,nextSibling);}else if(parent){parent.appendChild(node);}}else{node.setAttributeNS(null,"r",style.pointRadius);}
-var rotation=style.rotation;if((rotation!==undefined||node._rotation!==undefined)&&pos){node._rotation=rotation;rotation|=0;if(node.nodeName!=="svg"){node.setAttributeNS(null,"transform","rotate("+rotation+" "+pos.x+" "+
-pos.y+")");}else{var metrics=this.symbolMetrics[src.id];node.firstChild.setAttributeNS(null,"transform","rotate("
-+rotation+" "
-+metrics[1]+" "
-+metrics[2]+")");}}}
-if(options.isFilled){node.setAttributeNS(null,"fill",style.fillColor);node.setAttributeNS(null,"fill-opacity",style.fillOpacity);}else{node.setAttributeNS(null,"fill","none");}
-if(options.isStroked){node.setAttributeNS(null,"stroke",style.strokeColor);node.setAttributeNS(null,"stroke-opacity",style.strokeOpacity);node.setAttributeNS(null,"stroke-width",style.strokeWidth*widthFactor);node.setAttributeNS(null,"stroke-linecap",style.strokeLinecap||"round");node.setAttributeNS(null,"stroke-linejoin","round");style.strokeDashstyle&&node.setAttributeNS(null,"stroke-dasharray",this.dashStyle(style,widthFactor));}else{node.setAttributeNS(null,"stroke","none");}
-if(style.pointerEvents){node.setAttributeNS(null,"pointer-events",style.pointerEvents);}
-if(style.cursor!=null){node.setAttributeNS(null,"cursor",style.cursor);}
-return node;},dashStyle:function(style,widthFactor){var w=style.strokeWidth*widthFactor;var str=style.strokeDashstyle;switch(str){case'solid':return'none';case'dot':return[1,4*w].join();case'dash':return[4*w,4*w].join();case'dashdot':return[4*w,4*w,1,4*w].join();case'longdash':return[8*w,4*w].join();case'longdashdot':return[8*w,4*w,1,4*w].join();default:return OpenLayers.String.trim(str).replace(/\s+/g,",");}},createNode:function(type,id){var node=document.createElementNS(this.xmlns,type);if(id){node.setAttributeNS(null,"id",id);}
-return node;},nodeTypeCompare:function(node,type){return(type==node.nodeName);},createRenderRoot:function(){var svg=this.nodeFactory(this.container.id+"_svgRoot","svg");svg.style.display="block";return svg;},createRoot:function(suffix){return this.nodeFactory(this.container.id+suffix,"g");},createDefs:function(){var defs=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(defs);return defs;},drawPoint:function(node,geometry){return this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){var resolution=this.getResolution();var x=((geometry.x-this.featureDx)/resolution+this.left);var y=(this.top-geometry.y/resolution);if(this.inValidRange(x,y)){node.setAttributeNS(null,"cx",x);node.setAttributeNS(null,"cy",y);node.setAttributeNS(null,"r",radius);return node;}else{return false;}},drawLineString:function(node,geometry){var componentsResult=this.getComponentsString(geometry.components);if(componentsResult.path){node.setAttributeNS(null,"points",componentsResult.path);return(componentsResult.complete?node:null);}else{return false;}},drawLinearRing:function(node,geometry){var componentsResult=this.getComponentsString(geometry.components);if(componentsResult.path){node.setAttributeNS(null,"points",componentsResult.path);return(componentsResult.complete?node:null);}else{return false;}},drawPolygon:function(node,geometry){var d="";var draw=true;var complete=true;var linearRingResult,path;for(var j=0,len=geometry.components.length;j<len;j++){d+=" M";linearRingResult=this.getComponentsString(geometry.components[j].components," ");path=linearRingResult.path;if(path){d+=" "+path;complete=linearRingResult.complete&&complete;}else{draw=false;}}
-d+=" z";if(draw){node.setAttributeNS(null,"d",d);node.setAttributeNS(null,"fill-rule","evenodd");return complete?node:null;}else{return false;}},drawRectangle:function(node,geometry){var resolution=this.getResolution();var x=((geometry.x-this.featureDx)/resolution+this.left);var y=(this.top-geometry.y/resolution);if(this.inValidRange(x,y)){node.setAttributeNS(null,"x",x);node.setAttributeNS(null,"y",y);node.setAttributeNS(null,"width",geometry.width/resolution);node.setAttributeNS(null,"height",geometry.height/resolution);return node;}else{return false;}},drawText:function(featureId,style,location){var drawOutline=(!!style.labelOutlineWidth);if(drawOutline){var outlineStyle=OpenLayers.Util.extend({},style);outlineStyle.fontColor=outlineStyle.labelOutlineColor;outlineStyle.fontStrokeColor=outlineStyle.labelOutlineColor;outlineStyle.fontStrokeWidth=style.labelOutlineWidth;if(style.labelOutlineOpacity){outlineStyle.fontOpacity=style.labelOutlineOpacity;}
-delete outlineStyle.labelOutlineWidth;this.drawText(featureId,outlineStyle,location);}
-var resolution=this.getResolution();var x=((location.x-this.featureDx)/resolution+this.left);var y=(location.y/resolution-this.top);var suffix=(drawOutline)?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX;var label=this.nodeFactory(featureId+suffix,"text");label.setAttributeNS(null,"x",x);label.setAttributeNS(null,"y",-y);if(style.fontColor){label.setAttributeNS(null,"fill",style.fontColor);}
-if(style.fontStrokeColor){label.setAttributeNS(null,"stroke",style.fontStrokeColor);}
-if(style.fontStrokeWidth){label.setAttributeNS(null,"stroke-width",style.fontStrokeWidth);}
-if(style.fontOpacity){label.setAttributeNS(null,"opacity",style.fontOpacity);}
-if(style.fontFamily){label.setAttributeNS(null,"font-family",style.fontFamily);}
-if(style.fontSize){label.setAttributeNS(null,"font-size",style.fontSize);}
-if(style.fontWeight){label.setAttributeNS(null,"font-weight",style.fontWeight);}
-if(style.fontStyle){label.setAttributeNS(null,"font-style",style.fontStyle);}
-if(style.labelSelect===true){label.setAttributeNS(null,"pointer-events","visible");label._featureId=featureId;}else{label.setAttributeNS(null,"pointer-events","none");}
-var align=style.labelAlign||OpenLayers.Renderer.defaultSymbolizer.labelAlign;label.setAttributeNS(null,"text-anchor",OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]]||"middle");if(OpenLayers.IS_GECKO===true){label.setAttributeNS(null,"dominant-baseline",OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]]||"central");}
-var labelRows=style.label.split('\n');var numRows=labelRows.length;while(label.childNodes.length>numRows){label.removeChild(label.lastChild);}
-for(var i=0;i<numRows;i++){var tspan=this.nodeFactory(featureId+suffix+"_tspan_"+i,"tspan");if(style.labelSelect===true){tspan._featureId=featureId;tspan._geometry=location;tspan._geometryClass=location.CLASS_NAME;}
-if(OpenLayers.IS_GECKO===false){tspan.setAttributeNS(null,"baseline-shift",OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]]||"-35%");}
-tspan.setAttribute("x",x);if(i==0){var vfactor=OpenLayers.Renderer.SVG.LABEL_VFACTOR[align[1]];if(vfactor==null){vfactor=-.5;}
-tspan.setAttribute("dy",(vfactor*(numRows-1))+"em");}else{tspan.setAttribute("dy","1em");}
-tspan.textContent=(labelRows[i]==='')?' ':labelRows[i];if(!tspan.parentNode){label.appendChild(tspan);}}
-if(!label.parentNode){this.textRoot.appendChild(label);}},getComponentsString:function(components,separator){var renderCmp=[];var complete=true;var len=components.length;var strings=[];var str,component;for(var i=0;i<len;i++){component=components[i];renderCmp.push(component);str=this.getShortString(component);if(str){strings.push(str);}else{if(i>0){if(this.getShortString(components[i-1])){strings.push(this.clipLine(components[i],components[i-1]));}}
-if(i<len-1){if(this.getShortString(components[i+1])){strings.push(this.clipLine(components[i],components[i+1]));}}
-complete=false;}}
-return{path:strings.join(separator||","),complete:complete};},clipLine:function(badComponent,goodComponent){if(goodComponent.equals(badComponent)){return"";}
-var resolution=this.getResolution();var maxX=this.MAX_PIXEL-this.translationParameters.x;var maxY=this.MAX_PIXEL-this.translationParameters.y;var x1=(goodComponent.x-this.featureDx)/resolution+this.left;var y1=this.top-goodComponent.y/resolution;var x2=(badComponent.x-this.featureDx)/resolution+this.left;var y2=this.top-badComponent.y/resolution;var k;if(x2<-maxX||x2>maxX){k=(y2-y1)/(x2-x1);x2=x2<0?-maxX:maxX;y2=y1+(x2-x1)*k;}
-if(y2<-maxY||y2>maxY){k=(x2-x1)/(y2-y1);y2=y2<0?-maxY:maxY;x2=x1+(y2-y1)*k;}
-return x2+","+y2;},getShortString:function(point){var resolution=this.getResolution();var x=((point.x-this.featureDx)/resolution+this.left);var y=(this.top-point.y/resolution);if(this.inValidRange(x,y)){return x+","+y;}else{return false;}},getPosition:function(node){return({x:parseFloat(node.getAttributeNS(null,"cx")),y:parseFloat(node.getAttributeNS(null,"cy"))});},importSymbol:function(graphicName){if(!this.defs){this.defs=this.createDefs();}
-var id=this.container.id+"-"+graphicName;var existing=document.getElementById(id);if(existing!=null){return existing;}
-var symbol=OpenLayers.Renderer.symbol[graphicName];if(!symbol){throw new Error(graphicName+' is not a valid symbol name');}
-var symbolNode=this.nodeFactory(id,"symbol");var node=this.nodeFactory(null,"polygon");symbolNode.appendChild(node);var symbolExtent=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);var points=[];var x,y;for(var i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];symbolExtent.left=Math.min(symbolExtent.left,x);symbolExtent.bottom=Math.min(symbolExtent.bottom,y);symbolExtent.right=Math.max(symbolExtent.right,x);symbolExtent.top=Math.max(symbolExtent.top,y);points.push(x,",",y);}
-node.setAttributeNS(null,"points",points.join(" "));var width=symbolExtent.getWidth();var height=symbolExtent.getHeight();var viewBox=[symbolExtent.left-width,symbolExtent.bottom-height,width*3,height*3];symbolNode.setAttributeNS(null,"viewBox",viewBox.join(" "));this.symbolMetrics[id]=[Math.max(width,height),symbolExtent.getCenterLonLat().lon,symbolExtent.getCenterLonLat().lat];this.defs.appendChild(symbolNode);return symbolNode;},getFeatureIdFromEvent:function(evt){var featureId=OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this,arguments);if(!featureId){var target=evt.target;featureId=target.parentNode&&target!=this.rendererRoot?target.parentNode._featureId:undefined;}
-return featureId;},CLASS_NAME:"OpenLayers.Renderer.SVG"});OpenLayers.Renderer.SVG.LABEL_ALIGN={"l":"start","r":"end","b":"bottom","t":"hanging"};OpenLayers.Renderer.SVG.LABEL_VSHIFT={"t":"-70%","b":"0"};OpenLayers.Renderer.SVG.LABEL_VFACTOR={"t":0,"b":-1};OpenLayers.Renderer.SVG.preventDefault=function(e){OpenLayers.Event.preventDefault(e);};OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=size||{w:20,h:20};this.offset=offset||{x:-(this.size.w/2),y:-(this.size.h/2)};this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
-this.draw();},setUrl:function(url){if(url!=null){this.url=url;}
-this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},erase:function(){if(this.imageDiv!=null&&this.imageDiv.parentNode!=null){OpenLayers.Element.remove(this.imageDiv);}},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
-if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
-OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x:this.px.x+this.offset.x,y:this.px.y+this.offset.y});}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},isDrawn:function(){var isDrawn=(this.imageDiv&&this.imageDiv.parentNode&&(this.imageDiv.parentNode.nodeType!=11));return isDrawn;},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
-this.events=new OpenLayers.Events(this,this.icon.imageDiv);},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},erase:function(){if(this.icon!=null){this.icon.erase();}},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
-this.lonlat=this.map.getLonLatFromLayerPx(px);},isDrawn:function(){var isDrawn=(this.icon&&this.icon.isDrawn());return isDrawn;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
-return onScreen;},inflate:function(inflate){if(this.icon){this.icon.setSize({w:this.icon.size.w*inflate,h:this.icon.size.h*inflate});}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25});};OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:false,read:function(json,type,filter){type=(type)?type:"FeatureCollection";var results=null;var obj=null;if(typeof json=="string"){obj=OpenLayers.Format.JSON.prototype.read.apply(this,[json,filter]);}else{obj=json;}
-if(!obj){OpenLayers.Console.error("Bad JSON: "+json);}else if(typeof(obj.type)!="string"){OpenLayers.Console.error("Bad GeoJSON - no type: "+json);}else if(this.isValidType(obj,type)){switch(type){case"Geometry":try{results=this.parseGeometry(obj);}catch(err){OpenLayers.Console.error(err);}
-break;case"Feature":try{results=this.parseFeature(obj);results.type="Feature";}catch(err){OpenLayers.Console.error(err);}
-break;case"FeatureCollection":results=[];switch(obj.type){case"Feature":try{results.push(this.parseFeature(obj));}catch(err){results=null;OpenLayers.Console.error(err);}
-break;case"FeatureCollection":for(var i=0,len=obj.features.length;i<len;++i){try{results.push(this.parseFeature(obj.features[i]));}catch(err){results=null;OpenLayers.Console.error(err);}}
-break;default:try{var geom=this.parseGeometry(obj);results.push(new OpenLayers.Feature.Vector(geom));}catch(err){results=null;OpenLayers.Console.error(err);}}
-break;}}
-return results;},isValidType:function(obj,type){var valid=false;switch(type){case"Geometry":if(OpenLayers.Util.indexOf(["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon","Box","GeometryCollection"],obj.type)==-1){OpenLayers.Console.error("Unsupported geometry type: "+
-obj.type);}else{valid=true;}
-break;case"FeatureCollection":valid=true;break;default:if(obj.type==type){valid=true;}else{OpenLayers.Console.error("Cannot convert types from "+
-obj.type+" to "+type);}}
-return valid;},parseFeature:function(obj){var feature,geometry,attributes,bbox;attributes=(obj.properties)?obj.properties:{};bbox=(obj.geometry&&obj.geometry.bbox)||obj.bbox;try{geometry=this.parseGeometry(obj.geometry);}catch(err){throw err;}
-feature=new OpenLayers.Feature.Vector(geometry,attributes);if(bbox){feature.bounds=OpenLayers.Bounds.fromArray(bbox);}
-if(obj.id){feature.fid=obj.id;}
-return feature;},parseGeometry:function(obj){if(obj==null){return null;}
-var geometry,collection=false;if(obj.type=="GeometryCollection"){if(!(OpenLayers.Util.isArray(obj.geometries))){throw"GeometryCollection must have geometries array: "+obj;}
-var numGeom=obj.geometries.length;var components=new Array(numGeom);for(var i=0;i<numGeom;++i){components[i]=this.parseGeometry.apply(this,[obj.geometries[i]]);}
-geometry=new OpenLayers.Geometry.Collection(components);collection=true;}else{if(!(OpenLayers.Util.isArray(obj.coordinates))){throw"Geometry must have coordinates array: "+obj;}
-if(!this.parseCoords[obj.type.toLowerCase()]){throw"Unsupported geometry type: "+obj.type;}
-try{geometry=this.parseCoords[obj.type.toLowerCase()].apply(this,[obj.coordinates]);}catch(err){throw err;}}
-if(this.internalProjection&&this.externalProjection&&!collection){geometry.transform(this.externalProjection,this.internalProjection);}
-return geometry;},parseCoords:{"point":function(array){if(this.ignoreExtraDims==false&&array.length!=2){throw"Only 2D points are supported: "+array;}
-return new OpenLayers.Geometry.Point(array[0],array[1]);},"multipoint":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
-points.push(p);}
-return new OpenLayers.Geometry.MultiPoint(points);},"linestring":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
-points.push(p);}
-return new OpenLayers.Geometry.LineString(points);},"multilinestring":function(array){var lines=[];var l=null;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
-lines.push(l);}
-return new OpenLayers.Geometry.MultiLineString(lines);},"polygon":function(array){var rings=[];var r,l;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
-r=new OpenLayers.Geometry.LinearRing(l.components);rings.push(r);}
-return new OpenLayers.Geometry.Polygon(rings);},"multipolygon":function(array){var polys=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["polygon"].apply(this,[array[i]]);}catch(err){throw err;}
-polys.push(p);}
-return new OpenLayers.Geometry.MultiPolygon(polys);},"box":function(array){if(array.length!=2){throw"GeoJSON box coordinates must have 2 elements";}
-return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(array[0][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[0][1])])]);}},write:function(obj,pretty){var geojson={"type":null};if(OpenLayers.Util.isArray(obj)){geojson.type="FeatureCollection";var numFeatures=obj.length;geojson.features=new Array(numFeatures);for(var i=0;i<numFeatures;++i){var element=obj[i];if(!element instanceof OpenLayers.Feature.Vector){var msg="FeatureCollection only supports collections "+"of features: "+element;throw msg;}
-geojson.features[i]=this.extract.feature.apply(this,[element]);}}else if(obj.CLASS_NAME.indexOf("OpenLayers.Geometry")==0){geojson=this.extract.geometry.apply(this,[obj]);}else if(obj instanceof OpenLayers.Feature.Vector){geojson=this.extract.feature.apply(this,[obj]);if(obj.layer&&obj.layer.projection){geojson.crs=this.createCRSObject(obj);}}
-return OpenLayers.Format.JSON.prototype.write.apply(this,[geojson,pretty]);},createCRSObject:function(object){var proj=object.layer.projection.toString();var crs={};if(proj.match(/epsg:/i)){var code=parseInt(proj.substring(proj.indexOf(":")+1));if(code==4326){crs={"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}};}else{crs={"type":"name","properties":{"name":"EPSG:"+code}};}}
-return crs;},extract:{'feature':function(feature){var geom=this.extract.geometry.apply(this,[feature.geometry]);var json={"type":"Feature","properties":feature.attributes,"geometry":geom};if(feature.fid!=null){json.id=feature.fid;}
-return json;},'geometry':function(geometry){if(geometry==null){return null;}
-if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
-var geometryType=geometry.CLASS_NAME.split('.')[2];var data=this.extract[geometryType.toLowerCase()].apply(this,[geometry]);var json;if(geometryType=="Collection"){json={"type":"GeometryCollection","geometries":data};}else{json={"type":geometryType,"coordinates":data};}
-return json;},'point':function(point){return[point.x,point.y];},'multipoint':function(multipoint){var array=[];for(var i=0,len=multipoint.components.length;i<len;++i){array.push(this.extract.point.apply(this,[multipoint.components[i]]));}
-return array;},'linestring':function(linestring){var array=[];for(var i=0,len=linestring.components.length;i<len;++i){array.push(this.extract.point.apply(this,[linestring.components[i]]));}
-return array;},'multilinestring':function(multilinestring){var array=[];for(var i=0,len=multilinestring.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[multilinestring.components[i]]));}
-return array;},'polygon':function(polygon){var array=[];for(var i=0,len=polygon.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[polygon.components[i]]));}
-return array;},'multipolygon':function(multipolygon){var array=[];for(var i=0,len=multipolygon.components.length;i<len;++i){array.push(this.extract.polygon.apply(this,[multipolygon.components[i]]));}
-return array;},'collection':function(collection){var len=collection.components.length;var array=new Array(len);for(var i=0;i<len;++i){array[i]=this.extract.geometry.apply(this,[collection.components[i]]);}
-return array;}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:false,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:false,fixPadding:function(){if(typeof this.padding=="number"){this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding);}},panMapIfOutOfView:false,keepInMap:false,closeOnMove:false,map:null,initialize:function(id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
-this.id=id;this.lonlat=lonlat;this.contentSize=(contentSize!=null)?contentSize:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);if(contentHTML!=null){this.contentHTML=contentHTML;}
-this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;var groupDivId=this.id+"_GroupDiv";this.groupDiv=OpenLayers.Util.createDiv(groupDivId,null,null,null,"relative",null,"hidden");var id=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(id,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);if(closeBox){this.addCloseBox(closeBoxCallback);}
-this.registerEvents();},destroy:function(){this.id=null;this.lonlat=null;this.size=null;this.contentHTML=null;this.backgroundColor=null;this.opacity=null;this.border=null;if(this.closeOnMove&&this.map){this.map.events.unregister("movestart",this,this.hide);}
-this.events.destroy();this.events=null;if(this.closeDiv){OpenLayers.Event.stopObservingElement(this.closeDiv);this.groupDiv.removeChild(this.closeDiv);}
-this.closeDiv=null;this.div.removeChild(this.groupDiv);this.groupDiv=null;if(this.map!=null){this.map.removePopup(this);}
-this.map=null;this.div=null;this.autoSize=null;this.minSize=null;this.maxSize=null;this.padding=null;this.panMapIfOutOfView=null;},draw:function(px){if(px==null){if((this.lonlat!=null)&&(this.map!=null)){px=this.map.getLayerPxFromLonLat(this.lonlat);}}
-if(this.closeOnMove){this.map.events.register("movestart",this,this.hide);}
-if(!this.disableFirefoxOverflowHack&&OpenLayers.BROWSER_NAME=='firefox'){this.map.events.register("movestart",this,function(){var style=document.defaultView.getComputedStyle(this.contentDiv,null);var currentOverflow=style.getPropertyValue("overflow");if(currentOverflow!="hidden"){this.contentDiv._oldOverflow=currentOverflow;this.contentDiv.style.overflow="hidden";}});this.map.events.register("moveend",this,function(){var oldOverflow=this.contentDiv._oldOverflow;if(oldOverflow){this.contentDiv.style.overflow=oldOverflow;this.contentDiv._oldOverflow=null;}});}
-this.moveTo(px);if(!this.autoSize&&!this.size){this.setSize(this.contentSize);}
-this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();if(this.panMapIfOutOfView){this.panIntoView();}
-return this.div;},updatePosition:function(){if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);if(px){this.moveTo(px);}}},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},visible:function(){return OpenLayers.Element.visible(this.div);},toggle:function(){if(this.visible()){this.hide();}else{this.show();}},show:function(){this.div.style.display='';if(this.panMapIfOutOfView){this.panIntoView();}},hide:function(){this.div.style.display='none';},setSize:function(contentSize){this.size=contentSize.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;this.fixPadding();wPadding+=this.padding.left+this.padding.right;hPadding+=this.padding.top+this.padding.bottom;if(this.closeDiv){var closeDivWidth=parseInt(this.closeDiv.style.width);wPadding+=closeDivWidth+contentDivPadding.right;}
-this.size.w+=wPadding;this.size.h+=hPadding;if(OpenLayers.BROWSER_NAME=="msie"){this.contentSize.w+=contentDivPadding.left+contentDivPadding.right;this.contentSize.h+=contentDivPadding.bottom+contentDivPadding.top;}
-if(this.div!=null){this.div.style.width=this.size.w+"px";this.div.style.height=this.size.h+"px";}
-if(this.contentDiv!=null){this.contentDiv.style.width=contentSize.w+"px";this.contentDiv.style.height=contentSize.h+"px";}},updateSize:function(){var preparedHTML="<div class='"+this.contentDisplayClass+"'>"+
-this.contentDiv.innerHTML+"</div>";var containerElement=(this.map)?this.map.div:document.body;var realSize=OpenLayers.Util.getRenderedDimensions(preparedHTML,null,{displayClass:this.displayClass,containerElement:containerElement});var safeSize=this.getSafeContentSize(realSize);var newSize=null;if(safeSize.equals(realSize)){newSize=realSize;}else{var fixedSize={w:(safeSize.w<realSize.w)?safeSize.w:null,h:(safeSize.h<realSize.h)?safeSize.h:null};if(fixedSize.w&&fixedSize.h){newSize=safeSize;}else{var clippedSize=OpenLayers.Util.getRenderedDimensions(preparedHTML,fixedSize,{displayClass:this.contentDisplayClass,containerElement:containerElement});var currentOverflow=OpenLayers.Element.getStyle(this.contentDiv,"overflow");if((currentOverflow!="hidden")&&(clippedSize.equals(safeSize))){var scrollBar=OpenLayers.Util.getScrollbarWidth();if(fixedSize.w){clippedSize.h+=scrollBar;}else{clippedSize.w+=scrollBar;}}
-newSize=this.getSafeContentSize(clippedSize);}}
-this.setSize(newSize);},setBackgroundColor:function(color){if(color!=undefined){this.backgroundColor=color;}
-if(this.div!=null){this.div.style.backgroundColor=this.backgroundColor;}},setOpacity:function(opacity){if(opacity!=undefined){this.opacity=opacity;}
-if(this.div!=null){this.div.style.opacity=this.opacity;this.div.style.filter='alpha(opacity='+this.opacity*100+')';}},setBorder:function(border){if(border!=undefined){this.border=border;}
-if(this.div!=null){this.div.style.border=this.border;}},setContentHTML:function(contentHTML){if(contentHTML!=null){this.contentHTML=contentHTML;}
-if((this.contentDiv!=null)&&(this.contentHTML!=null)&&(this.contentHTML!=this.contentDiv.innerHTML)){this.contentDiv.innerHTML=this.contentHTML;if(this.autoSize){this.registerImageListeners();this.updateSize();}}},registerImageListeners:function(){var onImgLoad=function(){if(this.popup.id===null){return;}
-this.popup.updateSize();if(this.popup.visible()&&this.popup.panMapIfOutOfView){this.popup.panIntoView();}
-OpenLayers.Event.stopObserving(this.img,"load",this.img._onImgLoad);};var images=this.contentDiv.getElementsByTagName("img");for(var i=0,len=images.length;i<len;i++){var img=images[i];if(img.width==0||img.height==0){var context={'popup':this,'img':img};img._onImgLoad=OpenLayers.Function.bind(onImgLoad,context);OpenLayers.Event.observe(img,'load',img._onImgLoad);}}},getSafeContentSize:function(size){var safeContentSize=size.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;this.fixPadding();wPadding+=this.padding.left+this.padding.right;hPadding+=this.padding.top+this.padding.bottom;if(this.closeDiv){var closeDivWidth=parseInt(this.closeDiv.style.width);wPadding+=closeDivWidth+contentDivPadding.right;}
-if(this.minSize){safeContentSize.w=Math.max(safeContentSize.w,(this.minSize.w-wPadding));safeContentSize.h=Math.max(safeContentSize.h,(this.minSize.h-hPadding));}
-if(this.maxSize){safeContentSize.w=Math.min(safeContentSize.w,(this.maxSize.w-wPadding));safeContentSize.h=Math.min(safeContentSize.h,(this.maxSize.h-hPadding));}
-if(this.map&&this.map.size){var extraX=0,extraY=0;if(this.keepInMap&&!this.panMapIfOutOfView){var px=this.map.getPixelFromLonLat(this.lonlat);switch(this.relativePosition){case"tr":extraX=px.x;extraY=this.map.size.h-px.y;break;case"tl":extraX=this.map.size.w-px.x;extraY=this.map.size.h-px.y;break;case"bl":extraX=this.map.size.w-px.x;extraY=px.y;break;case"br":extraX=px.x;extraY=px.y;break;default:extraX=px.x;extraY=this.map.size.h-px.y;break;}}
-var maxY=this.map.size.h-
-this.map.paddingForPopups.top-
-this.map.paddingForPopups.bottom-
-hPadding-extraY;var maxX=this.map.size.w-
-this.map.paddingForPopups.left-
-this.map.paddingForPopups.right-
-wPadding-extraX;safeContentSize.w=Math.min(safeContentSize.w,maxX);safeContentSize.h=Math.min(safeContentSize.h,maxY);}
-return safeContentSize;},getContentDivPadding:function(){var contentDivPadding=this._contentDivPadding;if(!contentDivPadding){if(this.div.parentNode==null){this.div.style.display="none";document.body.appendChild(this.div);}
-contentDivPadding=new OpenLayers.Bounds(OpenLayers.Element.getStyle(this.contentDiv,"padding-left"),OpenLayers.Element.getStyle(this.contentDiv,"padding-bottom"),OpenLayers.Element.getStyle(this.contentDiv,"padding-right"),OpenLayers.Element.getStyle(this.contentDiv,"padding-top"));this._contentDivPadding=contentDivPadding;if(this.div.parentNode==document.body){document.body.removeChild(this.div);this.div.style.display="";}}
-return contentDivPadding;},addCloseBox:function(callback){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,{w:17,h:17});this.closeDiv.className="olPopupCloseBox";var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+"px";this.closeDiv.style.top=contentDivPadding.top+"px";this.groupDiv.appendChild(this.closeDiv);var closePopup=callback||function(e){this.hide();OpenLayers.Event.stop(e);};OpenLayers.Event.observe(this.closeDiv,"touchend",OpenLayers.Function.bindAsEventListener(closePopup,this));OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(closePopup,this));},panIntoView:function(){var mapSize=this.map.getSize();var origTL=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top)));var newTL=origTL.clone();if(origTL.x<this.map.paddingForPopups.left){newTL.x=this.map.paddingForPopups.left;}else
-if((origTL.x+this.size.w)>(mapSize.w-this.map.paddingForPopups.right)){newTL.x=mapSize.w-this.map.paddingForPopups.right-this.size.w;}
-if(origTL.y<this.map.paddingForPopups.top){newTL.y=this.map.paddingForPopups.top;}else
-if((origTL.y+this.size.h)>(mapSize.h-this.map.paddingForPopups.bottom)){newTL.y=mapSize.h-this.map.paddingForPopups.bottom-this.size.h;}
-var dx=origTL.x-newTL.x;var dy=origTL.y-newTL.y;this.map.pan(dx,dy);},registerEvents:function(){this.events=new OpenLayers.Events(this,this.div,null,true);function onTouchstart(evt){OpenLayers.Event.stop(evt,true);}
-this.events.on({"mousedown":this.onmousedown,"mousemove":this.onmousemove,"mouseup":this.onmouseup,"click":this.onclick,"mouseout":this.onmouseout,"dblclick":this.ondblclick,"touchstart":onTouchstart,scope:this});},onmousedown:function(evt){this.mousedown=true;OpenLayers.Event.stop(evt,true);},onmousemove:function(evt){if(this.mousedown){OpenLayers.Event.stop(evt,true);}},onmouseup:function(evt){if(this.mousedown){this.mousedown=false;OpenLayers.Event.stop(evt,true);}},onclick:function(evt){OpenLayers.Event.stop(evt,true);},onmouseout:function(evt){this.mousedown=false;},ondblclick:function(evt){OpenLayers.Event.stop(evt,true);},CLASS_NAME:"OpenLayers.Popup"});OpenLayers.Popup.WIDTH=200;OpenLayers.Popup.HEIGHT=200;OpenLayers.Popup.COLOR="white";OpenLayers.Popup.OPACITY=1;OpenLayers.Popup.BORDER="0px";OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,keepInMap:true,anchor:null,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){var newArguments=[id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback];OpenLayers.Popup.prototype.initialize.apply(this,newArguments);this.anchor=(anchor!=null)?anchor:{size:new OpenLayers.Size(0,0),offset:new OpenLayers.Pixel(0,0)};},destroy:function(){this.anchor=null;this.relativePosition=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments);},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments);},moveTo:function(px){var oldRelativePosition=this.relativePosition;this.relativePosition=this.calculateRelativePosition(px);OpenLayers.Popup.prototype.moveTo.call(this,this.calculateNewPx(px));if(this.relativePosition!=oldRelativePosition){this.updateRelativePosition();}},setSize:function(contentSize){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(px);}},calculateRelativePosition:function(px){var lonlat=this.map.getLonLatFromLayerPx(px);var extent=this.map.getExtent();var quadrant=extent.determineQuadrant(lonlat);return OpenLayers.Bounds.oppositeQuadrant(quadrant);},updateRelativePosition:function(){},calculateNewPx:function(px){var newPx=px.offset(this.anchor.offset);var size=this.size||this.contentSize;var top=(this.relativePosition.charAt(0)=='t');newPx.y+=(top)?-size.h:this.anchor.size.h;var left=(this.relativePosition.charAt(1)=='l');newPx.x+=(left)?-size.w:this.anchor.size.w;return newPx;},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:false,positionBlocks:null,blocks:null,fixedRelativePosition:false,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);if(this.fixedRelativePosition){this.updateRelativePosition();this.calculateRelativePosition=function(px){return this.relativePosition;};}
-this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;if(closeBox){this.closeDiv.style.zIndex=1;}
-this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%";},destroy:function(){this.imageSrc=null;this.imageSize=null;this.isAlphaImage=null;this.fixedRelativePosition=false;this.positionBlocks=null;for(var i=0;i<this.blocks.length;i++){var block=this.blocks[i];if(block.image){block.div.removeChild(block.image);}
-block.image=null;if(block.div){this.groupDiv.removeChild(block.div);}
-block.div=null;}
-this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,arguments);},setBackgroundColor:function(color){},setBorder:function(){},setOpacity:function(opacity){},setSize:function(contentSize){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks();},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+
-this.padding.right+"px";this.closeDiv.style.top=contentDivPadding.top+
-this.padding.top+"px";}
-this.updateBlocks();},calculateNewPx:function(px){var newPx=OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);newPx=newPx.offset(this.positionBlocks[this.relativePosition].offset);return newPx;},createBlocks:function(){this.blocks=[];var firstPosition=null;for(var key in this.positionBlocks){firstPosition=key;break;}
-var position=this.positionBlocks[firstPosition];for(var i=0;i<position.blocks.length;i++){var block={};this.blocks.push(block);var divId=this.id+'_FrameDecorationDiv_'+i;block.div=OpenLayers.Util.createDiv(divId,null,null,null,"absolute",null,"hidden",null);var imgId=this.id+'_FrameDecorationImg_'+i;var imageCreator=(this.isAlphaImage)?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage;block.image=imageCreator(imgId,null,this.imageSize,this.imageSrc,"absolute",null,null,null);block.div.appendChild(block.image);this.groupDiv.appendChild(block.div);}},updateBlocks:function(){if(!this.blocks){this.createBlocks();}
-if(this.size&&this.relativePosition){var position=this.positionBlocks[this.relativePosition];for(var i=0;i<position.blocks.length;i++){var positionBlock=position.blocks[i];var block=this.blocks[i];var l=positionBlock.anchor.left;var b=positionBlock.anchor.bottom;var r=positionBlock.anchor.right;var t=positionBlock.anchor.top;var w=(isNaN(positionBlock.size.w))?this.size.w-(r+l):positionBlock.size.w;var h=(isNaN(positionBlock.size.h))?this.size.h-(b+t):positionBlock.size.h;block.div.style.width=(w<0?0:w)+'px';block.div.style.height=(h<0?0:h)+'px';block.div.style.left=(l!=null)?l+'px':'';block.div.style.bottom=(b!=null)?b+'px':'';block.div.style.right=(r!=null)?r+'px':'';block.div.style.top=(t!=null)?t+'px':'';block.image.style.left=positionBlock.position.x+'px';block.image.style.top=positionBlock.position.y+'px';}
-this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px";}},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Control.DrawFeature=OpenLayers.Class(OpenLayers.Control,{layer:null,callbacks:null,multi:false,featureAdded:function(){},initialize:function(layer,handler,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.callbacks=OpenLayers.Util.extend({done:this.drawFeature,modify:function(vertex,feature){this.layer.events.triggerEvent("sketchmodified",{vertex:vertex,feature:feature});},create:function(vertex,feature){this.layer.events.triggerEvent("sketchstarted",{vertex:vertex,feature:feature});}},this.callbacks);this.layer=layer;this.handlerOptions=this.handlerOptions||{};this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{renderers:layer.renderers,rendererOptions:layer.rendererOptions});if(!("multi"in this.handlerOptions)){this.handlerOptions.multi=this.multi;}
-var sketchStyle=this.layer.styleMap&&this.layer.styleMap.styles.temporary;if(sketchStyle){this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":sketchStyle})});}
-this.handler=new handler(this,this.callbacks,this.handlerOptions);},drawFeature:function(geometry){var feature=new OpenLayers.Feature.Vector(geometry);var proceed=this.layer.events.triggerEvent("sketchcomplete",{feature:feature});if(proceed!==false){feature.state=OpenLayers.State.INSERT;this.layer.addFeatures([feature]);this.featureAdded(feature);this.events.triggerEvent("featureadded",{feature:feature});}},insertXY:function(x,y){if(this.handler&&this.handler.line){this.handler.insertXY(x,y);}},insertDeltaXY:function(dx,dy){if(this.handler&&this.handler.line){this.handler.insertDeltaXY(dx,dy);}},insertDirectionLength:function(direction,length){if(this.handler&&this.handler.line){this.handler.insertDirectionLength(direction,length);}},insertDeflectionLength:function(deflection,length){if(this.handler&&this.handler.line){this.handler.insertDeflectionLength(deflection,length);}},undo:function(){return this.handler.undo&&this.handler.undo();},redo:function(){return this.handler.redo&&this.handler.redo();},finishSketch:function(){this.handler.finishGeometry();},cancel:function(){this.handler.cancel();},CLASS_NAME:"OpenLayers.Control.DrawFeature"});OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{contentDisplayClass:"olFramedCloudPopupContent",autoSize:true,panMapIfOutOfView:true,imageSize:new OpenLayers.Size(1276,736),isAlphaImage:false,fixedRelativePosition:false,positionBlocks:{"tl":{'offset':new OpenLayers.Pixel(44,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,18),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-632)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-688)}]},"tr":{'offset':new OpenLayers.Pixel(-45,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,19),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-631)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(0,0,null,null),position:new OpenLayers.Pixel(-215,-687)}]},"bl":{'offset':new OpenLayers.Pixel(45,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},"br":{'offset':new OpenLayers.Pixel(-44,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(1200,660),initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){this.imageSrc=OpenLayers.Util.getImageLocation('cloud-popup-relative.png');OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className=this.contentDisplayClass;},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Handler.Pinch=OpenLayers.Class(OpenLayers.Handler,{started:false,stopDown:false,pinching:false,last:null,start:null,touchstart:function(evt){var propagate=true;this.pinching=false;if(OpenLayers.Event.isMultiTouch(evt)){this.started=true;this.last=this.start={distance:this.getDistance(evt.touches),delta:0,scale:1};this.callback("start",[evt,this.start]);propagate=!this.stopDown;}else if(this.started){return false;}else{this.started=false;this.start=null;this.last=null;}
-OpenLayers.Event.preventDefault(evt);return propagate;},touchmove:function(evt){if(this.started&&OpenLayers.Event.isMultiTouch(evt)){this.pinching=true;var current=this.getPinchData(evt);this.callback("move",[evt,current]);this.last=current;OpenLayers.Event.stop(evt);}else if(this.started){return false;}
-return true;},touchend:function(evt){if(this.started&&!OpenLayers.Event.isMultiTouch(evt)){this.started=false;this.pinching=false;this.callback("done",[evt,this.start,this.last]);this.start=null;this.last=null;return false;}
-return true;},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.pinching=false;activated=true;}
-return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.pinching=false;this.start=null;this.last=null;deactivated=true;}
-return deactivated;},getDistance:function(touches){var t0=touches[0];var t1=touches[1];return Math.sqrt(Math.pow(t0.olClientX-t1.olClientX,2)+
-Math.pow(t0.olClientY-t1.olClientY,2));},getPinchData:function(evt){var distance=this.getDistance(evt.touches);var scale=distance/this.start.distance;return{distance:distance,delta:this.last.distance-distance,scale:scale};},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:['http://a.tile.openstreetmap.org/${z}/${x}/${y}.png','http://b.tile.openstreetmap.org/${z}/${x}/${y}.png','http://c.tile.openstreetmap.org/${z}/${x}/${y}.png'],attribution:"&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",sphericalMercator:true,wrapDateLine:true,tileOptions:null,initialize:function(name,url,options){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:'anonymous'},this.options&&this.options.tileOptions);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions());}
-obj=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[obj]);return obj;},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Control.Geolocate=OpenLayers.Class(OpenLayers.Control,{geolocation:null,available:('geolocation'in navigator),bind:true,watch:false,geolocationOptions:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){if(this.available&&!this.geolocation){this.geolocation=navigator.geolocation;}
-if(!this.geolocation){this.events.triggerEvent("locationuncapable");return false;}
-if(OpenLayers.Control.prototype.activate.apply(this,arguments)){if(this.watch){this.watchId=this.geolocation.watchPosition(OpenLayers.Function.bind(this.geolocate,this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions);}else{this.getCurrentLocation();}
-return true;}
-return false;},deactivate:function(){if(this.active&&this.watchId!==null){this.geolocation.clearWatch(this.watchId);}
-return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},geolocate:function(position){var center=new OpenLayers.LonLat(position.coords.longitude,position.coords.latitude).transform(new OpenLayers.Projection("EPSG:4326"),this.map.getProjectionObject());if(this.bind){this.map.setCenter(center);}
-this.events.triggerEvent("locationupdated",{position:position,point:new OpenLayers.Geometry.Point(center.lon,center.lat)});},getCurrentLocation:function(){if(!this.active||this.watch){return false;}
-this.geolocation.getCurrentPosition(OpenLayers.Function.bind(this.geolocate,this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions);return true;},failure:function(error){this.events.triggerEvent("locationfailed",{error:error});},CLASS_NAME:"OpenLayers.Control.Geolocate"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,dblclickTolerance:13,stopSingle:false,stopDouble:false,timerId:null,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(evt){this.startTouch();this.down=this.getEventInfo(evt);this.last=this.getEventInfo(evt);return true;},touchmove:function(evt){this.last=this.getEventInfo(evt);return true;},touchend:function(evt){if(this.down){evt.xy=this.last.xy;evt.lastTouches=this.last.touches;this.handleSingle(evt);this.down=null;}
-return true;},mousedown:function(evt){this.down=this.getEventInfo(evt);this.last=this.getEventInfo(evt);return true;},mouseup:function(evt){var propagate=true;if(this.checkModifiers(evt)&&this.control.handleRightClicks&&OpenLayers.Event.isRightClick(evt)){propagate=this.rightclick(evt);}
-return propagate;},rightclick:function(evt){if(this.passesTolerance(evt)){if(this.rightclickTimerId!=null){this.clearTimer();this.callback('dblrightclick',[evt]);return!this.stopDouble;}else{var clickEvent=this['double']?OpenLayers.Util.extend({},evt):this.callback('rightclick',[evt]);var delayedRightCall=OpenLayers.Function.bind(this.delayedRightCall,this,clickEvent);this.rightclickTimerId=window.setTimeout(delayedRightCall,this.delay);}}
-return!this.stopSingle;},delayedRightCall:function(evt){this.rightclickTimerId=null;if(evt){this.callback('rightclick',[evt]);}},click:function(evt){if(!this.last){this.last=this.getEventInfo(evt);}
-this.handleSingle(evt);return!this.stopSingle;},dblclick:function(evt){this.handleDouble(evt);return!this.stopDouble;},handleDouble:function(evt){if(this.passesDblclickTolerance(evt)){if(this["double"]){this.callback("dblclick",[evt]);}
-this.clearTimer();}},handleSingle:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){if(this.last.touches&&this.last.touches.length===1){if(this["double"]){OpenLayers.Event.preventDefault(evt);}
-this.handleDouble(evt);}
-if(!this.last.touches||this.last.touches.length!==2){this.clearTimer();}}else{this.first=this.getEventInfo(evt);var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.queuePotentialClick(clickEvent);}}},queuePotentialClick:function(evt){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,evt),this.delay);},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down&&this.down.xy){passes=this.pixelTolerance>=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;i<ii;++i){if(this.getTouchDistance(this.down.touches[i],this.last.touches[i])>this.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;i<len;i++){touch=evt.touches[i];touches[i]={clientX:touch.olClientX,clientY:touch.olClientY};}}
-return{xy:evt.xy,touches:touches};},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();this.down=null;this.first=null;this.last=null;deactivated=true;}
-return deactivated;},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Protocol.WFS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.0.0",CLASS_NAME:"OpenLayers.Protocol.WFS.v1_0_0"});OpenLayers.Strategy.Cluster=OpenLayers.Class(OpenLayers.Strategy,{distance:20,threshold:null,features:null,clusters:null,clustering:false,resolution:null,activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"beforefeaturesadded":this.cacheFeatures,"featuresremoved":this.clearCache,"moveend":this.cluster,scope:this});}
-return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.clearCache();this.layer.events.un({"beforefeaturesadded":this.cacheFeatures,"featuresremoved":this.clearCache,"moveend":this.cluster,scope:this});}
-return deactivated;},cacheFeatures:function(event){var propagate=true;if(!this.clustering){this.clearCache();this.features=event.features;this.cluster();propagate=false;}
-return propagate;},clearCache:function(){if(!this.clustering){this.features=null;}},cluster:function(event){if((!event||event.zoomChanged)&&this.features){var resolution=this.layer.map.getResolution();if(resolution!=this.resolution||!this.clustersExist()){this.resolution=resolution;var clusters=[];var feature,clustered,cluster;for(var i=0;i<this.features.length;++i){feature=this.features[i];if(feature.geometry){clustered=false;for(var j=clusters.length-1;j>=0;--j){cluster=clusters[j];if(this.shouldCluster(cluster,feature)){this.addToCluster(cluster,feature);clustered=true;break;}}
-if(!clustered){clusters.push(this.createCluster(this.features[i]));}}}
-this.clustering=true;this.layer.removeAllFeatures();this.clustering=false;if(clusters.length>0){if(this.threshold>1){var clone=clusters.slice();clusters=[];var candidate;for(var i=0,len=clone.length;i<len;++i){candidate=clone[i];if(candidate.attributes.count<this.threshold){Array.prototype.push.apply(clusters,candidate.cluster);}else{clusters.push(candidate);}}}
-this.clustering=true;this.layer.addFeatures(clusters);this.clustering=false;}
-this.clusters=clusters;}}},clustersExist:function(){var exist=false;if(this.clusters&&this.clusters.length>0&&this.clusters.length==this.layer.features.length){exist=true;for(var i=0;i<this.clusters.length;++i){if(this.clusters[i]!=this.layer.features[i]){exist=false;break;}}}
-return exist;},shouldCluster:function(cluster,feature){var cc=cluster.geometry.getBounds().getCenterLonLat();var fc=feature.geometry.getBounds().getCenterLonLat();var distance=(Math.sqrt(Math.pow((cc.lon-fc.lon),2)+Math.pow((cc.lat-fc.lat),2))/this.resolution);return(distance<=this.distance);},addToCluster:function(cluster,feature){cluster.cluster.push(feature);cluster.attributes.count+=1;},createCluster:function(feature){var center=feature.geometry.getBounds().getCenterLonLat();var cluster=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(center.lon,center.lat),{count:1});cluster.cluster=[feature];return cluster;},CLASS_NAME:"OpenLayers.Strategy.Cluster"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:0,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.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,pinchOrigin:null,currentCenter:null,autoActivate:true,preserveCenter:false,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions);},pinchStart:function(evt,pinchData){var xy=(this.preserveCenter)?this.map.getPixelFromLonLat(this.map.getCenter()):evt.xy;this.pinchOrigin=xy;this.currentCenter=xy;},pinchMove:function(evt,pinchData){var scale=pinchData.scale;var containerOrigin=this.map.layerContainerOriginPx;var pinchOrigin=this.pinchOrigin;var current=(this.preserveCenter)?this.map.getPixelFromLonLat(this.map.getCenter()):evt.xy;var dx=Math.round((containerOrigin.x+current.x-pinchOrigin.x)+(scale-1)*(containerOrigin.x-pinchOrigin.x));var dy=Math.round((containerOrigin.y+current.y-pinchOrigin.y)+(scale-1)*(containerOrigin.y-pinchOrigin.y));this.map.applyTransform(dx,dy,scale);this.currentCenter=current;},pinchDone:function(evt,start,last){this.map.applyTransform();var zoom=this.map.getZoomForResolution(this.map.getResolution()/last.scale,true);if(zoom!==this.map.getZoom()||!this.currentCenter.equals(this.pinchOrigin)){var resolution=this.map.getResolutionForZoom(zoom);var location=this.map.getLonLatFromPixel(this.pinchOrigin);var zoomPixel=this.currentCenter;var size=this.map.getSize();location.lon+=resolution*((size.w/2)-zoomPixel.x);location.lat-=resolution*((size.h/2)-zoomPixel.y);this.map.div.clientWidth=this.map.div.clientWidth;this.map.setCenter(location,zoom);}},CLASS_NAME:"OpenLayers.Control.PinchZoom"});OpenLayers.Control.TouchNavigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,clickHandlerOptions:null,documentDrag:false,autoActivate:true,initialize:function(options){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();if(this.dragPan){this.dragPan.destroy();}
-this.dragPan=null;if(this.pinchZoom){this.pinchZoom.destroy();delete this.pinchZoom;}
-OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){this.dragPan.activate();this.handlers.click.activate();this.pinchZoom.activate();return true;}
-return false;},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.dragPan.deactivate();this.handlers.click.deactivate();this.pinchZoom.deactivate();return true;}
-return false;},draw:function(){var clickCallbacks={click:this.defaultClick,dblclick:this.defaultDblClick};var clickOptions=OpenLayers.Util.extend({"double":true,stopDouble:true,pixelTolerance:2},this.clickHandlerOptions);this.handlers.click=new OpenLayers.Handler.Click(this,clickCallbacks,clickOptions);this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,documentDrag:this.documentDrag},this.dragPanOptions));this.dragPan.draw();this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions));},defaultClick:function(evt){if(evt.lastTouches&&evt.lastTouches.length==2){this.map.zoomOut();}},defaultDblClick:function(evt){this.map.zoomTo(this.map.zoom+1,evt.xy);},CLASS_NAME:"OpenLayers.Control.TouchNavigation"});OpenLayers.Protocol.HTTP=OpenLayers.Class(OpenLayers.Protocol,{url:null,headers:null,params:null,callback:null,scope:null,readWithPOST:false,updateWithPOST:false,deleteWithPOST:false,wildcarded:false,srsInBBOX:false,initialize:function(options){options=options||{};this.params={};this.headers={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var format=new OpenLayers.Format.QueryStringFilter({wildcarded:this.wildcarded,srsInBBOX:this.srsInBBOX});this.filterToParams=function(filter,params){return format.write(filter,params);};}},destroy:function(){this.params=null;this.headers=null;OpenLayers.Protocol.prototype.destroy.apply(this);},read:function(options){OpenLayers.Protocol.prototype.read.apply(this,arguments);options=options||{};options.params=OpenLayers.Util.applyDefaults(options.params,this.options.params);options=OpenLayers.Util.applyDefaults(options,this.options);if(options.filter&&this.filterToParams){options.params=this.filterToParams(options.filter,options.params);}
-var readWithPOST=(options.readWithPOST!==undefined)?options.readWithPOST:this.readWithPOST;var resp=new OpenLayers.Protocol.Response({requestType:"read"});if(readWithPOST){var headers=options.headers||{};headers["Content-Type"]="application/x-www-form-urlencoded";resp.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleRead,resp,options),data:OpenLayers.Util.getParameterString(options.params),headers:headers});}else{resp.priv=OpenLayers.Request.GET({url:options.url,callback:this.createCallback(this.handleRead,resp,options),params:options.params,headers:options.headers});}
-return resp;},handleRead:function(resp,options){this.handleResponse(resp,options);},create:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:features,requestType:"create"});resp.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleCreate,resp,options),headers:options.headers,data:this.format.write(features)});return resp;},handleCreate:function(resp,options){this.handleResponse(resp,options);},update:function(feature,options){options=options||{};var url=options.url||feature.url||this.options.url+"/"+feature.fid;options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:feature,requestType:"update"});var method=this.updateWithPOST?"POST":"PUT";resp.priv=OpenLayers.Request[method]({url:url,callback:this.createCallback(this.handleUpdate,resp,options),headers:options.headers,data:this.format.write(feature)});return resp;},handleUpdate:function(resp,options){this.handleResponse(resp,options);},"delete":function(feature,options){options=options||{};var url=options.url||feature.url||this.options.url+"/"+feature.fid;options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:feature,requestType:"delete"});var method=this.deleteWithPOST?"POST":"DELETE";var requestOptions={url:url,callback:this.createCallback(this.handleDelete,resp,options),headers:options.headers};if(this.deleteWithPOST){requestOptions.data=this.format.write(feature);}
-resp.priv=OpenLayers.Request[method](requestOptions);return resp;},handleDelete:function(resp,options){this.handleResponse(resp,options);},handleResponse:function(resp,options){var request=resp.priv;if(options.callback){if(request.status>=200&&request.status<300){if(resp.requestType!="delete"){resp.features=this.parseFeatures(request);}
-resp.code=OpenLayers.Protocol.Response.SUCCESS;}else{resp.code=OpenLayers.Protocol.Response.FAILURE;}
-options.callback.call(options.scope,resp);}},parseFeatures:function(request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
-if(!doc||doc.length<=0){return null;}
-return this.format.read(doc);},commit:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=[],nResponses=0;var types={};types[OpenLayers.State.INSERT]=[];types[OpenLayers.State.UPDATE]=[];types[OpenLayers.State.DELETE]=[];var feature,list,requestFeatures=[];for(var i=0,len=features.length;i<len;++i){feature=features[i];list=types[feature.state];if(list){list.push(feature);requestFeatures.push(feature);}}
-var nRequests=(types[OpenLayers.State.INSERT].length>0?1:0)+
-types[OpenLayers.State.UPDATE].length+
-types[OpenLayers.State.DELETE].length;var success=true;var finalResponse=new OpenLayers.Protocol.Response({reqFeatures:requestFeatures});function insertCallback(response){var len=response.features?response.features.length:0;var fids=new Array(len);for(var i=0;i<len;++i){fids[i]=response.features[i].fid;}
-finalResponse.insertIds=fids;callback.apply(this,[response]);}
-function callback(response){this.callUserCallback(response,options);success=success&&response.success();nResponses++;if(nResponses>=nRequests){if(options.callback){finalResponse.code=success?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE;options.callback.apply(options.scope,[finalResponse]);}}}
-var queue=types[OpenLayers.State.INSERT];if(queue.length>0){resp.push(this.create(queue,OpenLayers.Util.applyDefaults({callback:insertCallback,scope:this},options.create)));}
-queue=types[OpenLayers.State.UPDATE];for(var i=queue.length-1;i>=0;--i){resp.push(this.update(queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options.update)));}
-queue=types[OpenLayers.State.DELETE];for(var i=queue.length-1;i>=0;--i){resp.push(this["delete"](queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options["delete"])));}
-return resp;},abort:function(response){if(response){response.priv.abort();}},callUserCallback:function(resp,options){var opt=options[resp.requestType];if(opt&&opt.callback){opt.callback.call(opt.scope,resp);}},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.TileManager=OpenLayers.Class({cacheSize:256,tilesPerFrame:2,frameDelay:16,moveDelay:100,zoomDelay:200,maps:null,tileQueueId:null,tileQueue:null,tileCache:null,tileCacheIndex:null,initialize:function(options){OpenLayers.Util.extend(this,options);this.maps=[];this.tileQueueId={};this.tileQueue={};this.tileCache={};this.tileCacheIndex=[];},addMap:function(map){if(this._destroyed||!OpenLayers.Layer.Grid){return;}
-this.maps.push(map);this.tileQueue[map.id]=[];for(var i=0,ii=map.layers.length;i<ii;++i){this.addLayer({layer:map.layers[i]});}
-map.events.on({move:this.move,zoomend:this.zoomEnd,changelayer:this.changeLayer,addlayer:this.addLayer,preremovelayer:this.removeLayer,scope:this});},removeMap:function(map){if(this._destroyed||!OpenLayers.Layer.Grid){return;}
-window.clearTimeout(this.tileQueueId[map.id]);if(map.layers){for(var i=0,ii=map.layers.length;i<ii;++i){this.removeLayer({layer:map.layers[i]});}}
-if(map.events){map.events.un({move:this.move,zoomend:this.zoomEnd,changelayer:this.changeLayer,addlayer:this.addLayer,preremovelayer:this.removeLayer,scope:this});}
-delete this.tileQueue[map.id];delete this.tileQueueId[map.id];OpenLayers.Util.removeItem(this.maps,map);},move:function(evt){this.updateTimeout(evt.object,this.moveDelay,true);},zoomEnd:function(evt){this.updateTimeout(evt.object,this.zoomDelay);},changeLayer:function(evt){if(evt.property==='visibility'||evt.property==='params'){this.updateTimeout(evt.object,0);}},addLayer:function(evt){var layer=evt.layer;if(layer instanceof OpenLayers.Layer.Grid){layer.events.on({addtile:this.addTile,retile:this.clearTileQueue,scope:this});var i,j,tile;for(i=layer.grid.length-1;i>=0;--i){for(j=layer.grid[i].length-1;j>=0;--j){tile=layer.grid[i][j];this.addTile({tile:tile});if(tile.url&&!tile.imgDiv){this.manageTileCache({object:tile});}}}}},removeLayer:function(evt){var layer=evt.layer;if(layer instanceof OpenLayers.Layer.Grid){this.clearTileQueue({object:layer});if(layer.events){layer.events.un({addtile:this.addTile,retile:this.clearTileQueue,scope:this});}
-if(layer.grid){var i,j,tile;for(i=layer.grid.length-1;i>=0;--i){for(j=layer.grid[i].length-1;j>=0;--j){tile=layer.grid[i][j];this.unloadTile({object:tile});}}}}},updateTimeout:function(map,delay,nice){window.clearTimeout(this.tileQueueId[map.id]);var tileQueue=this.tileQueue[map.id];if(!nice||tileQueue.length){this.tileQueueId[map.id]=window.setTimeout(OpenLayers.Function.bind(function(){this.drawTilesFromQueue(map);if(tileQueue.length){this.updateTimeout(map,this.frameDelay);}},this),delay);}},addTile:function(evt){if(evt.tile instanceof OpenLayers.Tile.Image){evt.tile.events.on({beforedraw:this.queueTileDraw,beforeload:this.manageTileCache,loadend:this.addToCache,unload:this.unloadTile,scope:this});}else{this.removeLayer({layer:evt.tile.layer});}},unloadTile:function(evt){var tile=evt.object;tile.events.un({beforedraw:this.queueTileDraw,beforeload:this.manageTileCache,loadend:this.addToCache,unload:this.unloadTile,scope:this});OpenLayers.Util.removeItem(this.tileQueue[tile.layer.map.id],tile);},queueTileDraw:function(evt){var tile=evt.object;var queued=false;var layer=tile.layer;var url=layer.getURL(tile.bounds);var img=this.tileCache[url];if(img&&img.className!=='olTileImage'){delete this.tileCache[url];OpenLayers.Util.removeItem(this.tileCacheIndex,url);img=null;}
-if(layer.url&&(layer.async||!img)){var tileQueue=this.tileQueue[layer.map.id];if(!~OpenLayers.Util.indexOf(tileQueue,tile)){tileQueue.push(tile);}
-queued=true;}
-return!queued;},drawTilesFromQueue:function(map){var tileQueue=this.tileQueue[map.id];var limit=this.tilesPerFrame;var animating=map.zoomTween&&map.zoomTween.playing;while(!animating&&tileQueue.length&&limit){tileQueue.shift().draw(true);--limit;}},manageTileCache:function(evt){var tile=evt.object;var img=this.tileCache[tile.url];if(img){if(img.parentNode&&OpenLayers.Element.hasClass(img.parentNode,'olBackBuffer')){img.parentNode.removeChild(img);img.id=null;}
-if(!img.parentNode){img.style.visibility='hidden';img.style.opacity=0;tile.setImage(img);OpenLayers.Util.removeItem(this.tileCacheIndex,tile.url);this.tileCacheIndex.push(tile.url);}}},addToCache:function(evt){var tile=evt.object;if(!this.tileCache[tile.url]){if(!OpenLayers.Element.hasClass(tile.imgDiv,'olImageLoadError')){if(this.tileCacheIndex.length>=this.cacheSize){delete this.tileCache[this.tileCacheIndex[0]];this.tileCacheIndex.shift();}
-this.tileCache[tile.url]=tile.imgDiv;this.tileCacheIndex.push(tile.url);}}},clearTileQueue:function(evt){var layer=evt.object;var tileQueue=this.tileQueue[layer.map.id];for(var i=tileQueue.length-1;i>=0;--i){if(tileQueue[i].layer===layer){tileQueue.splice(i,1);}}},destroy:function(){for(var i=this.maps.length-1;i>=0;--i){this.removeMap(this.maps[i]);}
-this.maps=null;this.tileQueue=null;this.tileQueueId=null;this.tileCache=null;this.tileCacheIndex=null;this._destroyed=true;}});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[];},destroy:function(){this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({buttonclick:this.onButtonClick,addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});if(this.outsideViewport){this.events.attachToElement(this.div);this.events.register("buttonclick",this,this.onButtonClick);}else{this.map.events.register("buttonclick",this,this.onButtonClick);}},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();if(!this.outsideViewport){this.minimizeControl();}
-this.redraw();return this.div;},onButtonClick:function(evt){var button=evt.buttonElement;if(button===this.minimizeDiv){this.minimizeControl();}else if(button===this.maximizeDiv){this.maximizeControl();}else if(button._layerSwitcher===this.id){if(button["for"]){button=document.getElementById(button["for"]);}
-if(!button.disabled){if(button.type=="radio"){button.checked=true;this.map.setBaseLayer(this.map.getLayer(button._layer));}else{button.checked=!button.checked;this.updateMap();}}}},clearLayersArray:function(layersType){this[layersType+"LayersDiv"].innerHTML="";this[layersType+"Layers"]=[];},checkRedraw:function(){if(!this.layerStates.length||(this.map.layers.length!=this.layerStates.length)){return true;}
-for(var i=0,len=this.layerStates.length;i<len;i++){var layerState=this.layerStates[i];var layer=this.map.layers[i];if((layerState.name!=layer.name)||(layerState.inRange!=layer.inRange)||(layerState.id!=layer.id)||(layerState.visibility!=layer.visibility)){return true;}}
-return false;},redraw:function(){if(!this.checkRedraw()){return this.div;}
-this.clearLayersArray("base");this.clearLayersArray("data");var containsOverlays=false;var containsBaseLayers=false;var len=this.map.layers.length;this.layerStates=new Array(len);for(var i=0;i<len;i++){var layer=this.map.layers[i];this.layerStates[i]={'name':layer.name,'visibility':layer.visibility,'inRange':layer.inRange,'id':layer.id};}
-var layers=this.map.layers.slice();if(!this.ascending){layers.reverse();}
-for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];var baseLayer=layer.isBaseLayer;if(layer.displayInLayerSwitcher){if(baseLayer){containsBaseLayers=true;}else{containsOverlays=true;}
-var checked=(baseLayer)?(layer==this.map.baseLayer):layer.getVisibility();var inputElem=document.createElement("input"),inputId=OpenLayers.Util.createUniqueID(this.id+"_input_");inputElem.id=inputId;inputElem.name=(baseLayer)?this.id+"_baseLayers":layer.name;inputElem.type=(baseLayer)?"radio":"checkbox";inputElem.value=layer.name;inputElem.checked=checked;inputElem.defaultChecked=checked;inputElem.className="olButton";inputElem._layer=layer.id;inputElem._layerSwitcher=this.id;if(!baseLayer&&!layer.inRange){inputElem.disabled=true;}
-var labelSpan=document.createElement("label");labelSpan["for"]=inputElem.id;OpenLayers.Element.addClass(labelSpan,"labelSpan olButton");labelSpan._layer=layer.id;labelSpan._layerSwitcher=this.id;if(!baseLayer&&!layer.inRange){labelSpan.style.color="gray";}
-labelSpan.innerHTML=layer.name;labelSpan.style.verticalAlign=(baseLayer)?"bottom":"baseline";var br=document.createElement("br");var groupArray=(baseLayer)?this.baseLayers:this.dataLayers;groupArray.push({'layer':layer,'inputElem':inputElem,'labelSpan':labelSpan});var groupDiv=(baseLayer)?this.baseLayersDiv:this.dataLayersDiv;groupDiv.appendChild(inputElem);groupDiv.appendChild(labelSpan);groupDiv.appendChild(br);}}
-this.dataLbl.style.display=(containsOverlays)?"":"none";this.baseLbl.style.display=(containsBaseLayers)?"":"none";return this.div;},updateMap:function(){for(var i=0,len=this.baseLayers.length;i<len;i++){var layerEntry=this.baseLayers[i];if(layerEntry.inputElem.checked){this.map.setBaseLayer(layerEntry.layer,false);}}
-for(var i=0,len=this.dataLayers.length;i<len;i++){var layerEntry=this.dataLayers[i];layerEntry.layer.setVisibility(layerEntry.inputElem.checked);}},maximizeControl:function(e){this.div.style.width="";this.div.style.height="";this.showControls(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.div.style.width="0px";this.div.style.height="0px";this.showControls(true);if(e!=null){OpenLayers.Event.stop(e);}},showControls:function(minimize){this.maximizeDiv.style.display=minimize?"":"none";this.minimizeDiv.style.display=minimize?"none":"";this.layersDiv.style.display=minimize?"none":"";},loadContents:function(){this.layersDiv=document.createElement("div");this.layersDiv.id=this.id+"_layersDiv";OpenLayers.Element.addClass(this.layersDiv,"layersDiv");this.baseLbl=document.createElement("div");this.baseLbl.innerHTML=OpenLayers.i18n("Base Layer");OpenLayers.Element.addClass(this.baseLbl,"baseLbl");this.baseLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.baseLayersDiv,"baseLayersDiv");this.dataLbl=document.createElement("div");this.dataLbl.innerHTML=OpenLayers.i18n("Overlays");OpenLayers.Element.addClass(this.dataLbl,"dataLbl");this.dataLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.dataLayersDiv,"dataLayersDiv");if(this.ascending){this.layersDiv.appendChild(this.baseLbl);this.layersDiv.appendChild(this.baseLayersDiv);this.layersDiv.appendChild(this.dataLbl);this.layersDiv.appendChild(this.dataLayersDiv);}else{this.layersDiv.appendChild(this.dataLbl);this.layersDiv.appendChild(this.dataLayersDiv);this.layersDiv.appendChild(this.baseLbl);this.layersDiv.appendChild(this.baseLayersDiv);}
-this.div.appendChild(this.layersDiv);var img=OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv",null,null,img,"absolute");OpenLayers.Element.addClass(this.maximizeDiv,"maximizeDiv olButton");this.maximizeDiv.style.display="none";this.div.appendChild(this.maximizeDiv);var img=OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv",null,null,img,"absolute");OpenLayers.Element.addClass(this.minimizeDiv,"minimizeDiv olButton");this.minimizeDiv.style.display="none";this.div.appendChild(this.minimizeDiv);},CLASS_NAME:"OpenLayers.Control.LayerSwitcher"}); \ No newline at end of file
diff --git a/chimere/static/openlayers/SimplePanZoom.js b/chimere/static/openlayers/SimplePanZoom.js
deleted file mode 100644
index 45619c3..0000000
--- a/chimere/static/openlayers/SimplePanZoom.js
+++ /dev/null
@@ -1,366 +0,0 @@
-/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control/PanZoom.js
- */
-
-/**
- * Class: OpenLayers.Control.PanZoomBar
- * The PanZoomBar is a visible control composed of a
- * <OpenLayers.Control.PanPanel> and a <OpenLayers.Control.ZoomBar>.
- * By default it is displayed in the upper left corner of the map as 4
- * directional arrows above a vertical slider.
- *
- * Inherits from:
- * - <OpenLayers.Control.PanZoom>
- */
-OpenLayers.Control.SimplePanZoom = OpenLayers.Class(OpenLayers.Control.PanZoom, {
-
- /**
- * APIProperty: zoomStopWidth
- */
- zoomStopWidth: 18,
-
- /**
- * APIProperty: zoomStopHeight
- */
- zoomStopHeight: 7,
-
- /**
- * Property: slider
- */
- slider: null,
-
- /**
- * Property: sliderEvents
- * {<OpenLayers.Events>}
- */
- sliderEvents: null,
-
- /**
- * Property: zoombarDiv
- * {DOMElement}
- */
- zoombarDiv: null,
-
- /**
- * APIProperty: zoomWorldIcon
- * {Boolean}
- */
- zoomWorldIcon: false,
-
- /**
- * APIProperty: panIcons
- * {Boolean} Set this property to false not to display the pan icons. If
- * false the zoom world icon is placed under the zoom bar. Defaults to
- * true.
- */
- panIcons: true,
-
- /**
- * APIProperty: forceFixedZoomLevel
- * {Boolean} Force a fixed zoom level even though the map has
- * fractionalZoom
- */
- forceFixedZoomLevel: false,
-
- /**
- * Property: mouseDragStart
- * {<OpenLayers.Pixel>}
- */
- mouseDragStart: null,
-
- /**
- * Property: deltaY
- * {Number} The cumulative vertical pixel offset during a zoom bar drag.
- */
- deltaY: null,
-
- /**
- * Property: zoomStart
- * {<OpenLayers.Pixel>}
- */
- zoomStart: null,
-
- /**
- * Constructor: OpenLayers.Control.PanZoomBar
- */
- buttons: null,
-
- /**
- * Top position of the slider: change if the Y position of the slider have change
- */
- startTop: 75,
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
-
- this._removeZoomBar();
-
- this.map.events.un({
- "changebaselayer": this.redraw,
- "updatesize": this.redraw,
- scope: this
- });
-
- OpenLayers.Control.PanZoom.prototype.destroy.apply(this, arguments);
-
- delete this.mouseDragStart;
- delete this.zoomStart;
- },
-
- /**
- * Method: setMap
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Control.PanZoom.prototype.setMap.apply(this, arguments);
- this.map.events.on({
- "changebaselayer": this.redraw,
- "updatesize": this.redraw,
- scope: this
- });
- },
-
- /**
- * Method: redraw
- * clear the div and start over.
- */
- redraw: function() {
- if (this.div !== null) {
- this.removeButtons();
- this._removeZoomBar();
- }
- this.draw();
- },
-
- /**
- * Method: draw
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- */
- draw: function(px) {
- // initialize our internal div
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- px = this.position.clone();
-
- // place the controls
- this.buttons = [];
- var ids = ['panup', 'panleft', 'panright', 'pandown', 'zoomout', 'zoomin'];
-
- for (var i = 0; i < ids.length; i++) {
- var b = document.createElement('div');
- b.id = ids[i];
- b.action = ids[i];
- b.className = 'button olButton';
- this.div.appendChild(b);
- this.buttons.push(b);
- }
-
- this._addZoomBar();
- return this.div;
- },
-
- /**
- * Method: _addZoomBar
- *
- * Parameters:
- * centered - {<OpenLayers.Pixel>} where zoombar drawing is to start.
- */
- _addZoomBar:function() {
- var id = this.id + "_" + this.map.id;
- var zoomsToEnd = this.map.getNumZoomLevels() - 1 - this.map.getZoom();
- var slider = document.createElement('div');
- slider.id = 'slider';
- slider.className = 'button';
- slider.style.cursor = 'move';
- this.slider = slider;
-
- this.sliderEvents = new OpenLayers.Events(this, slider, null, true,
- { includeXY: true });
- this.sliderEvents.on({
- "touchstart": this.zoomBarDown,
- "touchmove": this.zoomBarDrag,
- "touchend": this.zoomBarUp,
- "mousedown": this.zoomBarDown,
- "mousemove": this.zoomBarDrag,
- "mouseup": this.zoomBarUp
- });
-
- var height = this.zoomStopHeight * (this.map.getNumZoomLevels());
-
- // this is the background image
- var div = document.createElement('div');
- div.className = 'button';
- div.id = 'zoombar';
- this.zoombarDiv = div;
-
- this.div.appendChild(div);
- this.div.appendChild(slider);
-
- this.map.events.register("zoomend", this, this.moveZoomBar);
- },
-
- /**
- * Method: _removeZoomBar
- */
- _removeZoomBar: function() {
- this.sliderEvents.un({
- "touchstart": this.zoomBarDown,
- "touchmove": this.zoomBarDrag,
- "touchend": this.zoomBarUp,
- "mousedown": this.zoomBarDown,
- "mousemove": this.zoomBarDrag,
- "mouseup": this.zoomBarUp
- });
- this.sliderEvents.destroy();
-
- this.div.removeChild(this.zoombarDiv);
- this.zoombarDiv = null;
- this.div.removeChild(this.slider);
- this.slider = null;
-
- this.map.events.unregister("zoomend", this, this.moveZoomBar);
- },
-
- /**
- * Method: onButtonClick
- *
- * Parameters:
- * evt - {Event}
- */
- onButtonClick: function(evt) {
- OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this, arguments);
- if (evt.buttonElement === this.zoombarDiv) {
- var levels = evt.buttonXY.y / this.zoomStopHeight;
- if (this.forceFixedZoomLevel || !this.map.fractionalZoom) {
- levels = Math.floor(levels);
- }
- var zoom = (this.map.getNumZoomLevels() - 1) - levels;
- zoom = Math.min(Math.max(zoom, 0), this.map.getNumZoomLevels() - 1);
- this.map.zoomTo(zoom);
- }
- },
-
- /**
- * Method: passEventToSlider
- * This function is used to pass events that happen on the div, or the map,
- * through to the slider, which then does its moving thing.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- */
- passEventToSlider:function(evt) {
- this.sliderEvents.handleBrowserEvent(evt);
- },
-
- /*
- * Method: zoomBarDown
- * event listener for clicks on the slider
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- */
- zoomBarDown:function(evt) {
- if (!OpenLayers.Event.isLeftClick(evt) && !OpenLayers.Event.isSingleTouch(evt)) {
- return;
- }
- this.map.events.on({
- "touchmove": this.passEventToSlider,
- "mousemove": this.passEventToSlider,
- "mouseup": this.passEventToSlider,
- scope: this
- });
- this.mouseDragStart = evt.xy.clone();
- this.zoomStart = evt.xy.clone();
- this.div.style.cursor = "move";
- // reset the div offsets just in case the div moved
- this.zoombarDiv.offsets = null;
- OpenLayers.Event.stop(evt);
- },
-
- /*
- * Method: zoomBarDrag
- * This is what happens when a click has occurred, and the client is
- * dragging. Here we must ensure that the slider doesn't go beyond the
- * bottom/top of the zoombar div, as well as moving the slider to its new
- * visual location
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- */
- zoomBarDrag: function(evt) {
- if (this.mouseDragStart !== null) {
- var deltaY = this.mouseDragStart.y - evt.xy.y;
- var offsets = OpenLayers.Util.pagePosition(this.zoombarDiv);
- if ((evt.clientY - offsets[1]) > 0 &&
- (evt.clientY - offsets[1]) < 140) {
- var newTop = parseInt(this.slider.style.top, 10) - deltaY;
- this.slider.style.top = newTop + "px";
- this.mouseDragStart = evt.xy.clone();
- }
- // set cumulative displacement
- this.deltaY = this.zoomStart.y - evt.xy.y;
- OpenLayers.Event.stop(evt);
- }
- },
-
- /*
- * Method: zoomBarUp
- * Perform cleanup when a mouseup event is received -- discover new zoom
- * level and switch to it.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- */
- zoomBarUp: function(evt) {
- if (!OpenLayers.Event.isLeftClick(evt) && evt.type !== "touchend") {
- return;
- }
- if (this.mouseDragStart) {
- this.div.style.cursor="";
- this.map.events.un({
- "touchmove": this.passEventToSlider,
- "mouseup": this.passEventToSlider,
- "mousemove": this.passEventToSlider,
- scope: this
- });
- var zoomLevel = this.map.zoom;
- if (!this.forceFixedZoomLevel && this.map.fractionalZoom) {
- zoomLevel += this.deltaY/this.zoomStopHeight;
- zoomLevel = Math.min(Math.max(zoomLevel, 0),
- this.map.getNumZoomLevels() - 1);
- } else {
- zoomLevel += this.deltaY/this.zoomStopHeight;
- zoomLevel = Math.max(Math.round(zoomLevel), 0);
- }
- this.map.zoomTo(zoomLevel);
- this.mouseDragStart = null;
- this.zoomStart = null;
- this.deltaY = 0;
- OpenLayers.Event.stop(evt);
- }
- },
-
- /*
- * Method: moveZoomBar
- * Change the location of the slider to match the current zoom level.
- */
- moveZoomBar:function() {
- var newTop =
- ((this.map.getNumZoomLevels()-1) - this.map.getZoom()) *
- this.zoomStopHeight + this.startTop;
- this.slider.style.top = newTop + "px";
- },
-
- CLASS_NAME: "OpenLayers.Control.SimplePanZoom"
-});
diff --git a/chimere/templates/chimere/blocks/JQueryAutoComplete.html b/chimere/templates/chimere/blocks/JQueryAutoComplete.html
new file mode 100644
index 0000000..c316869
--- /dev/null
+++ b/chimere/templates/chimere/blocks/JQueryAutoComplete.html
@@ -0,0 +1,57 @@
+<input{{attrs_select|safe}}/>
+<input type="hidden"{{attrs_hidden|safe}}/>
+ <script type="text/javascript"><!--//
+
+$(function() {
+ $('#id_select_{{field_id}}').autocomplete({
+ autoFocus: true,
+ source:{{source|safe}},
+ select: function (event, ui){
+ if(ui.item){
+ $('#id_{{field_id}}').val(ui.item.id);
+ } else {
+ $('#id_{{field_id}}').val(null);
+ $('#id_select_{{field_id}}').val('');
+ }
+ },
+ minLength: 2,
+ change: function (event, ui){
+ if(ui.item){
+ $('#id_{{field_id}}').val(ui.item.id);
+ } else {
+ $('#id_{{field_id}}').val(null);
+ $('#id_select_{{field_id}}').val('');
+ }
+ },
+ open: function(){
+ setTimeout(function () {
+ $('.ui-autocomplete').css('z-index', 1000);
+ }, 0);
+ }{% if options %},
+ {{options}}{% endif %}
+ });
+
+ $('#id_select_{{field_id}}').on('click', function(){
+ $('#id_{{field_id}}').val(null);
+ $('#id_select_{{field_id}}').val(null);
+ });
+
+ $('body').on('click', function(){
+ if (!$('#id_{{field_id}}').val()) {
+ $('#id_select_{{field_id}}').val(null);
+ }
+ });
+
+ $('#id_select_{{field_id}}').on( "autocompletefocus",
+ function( event, ui ){
+ disable_enter = true;
+ } );
+
+ $('#id_select_{{field_id}}').on( "autocompleteselect",
+ function( event, ui ){
+ disable_enter = false;
+ } );
+
+});
+//--></script>
+
diff --git a/chimere/templates/chimere/blocks/head_chimere.html b/chimere/templates/chimere/blocks/head_chimere.html
index 7ed2b54..0554f4c 100644
--- a/chimere/templates/chimere/blocks/head_chimere.html
+++ b/chimere/templates/chimere/blocks/head_chimere.html
@@ -1,7 +1,8 @@
-{% for css_url in OSM_CSS_URLS %}
+{% if not is_edit %}{% for css_url in MAP_CSS_URLS %}
<link rel="stylesheet" href="{{ css_url }}" />{% endfor %}
-{% for js_url in OSM_JS_URLS %}
+{% for js_url in MAP_JS_URLS %}
<script src="{{ js_url }}" type="text/javascript"></script>{% endfor %}
+{% endif %}
{% if routing %}<script src="{{ STATIC_URL }}chimere/js/routing-widget.js" type="text/javascript"></script>{% endif %}
{% if enable_clustering %}<script src="{{ STATIC_URL }}chimere/js/clustering.js" type="text/javascript"></script>{% endif %}
<script src="{{ STATIC_URL }}chimere/js/jquery.chimere.js" type="text/javascript"></script>
@@ -15,27 +16,13 @@
<script src="{{ STATIC_URL }}chimere/js/base.js" type="text/javascript"></script>
<script type="text/javascript">
var DEFAULT_ZOOM = {{ DEFAULT_ZOOM }};
- var EPSG_DISPLAY_PROJECTION = epsg_display_projection = new OpenLayers.Projection('EPSG:{{ EPSG_DISPLAY_PROJECTION }}');
- OpenLayers.ImgPath = '{{ STATIC_URL }}chimere/img/';
- var EPSG_PROJECTION = epsg_projection = new OpenLayers.Projection('EPSG:{{ EPSG_PROJECTION }}');
- var CENTER_LONLAT = centerLonLat = new OpenLayers.LonLat{{ DEFAULT_CENTER }}.transform(epsg_display_projection, epsg_projection);
- /*var map_layer = {{ MAP_LAYER|safe }};*/
+ var EPSG_DISPLAY_PROJECTION = 'EPSG:{{ EPSG_DISPLAY_PROJECTION }}';
+ //OL3-deprecated: OpenLayers.ImgPath = '{{ STATIC_URL }}chimere/img/';
+ var EPSG_PROJECTION = epsg_projection = 'EPSG:{{ EPSG_PROJECTION }}';
+ var CENTER_LONLAT = centerLonLat = ol.proj.transform(
+ [{{DEFAULT_CENTER.0|safe}}, {{DEFAULT_CENTER.1|safe}}],
+ EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
var restricted_extent;
- {% if area_name %}
- var area_name = '{{ area_name }}';{% endif %}
-
- $(function() {$( ".draggable" ).draggable({handle:"h2"});});
+ {% if area_name %}var area_name = '{{ area_name }}';{% endif %}
var get_share_url = '{% url chimere:get-share-url %}';
</script>
-<style type="text/css">
-.olControlPanPanel div {
- background-image: url({{STATIC_URL}}chimere/img/pan-panel.png);
-}
-
-.olControlZoomPanel div {
- background-image: url({{STATIC_URL}}chimere/img/zoom-panel.png);
-}
-</style>
-
-
-
diff --git a/chimere/templates/chimere/blocks/head_form.html b/chimere/templates/chimere/blocks/head_form.html
index 032a711..4c24b29 100644
--- a/chimere/templates/chimere/blocks/head_form.html
+++ b/chimere/templates/chimere/blocks/head_form.html
@@ -1,2 +1,2 @@
-<script src="{{ TINYMCE_URL }}tiny_mce.js" type="text/javascript"></script>
+{% if TINYMCE_URL %}<script src="{{ TINYMCE_URL }}tiny_mce.js" type="text/javascript"></script>{% endif %}
diff --git a/chimere/templates/chimere/blocks/head_jme.html b/chimere/templates/chimere/blocks/head_jme.html
index bf31e6f..47bda85 100644
--- a/chimere/templates/chimere/blocks/head_jme.html
+++ b/chimere/templates/chimere/blocks/head_jme.html
@@ -1,3 +1,5 @@
+
+{% comment %}
<script class="jwPlayer" type="application/swf" src="{{STATIC_URL}}jme/packages/player.swf"></script>
<script src="{{STATIC_URL}}jme/packages/mm.full.min.js" type="text/javascript"></script>
<script src="{{STATIC_URL}}jme/utils/jmeEmbedControls.js" type="text/javascript"></script>
@@ -11,6 +13,7 @@
<script src="{{STATIC_URL}}jme/plugins/fullwindow.js" type="text/javascript"></script>
<!-- useractivity -->
<script src="{{STATIC_URL}}jme/utils/useractivity.js" type="text/javascript"></script>
+{% endcomment %}
<!-- prettyPhoto not jme but media -->
<link rel="stylesheet" href="{{STATIC_URL}}prettyPhoto/css/prettyPhoto.css" />
diff --git a/chimere/templates/chimere/blocks/live_coordinates.html b/chimere/templates/chimere/blocks/live_coordinates.html
index 6d0dfb4..b4b7d1e 100644
--- a/chimere/templates/chimere/blocks/live_coordinates.html
+++ b/chimere/templates/chimere/blocks/live_coordinates.html
@@ -1,14 +1,16 @@
<script type='text/javascript'>
var resolutions;
var zoomOffset;
- OpenLayers.ImgPath = '%schimere/img/';
- var EPSG_DISPLAY_PROJECTION = epsg_display_projection = new OpenLayers.Projection('EPSG:%s');
- var EPSG_PROJECTION = epsg_projection = new OpenLayers.Projection('EPSG:%s');
- var CENTER_LONLAT = centerLonLat = new OpenLayers.LonLat%s.transform(epsg_display_projection, epsg_projection);
+ // OpenLayers.ImgPath = '%schimere/img/';
+ var EPSG_DISPLAY_PROJECTION = epsg_display_projection = 'EPSG:%s';
+ var EPSG_PROJECTION = epsg_projection = 'EPSG:%s';
+ var CENTER_LONLAT = centerLonLat = ol.proj.transform(%s,
+ EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION);
var DEFAULT_ZOOM = %s;
+ {{extra_js|safe}}
var chimere_init_options = {};
chimere_init_options["input_id"] = 'id_{{name}}';
- chimere_init_options["default_icon"] = new OpenLayers.Icon('%schimere/img/marker-green.png', new OpenLayers.Size(21, 25), new OpenLayers.Pixel(-(21/2), -25));
+ //chimere_init_options["default_icon"] = new OpenLayers.Icon('%schimere/img/marker-green.png', new OpenLayers.Size(21, 25), new OpenLayers.Pixel(-(21/2), -25));
chimere_init_options["map_layers"] = [%s];
chimere_init_options['dynamic_categories'] = false;
chimere_init_options['edition'] = true;
@@ -19,15 +21,16 @@
</div>
+<div id='layerSwitcher'></div>
<div id='map_edit'></div>
<div id='live_lonlat'>
<p>
<label for='live_latitude'>{{lat}}</label>
- <input type='text' name='live_latitude' id='live_latitude' size='8' adisabled='true' value='{{value_y|stringformat:"f"}}'/>
+ <input type='text' readonly='readonly' name='live_latitude' id='live_latitude' size='8' adisabled='true' value='{{value_y|stringformat:"f"}}'/>
</p>
<p>
<label for='live_longitude'>{{lon}}</label>
- <input type='text' name='live_longitude' id='live_longitude' size='8' adisabled='true' value='{{value_x|stringformat:"f"}}'/>
+ <input type='text' readonly='readonly' name='live_longitude' id='live_longitude' size='8' adisabled='true' value='{{value_x|stringformat:"f"}}'/>
</p>
<input type='hidden' name='{{name}}' id='id_{{name}}' value='{{val}}'/>
@@ -35,27 +38,25 @@
function init_map_edit(){
$('#map_edit').chimere(chimere_init_options);
{% if isvalue %}
- var mylonlat = new OpenLayers.LonLat({{value_x|stringformat:"f"}},
- {{value_y|stringformat:"f"}});
- $("#map_edit").chimere(
- "putEditMarker",
- mylonlat.transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION),
- true);
+ var mylonlat = [{{value_x|stringformat:"f"}},
+ {{value_y|stringformat:"f"}}];
+ $("#map_edit").chimere("putEditMarker",
+ mylonlat, true);
+ $('#map_edit').chimere('activateModify');
+ {% else %}
+ $('#map_edit').chimere('activateDraw');
{% endif %}
- $('#live_latitude').change(function() {
- var mylonlat = new OpenLayers.LonLat($('#live_longitude').val(),
- $('#live_latitude').val());
- $("#map_edit").chimere("putEditMarker",
- mylonlat.transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION), false);
- $("#map_edit").chimere("settings").map.setCenter(mylonlat);
- });
- $('#live_longitude').change(function() {
- var mylonlat = new OpenLayers.LonLat($('#live_longitude').val(),
- $('#live_latitude').val());
+ $('#map_edit').chimere('zoom', { 'area':%s });
+
+ function update_marker_on_map(){
+ var mylonlat = [$('#live_longitude').val(),
+ $('#live_latitude').val()];
$("#map_edit").chimere("putEditMarker",
- mylonlat.transform(EPSG_DISPLAY_PROJECTION, EPSG_PROJECTION), false);
- $("#map_edit").chimere("settings").map.setCenter(mylonlat);
- });
+ mylonlat,
+ true);
+ }
+ $('#live_latitude').change(update_marker_on_map);
+ $('#live_longitude').change(update_marker_on_map);
}
{% if initialized %}init_map_edit();{% endif %}
</script>
diff --git a/chimere/templates/chimere/blocks/map.html b/chimere/templates/chimere/blocks/map.html
index 764d07b..9a39647 100644
--- a/chimere/templates/chimere/blocks/map.html
+++ b/chimere/templates/chimere/blocks/map.html
@@ -1,4 +1,17 @@
{% load i18n %}
+<div id='category_description' class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="{% trans "Close" %}"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="category_description-label"></h4>
+ </div>
+ <div class="modal-body" id="category_description-content">
+ </div>
+ </div>
+ </div>
+</div>
+
<div id='{{map_id}}'></div>
<script type="text/javascript">
$("#{{map_id}}").show();
@@ -12,7 +25,6 @@ $(function(){
<div id="waiting">
<div id="waiting-content">
<img alt='Ajax loader' src='{{STATIC_URL}}chimere/img/ajax-loader.gif'/>
- <p>{% trans "Loading of the map in progress" %}</p>
</div>
</div>
<div id="layer_selection">
@@ -22,13 +34,18 @@ $(function(){
</ul>
</div>
<script type="text/javascript">
- {% if single_category %}
- $(function() {$('#panel').hide()});{% endif %}
+ {% if not display_category_menu %}
+ $(function() {
+ $('#panel').hide();
+ $(".show-hide-panel").hide();
+ $("#categories-lnk").hide();
+ });{% endif %}
+ {{extra_js}}
var chimere_init_options = {};
{% if MOBILE %}chimere_init_options["mobile"] = true;{% endif %}
{% if enable_clustering %}chimere_init_options["enable_clustering"] = true;{% endif %}
chimere_init_options["default_icon"] = '{{STATIC_URL}}img/marker-green.png';
- chimere_init_options["map_layers"] = [{{js_map_layers|safe|escape}}];
+ {% if js_map_layers %}chimere_init_options["map_layers"] = [{{js_map_layers|safe|escape}}];{% endif %}
chimere_init_options['permalink_label'] = '{%trans "Permalink"%}';
chimere_init_options['permalink_element'] = document.getElementById('permalink');
chimere_init_options['routing'] = {{routing}};
@@ -46,8 +63,9 @@ $(function(){
{% if p_routing_steps %}chimere_init_options["routing_steps_lonlat"] = [{{ p_routing_steps }}];{% endif %}
{% if p_routing_transport %}chimere_init_options["routing_transport"] = "{{ p_routing_transport }}";{% endif %}
{% if p_routing_speed %}chimere_init_options["routing_speed"] = "{{ p_routing_speed }}";{% endif %}
- chimere_init_options["icon_offset"] = new OpenLayers.Pixel({{icon_offset_x}},
- {{icon_offset_y}});
+ //chimere_init_options["icon_offset"] = new OpenLayers.Pixel({{icon_offset_x}},
+ // {{icon_offset_y}});
+ chimere_init_options["icon_offset"] = ({{icon_offset_x}}, {{icon_offset_y}});
chimere_init_options["dynamic_categories"] = {{ dynamic_categories }};
{% if p_display_submited %}chimere_init_options["display_submited"] = {{ p_display_submited }};{% endif %}
chimere_init_options["checked_categories"] = [{% for cc in checked_categories %}{% if forloop.counter0 > 0 %}, {% endif %}{{cc}}{% endfor %}];
@@ -62,13 +80,22 @@ $(function(){
{% if selected_map_layer %}
chimere_init_options["selected_map_layer"] = {{selected_map_layer}};
{% endif %}
+
+ $('#category_description').modal({show:false});
+ chimere_init_options["open_dialog_fx"] = function (title, content){
+ $('#category_description-content').html(content);
+ $('#category_description-label').html(title);
+ $('#category_description').modal('show');
+ }
$("#main-map").chimere(chimere_init_options);
{% if zoom %}
$('#maps').chimere('zoom', {'area':{{zoom}} });
{% endif %}
+ {{extra_map_def|safe}}
+
// init layer selection
- $(function() {
+ /* $(function() {
{% for layer_name, js, def in map_layers %}
$('#layer_list').append("<li><input type='radio' value='{{forloop.counter0}}' name='layer_type' id='layer_{{forloop.counter}}'{% if def %} checked='checked'{% endif %}><label for='layer_{{forloop.counter}}'>{{layer_name}}</li>");{% endfor %}
{% for subcat in subcat_layer %}
@@ -88,7 +115,9 @@ $(function(){
$('#'+$(this).val()).trigger('click');
$('#'+$(this).val()).prop("checked", this.checked);
});
+ highlight_selected_categories();
});
+ */
</script>
<div id='marker_hover'><div id='marker_hover_content'></div></div>
<div id='cluster_list'></div>
diff --git a/chimere/templates/chimere/blocks/ol_map.html b/chimere/templates/chimere/blocks/ol_map.html
index a12651c..84aec00 100644
--- a/chimere/templates/chimere/blocks/ol_map.html
+++ b/chimere/templates/chimere/blocks/ol_map.html
@@ -3,8 +3,11 @@
<script>
{{map_id}} = new OpenLayers.Map("{{map_id}}");
{{map_id}}.addLayer(new OpenLayers.Layer.OSM());
- var fromProjection = new OpenLayers.Projection("EPSG:4326");
- var toProjection = new OpenLayers.Projection("EPSG:900913");
+
+ var fromProjection = 'EPSG:4326';
+ var toProjection = 'EPSG:900913';
+
+
{% ifequal geom_type 'point' %}
var lat = '{{geom.y|unlocalize_point}}';
var lon = '{{geom.x|unlocalize_point}}';
diff --git a/chimere/templates/chimere/blocks/polygon_edit.html b/chimere/templates/chimere/blocks/polygon_edit.html
new file mode 100644
index 0000000..59fe07e
--- /dev/null
+++ b/chimere/templates/chimere/blocks/polygon_edit.html
@@ -0,0 +1,36 @@
+{% load unescape i18n %}<script type='text/javascript'>
+ var resolutions;
+ var zoomOffset;
+ image_path = '{static_url}chimere/img/';
+ var EPSG_DISPLAY_PROJECTION = epsg_display_projection = 'EPSG:{display_projection}';
+ var EPSG_PROJECTION = epsg_projection = 'EPSG:{projection}';
+ var CENTER_LONLAT = centerLonLat = ol.proj.transform(
+ {center}, epsg_display_projection, epsg_projection);
+ var DEFAULT_ZOOM = {zoom};
+ {extra_js}
+ var chimere_init_options = {% raw %}{{}}{% endraw %};
+ chimere_init_options["input_id"] = 'id_{{name}}';
+ chimere_init_options["map_layers"] = [{map_layers}];
+ chimere_init_options['dynamic_categories'] = false;
+ chimere_init_options['edition'] = true;
+ chimere_init_options['edition_type'] = 'polygon';
+ chimere_init_options["checked_categories"] = [];
+ {% if default_area %} chimere_init_options['selected_map_layer'] = {{default_area}};{% endif %}
+</script>
+
+<div id='popup'></div>
+<div id='layerSwitcher'></div>
+<div id='map_edit'></div>
+<div class='help'>{% trans "To delete a vertice, hold the SHIFT key and click." %}</div>
+ <input type='hidden' name='{{name}}' id='id_{{name}}' value='{{value}}'/>
+
+<script type="text/javascript">
+ function init_map_edit(){% raw %}{{{% endraw %}
+ $('#map_edit').chimere(chimere_init_options);
+ $('#map_edit').chimere('activateDraw');
+ $('#map_edit').chimere('zoom', {% raw %} {{ 'area':{zoom} }} {% endraw %});
+ {% if value %}$('#map_edit').chimere('initFeature', '{{value}}');
+ {% endif %}
+ {% raw %}}}{% endraw %}
+ {% if initialized %}init_map_edit();{% endif %}
+</script>
diff --git a/chimere/templates/chimere/category_item_detail.html b/chimere/templates/chimere/category_item_detail.html
index 3f90c6c..284dfd0 100644
--- a/chimere/templates/chimere/category_item_detail.html
+++ b/chimere/templates/chimere/category_item_detail.html
@@ -27,7 +27,7 @@
{% if marker.license %}<p class='detail_license'><strong>{% trans "License:" %}</strong> <span>{{marker.license}}</span></p>{% endif %}
{% share_bar marker.name %}
<a href="{% get_tinyfied_url marker area_name %}">{% trans "See on the map" %}</a>
- <p class='detail_amendment'><a href='{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{%else%}{% url chimere:edit-item area_name_slash|default_if_none:"" marker.pk "" %}{%endif%}'>
+ <p class='detail_amendment'><a href='{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{%else%}{% url chimere:editmarker-item area_name_slash|default_if_none:"" marker.pk "" %}{%endif%}'>
{% trans "Submit an amendment" %}
</a>
{% if moderator_emails %}
diff --git a/chimere/templates/chimere/detail.html b/chimere/templates/chimere/detail.html
index abdd76e..d73d8a5 100644
--- a/chimere/templates/chimere/detail.html
+++ b/chimere/templates/chimere/detail.html
@@ -20,8 +20,8 @@
{% if marker.description %}
<p class='description'>{{ marker.description|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td tr th"|safe}}</p>
{% endif %}
- {% for property in marker.getProperties %}
- <p class='{{property.propertymodel.getNamedId}}'>{{ property.value|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td tr th"|safe}}</p>
+ {% for property in properties %}
+ <p class='{{property.propertymodel.getNamedId}}'><strong>{{property.propertymodel}}</strong>{% trans ":" %} {{ property.value|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td tr th"|safe}}</p>
{% endfor %}
{% if marker.origin %}<p class='detail_source'><strong>{% trans "Source:" %}</strong> <span>{{marker.origin}}</span></p>{% endif %}
{% if marker.license %}<p class='detail_license'><strong>{% trans "License:" %}</strong> <span>{{marker.license}}</span></p>{% endif %}
@@ -30,13 +30,14 @@
</p>{% endif %}
</div>
{% share_bar marker.name %}
- <p class='detail_amendment'><a href='{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{%else%}{% url chimere:edit-item area_name_slash|default_if_none:"" marker.pk "" %}{%endif%}'>
+ <p class='detail_amendment'><a href='{% if marker.polygon %}{% url chimere:editpolygon-item area_name_slash|default_if_none:"" marker.pk "" %}{% else %}{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{% else %}{% url chimere:editmarker-item area_name_slash|default_if_none:"" marker.pk "" %}{% endif %}{% endif %}'>
{% trans "Submit an amendment" %}
</a>
{% if moderator_emails %}
<a href="mailto:?from={{moderator_emails}}&subject={% trans "Propose amendment" %}&body={% trans "I would like to propose an amendment for this item:"%} {{share_url}}">
{% trans "Propose amendment" %}
</a>{%endif%}
+ </p>
</div>
{% if marker.multimedia_items %}
<div id='gallery-{{time_now}}' class='gallery'>
diff --git a/chimere/templates/chimere/edit.html b/chimere/templates/chimere/edit.html
index 0e1b849..ab5bb4b 100644
--- a/chimere/templates/chimere/edit.html
+++ b/chimere/templates/chimere/edit.html
@@ -22,58 +22,58 @@
{% endif %}</fieldset>
{% if is_modification and is_superuser %}<div class='warning'><p>{% trans "You are logged as an administrator. Your modifications will be taking into account immediately." %}</p></div>{% endif %}
<fieldset class='edit'>
- <legend>{% if is_modification %}{% trans "Modify a point of interest" %}{% else %}{% trans "Add a point of interest" %}{% endif %}</legend>
+ {% block legend %}<legend>{% if is_modification %}{% trans "Modify a point of interest" %}{% else %}{% trans "Add a point of interest" %}{% endif %}</legend>{% endblock %}
<form enctype="multipart/form-data" method='post' action='.'>
{% csrf_token %}
<div class='rightWrapper'>
<div class='rightform'>
- <div class="fieldWrapper">
+ <div class="fieldWrapper full">
+ {% block geometry %}
<label for="id_point">{% trans "Point"%} *</label>
{%if form.point.errors %}<ul class="errorlist"><li>{% trans "Select a location for this new site" %}</li></ul>{%endif%}
{{point_widget}}
+ {% endblock %}
</div>
</div>
</div>
<div class='leftform'>
<p>* {% trans "indicates a mandatory field" %}</p>
+ <div class="fieldWrapper full">
+ <label for="id_subcategory">{% if form.categories.label %}{{ form.categories.label }}{% else %}{% trans "Categories" %} *{% endif %}</label>
+ {% if form.categories.errors %}<div class='errors'>{{ form.categories.errors }}</div>{% endif %}
+ {{ form.categories }}
+ </div>
<div class="fieldWrapper">
<label for="id_name">{% trans "Name"%} *</label>
{% if form.name.errors %}<div class='errors'>{{ form.name.errors }}</div>{% endif %}
{{ form.name }}
</div>
<div class="fieldWrapper">
- <label for="id_subcategory">{% trans "Categories" %} *</label>
- {% if form.categories.errors %}<div class='errors'>{{ form.categories.errors }}</div>{% endif %}
- {{ form.categories }}
- </div>
- <div class="fieldWrapper">
<label for="id_description">{% trans "Description" %}</label>
{{ form.description.errors }}
{{ form.description }}
<p class="help">{{ form.description.help_text }}</p>
</div>
- <div class="fieldWrapper">
+ {% if form.keywords %}<div class="fieldWrapper">
<label for="id_keywords">{% trans "Keywords" %}</label>
{{ form.keywords.errors }}
{{ form.keywords }}
<p class="help">{{ form.keywords.help_text }}</p>
- </div>
+ </div>{% endif %}
{% if dated %}
- <div class="fieldWrapper">
+ <div class="fieldWrapper full">
<label for="id_start_date">{% trans "Start date" %}</label>
{{ form.start_date.errors }}
{{ form.start_date }}
<p class="help">{{ form.start_date.help_text }}</p>
</div>
- <div class="fieldWrapper">
+ <div class="fieldWrapper full">
<label for="id_end_date">{% trans "End date" %}</label>
{{ form.end_date.errors }}
{{ form.end_date }}
<p class="help">{{ form.end_date.help_text }}</p>
</div>
{% endif %}
- </div>
- <div class='bottomform'>
{% for field in form %}
{% for property in properties %}
{% ifequal field.name property.getNamedId %}
@@ -85,6 +85,8 @@
{%endifequal%}
{%endfor%}
{%endfor%}
+ </div>
+ <div class='bottomform'>
{% inline_formset "Multimedia files" formset_multi %}
{% inline_formset "Picture files" formset_picture %}
@@ -100,11 +102,11 @@
cat_filters['{{subcat.id}}'].push('#id_{{property.getNamedId}}');
{% endfor %}
{% endfor %}
- $('#id_categories').change(function(){
+ $('.bsmSelect').change(function(){
for (idx in cat_to_hide){
$(cat_to_hide[idx]).parent().hide();
}
- var vals = $(this).val();
+ var vals = $('#id_categories').val();
for (val_id in vals){
var val = vals[val_id];
for (ids in cat_filters[val]){
@@ -112,7 +114,7 @@
}
}
});
- $('#id_categories').change();
+ $('.bsmSelect').change();
</script>
{% endif %}
</div>
@@ -131,7 +133,7 @@
{% if form.submiter_email.errors %}<div class='errors'>{{ form.submiter_email.errors }}</div>{% endif %}
{{ form.submiter_email }}
</div>
- <div class="fieldWrapper">
+ <div class="fieldWrapper full">
<label for="id_submiter_comment">{% trans "Comments about your submission"%}</label>
{% if form.submiter_comment.errors %}<div class='errors'>{{ form.submiter_comment.errors }}</div>{% endif %}
{{ form.submiter_comment }}
diff --git a/chimere/templates/chimere/edit_polygon.html b/chimere/templates/chimere/edit_polygon.html
new file mode 100644
index 0000000..7bba0d0
--- /dev/null
+++ b/chimere/templates/chimere/edit_polygon.html
@@ -0,0 +1,12 @@
+{% extends "chimere/edit.html" %}
+{% load i18n chimere_tags adminmedia inline_formset%}
+
+{% block legend %}
+<legend>{% if is_modification %}{% trans "Modify a polygon" %}{% else %}{% trans "Add a polygon" %}{% endif %}</legend>
+{% endblock %}
+
+{% block geometry %}
+<label for="id_polygon">{% trans "Polygon"%} *</label>
+{%if form.polygon.errors %}<ul class="errorlist"><li>{% trans "Draw the associated polygon" %}</li></ul>{%endif%}
+{{polygon_widget}}
+{% endblock %}
diff --git a/chimere/templates/chimere/main_map.html b/chimere/templates/chimere/main_map.html
index a3dec9a..45423ba 100644
--- a/chimere/templates/chimere/main_map.html
+++ b/chimere/templates/chimere/main_map.html
@@ -45,6 +45,8 @@
{% endblock %}
{% block content %}
{{block.super}}
+ <div id='popup'></div>
+ <div id='layerSwitcher'></div>
<div id='main-map'></div>
<script type="text/javascript">
$("#main-map").show();
diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py
index 61a1ab9..6f1f3a8 100644
--- a/chimere/templatetags/chimere_tags.py
+++ b/chimere/templatetags/chimere_tags.py
@@ -9,7 +9,7 @@ from django import template
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
-from django.db.models import Q, Count
+from django.db.models import Q
from django.template import defaultfilters
from django.utils.translation import ugettext as _
from django.template.loader import render_to_string
@@ -21,6 +21,7 @@ log = getLogger(__name__)
register = template.Library()
+
@register.inclusion_tag('chimere/blocks/areas.html', takes_context=True)
def display_areas(context):
"""
@@ -33,45 +34,50 @@ def display_areas(context):
context_data['area_name'] = context["area_name"]
return context_data
+
@register.inclusion_tag('chimere/blocks/submited.html', takes_context=True)
def submited(context):
"""
Submited message.
"""
- return {"edit_url":reverse('chimere:edit'),
- "index_url":reverse('chimere:index'),
- 'contact_email':settings.CONTACT_EMAIL \
- if hasattr(settings, 'CONTACT_EMAIL') else None}
+ return {"edit_url": reverse('chimere:edit'),
+ "index_url": reverse('chimere:index'),
+ 'contact_email':
+ settings.CONTACT_EMAIL if hasattr(settings, 'CONTACT_EMAIL')
+ else None}
+
def get_news(area=None):
# Retrieve news
news = News.objects.filter(available=True, is_front_page=True)
if area:
- news = news.filter(Q(areas__isnull=True)|Q(areas__in=[area.pk]))
+ news = news.filter(Q(areas__isnull=True) | Q(areas__in=[area.pk]))
news = list(news.all())
if settings.CHIMERE_DAYS_BEFORE_EVENT:
# Retrieve active markers
today = date.today()
after = today + timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)
- q = Marker.objects.filter(status='A', start_date__lte=after).filter(
- Q(end_date__gte=today)|
- (Q(end_date__isnull=True) & Q(start_date__gte=today)))
+ q = Marker.objects.filter(
+ status='A', start_date__lte=after).filter(
+ Q(end_date__gte=today) |
+ (Q(end_date__isnull=True) & Q(start_date__gte=today)))
- if not 'CHIMERE_ALL_DATED_ARE_FRONT' in dir(settings)\
+ if 'CHIMERE_ALL_DATED_ARE_FRONT' not in dir(settings)\
or not settings.CHIMERE_ALL_DATED_ARE_FRONT:
q = q.filter(is_front_page=True)
if area:
q = q.filter(area.getIncludeMarker())
news += list(q)
- news.sort(key=lambda x:x.date)
+ news.sort(key=lambda x: x.date)
return news
+
@register.inclusion_tag('chimere/blocks/welcome.html', takes_context=True)
def display_welcome(context, display=False, title=''):
"""
Welcome message and active news.
"""
- context_data = {'display':display}
+ context_data = {'display': display}
area = None
if "area_name" in context:
try:
@@ -90,16 +96,17 @@ def display_welcome(context, display=False, title=''):
context_data['news_lst'] = get_news(area)[:3]
context_data['STATIC_URL'] = settings.STATIC_URL
context_data['title'] = title if title \
- else _(u"Welcome to the %s") % settings.PROJECT_NAME
+ else _(u"Welcome to the %s") % settings.PROJECT_NAME
return context_data
+
@register.inclusion_tag('chimere/blocks/news.html', takes_context=True)
def display_news(context, title=''):
"""
All news.
"""
area = None
- context_data = {'STATIC_URL':settings.STATIC_URL}
+ context_data = {'STATIC_URL': settings.STATIC_URL}
if "area_name" in context:
try:
area = Area.objects.get(urn=context["area_name"])
@@ -110,27 +117,28 @@ def display_news(context, title=''):
context_data['news_lst'] = get_news(area)
return context_data
+
@register.inclusion_tag('chimere/blocks/head_jquery.html', takes_context=True)
def head_jquery(context):
"""
Create context and display head elements (js, css, etc.) for jquery.
"""
context_data = {
- "JQUERY_JS_URLS": settings.JQUERY_JS_URLS,
- "JQUERY_CSS_URLS": settings.JQUERY_CSS_URLS,
- }
+ "JQUERY_JS_URLS": settings.JQUERY_JS_URLS,
+ "JQUERY_CSS_URLS": settings.JQUERY_CSS_URLS,
+ }
return context_data
+
@register.inclusion_tag('chimere/blocks/head_jme.html', takes_context=True)
def head_jme(context):
"""
Create context and display head elements (js, css, etc.) for jme.
"""
- context_data = {
- "STATIC_URL": settings.STATIC_URL,
- }
+ context_data = {"STATIC_URL": settings.STATIC_URL}
return context_data
+
@register.inclusion_tag('chimere/blocks/head_chimere.html', takes_context=True)
def head_chimere(context):
"""
@@ -143,64 +151,71 @@ def head_chimere(context):
area = Area.objects.get(urn=area_name)
except ObjectDoesNotExist:
pass
+ action_selected = context.get('action_selected', None)
+ is_edit = action_selected and action_selected[0] == "contribute"
context_data = {
- "STATIC_URL": settings.STATIC_URL,
- "MEDIA_URL": settings.MEDIA_URL,
- "DYNAMIC_CATEGORIES": 'true' if area and area.dynamic_categories \
- else 'false',
- "EXTRA_URL": reverse("chimere:index"),
- "EPSG_DISPLAY_PROJECTION": settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- "EPSG_PROJECTION": settings.CHIMERE_EPSG_PROJECTION,
- "DEFAULT_CENTER": settings.CHIMERE_DEFAULT_CENTER,
- "DEFAULT_ZOOM": settings.CHIMERE_DEFAULT_ZOOM,
- "MAP_LAYER": settings.CHIMERE_DEFAULT_MAP_LAYER,
- "OSM_CSS_URLS": settings.OSM_CSS_URLS,
- 'MOBILE':context['MOBILE'],
- 'routing': settings.CHIMERE_ENABLE_ROUTING \
- if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') else False,
- 'enable_clustering':settings.CHIMERE_ENABLE_CLUSTERING,
- }
- context_data['OSM_JS_URLS'] = settings.OSM_JS_URLS
+ "is_edit": is_edit,
+ "STATIC_URL": settings.STATIC_URL,
+ "MEDIA_URL": settings.MEDIA_URL,
+ "DYNAMIC_CATEGORIES": 'true' if area and area.dynamic_categories
+ else 'false',
+ "EXTRA_URL": reverse("chimere:index"),
+ "EPSG_DISPLAY_PROJECTION": settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ "EPSG_PROJECTION": settings.CHIMERE_EPSG_PROJECTION,
+ "DEFAULT_CENTER": settings.CHIMERE_DEFAULT_CENTER,
+ "DEFAULT_ZOOM": settings.CHIMERE_DEFAULT_ZOOM,
+ "MAP_LAYER": settings.CHIMERE_DEFAULT_MAP_LAYER,
+ "MAP_CSS_URLS": settings.MAP_CSS_URLS,
+ 'MOBILE': context['MOBILE'],
+ 'routing':
+ settings.CHIMERE_ENABLE_ROUTING
+ if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') else False,
+ 'enable_clustering': settings.CHIMERE_ENABLE_CLUSTERING,
+ }
+ context_data['MAP_JS_URLS'] = settings.MAP_JS_URLS
if context['MOBILE']:
- context_data['OSM_JS_URLS'] = settings.OSM_MOBILE_JS_URLS
+ context_data['MAP_JS_URLS'] = settings.MAP_MOBILE_JS_URLS
return context_data
+
@register.inclusion_tag('chimere/blocks/head_form.html')
def head_form():
"""
Manualy add forms header (necessary in case of ajax load)
"""
- context_data = {
- "TINYMCE_URL": settings.TINYMCE_URL,
- }
+ context_data = {"TINYMCE_URL": settings.TINYMCE_URL}
return context_data
+
@register.inclusion_tag('chimere/blocks/map_menu.html', takes_context=True)
def map_menu(context):
- context_data = {'routing': settings.CHIMERE_ENABLE_ROUTING \
- if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') else False,
- 'simple':context.get('simple')}
+ context_data = {
+ 'routing': settings.CHIMERE_ENABLE_ROUTING
+ if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') else False,
+ 'simple': context.get('simple')}
return context_data
+
@register.inclusion_tag('chimere/blocks/routing.html', takes_context=True)
def routing(context):
if not hasattr(settings, 'CHIMERE_ENABLE_ROUTING') or \
not settings.CHIMERE_ENABLE_ROUTING:
- return {'routing':False}
- context_data = {
- 'routing':settings.CHIMERE_ENABLE_ROUTING,
- 'itinerary_form':context['itinerary_form'],
- 'routing_fail_message':_(settings.CHIMERE_ROUTING_FAIL_MESSAGE
- ).replace('\n', '\\n'),
- 'routing_transport':context['routing_transport']}
+ return {'routing': False}
+ context_data = {
+ 'routing': settings.CHIMERE_ENABLE_ROUTING,
+ 'itinerary_form': context['itinerary_form'],
+ 'routing_fail_message':
+ _(settings.CHIMERE_ROUTING_FAIL_MESSAGE).replace('\n', '\\n'),
+ 'routing_transport': context['routing_transport']}
context_data['STATIC_URL'] = settings.STATIC_URL
return context_data
+
@register.inclusion_tag('chimere/blocks/map.html', takes_context=True)
def map(context, map_id='map'):
- context_data = {'map_id':map_id,
- "STATIC_URL": settings.STATIC_URL,
- "enable_clustering":settings.CHIMERE_ENABLE_CLUSTERING}
+ context_data = {'map_id': map_id,
+ "STATIC_URL": settings.STATIC_URL,
+ "enable_clustering": settings.CHIMERE_ENABLE_CLUSTERING}
context_data['icon_offset_x'] = settings.CHIMERE_ICON_OFFSET_X
context_data['icon_offset_y'] = settings.CHIMERE_ICON_OFFSET_Y
context_data['icon_width'] = settings.CHIMERE_ICON_WIDTH
@@ -208,12 +223,15 @@ def map(context, map_id='map'):
context_data['MOBILE'] = context['MOBILE']
context_data['routing'] = 'true' \
if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') and \
- settings.CHIMERE_ENABLE_ROUTING \
+ settings.CHIMERE_ENABLE_ROUTING \
else 'false'
area_name = context['area_name'] if 'area_name' in context else 'area_name'
map_layers, default_area = get_map_layers(area_name)
+ context_data['extra_js'] = u'\n'.join([
+ extra_js for n, js, default, extra_js in map_layers if extra_js])
context_data['js_map_layers'] = ", ".join(
- [js for name, js, default in map_layers])
+ [js for name, js, default, extra_js in map_layers
+ if "OpenLayers" not in js])
context_data['map_layers'] = map_layers
if default_area:
context_data['selected_map_layer'] = default_area
@@ -235,24 +253,29 @@ def map(context, map_id='map'):
subcat_layer = subcat_layer.filter(areas__pk=area.pk)
context_data['area_id'] = area_name
if 'zoomout' in context and context['zoomout']:
- context_data['zoom'] = "[%s]" % ",".join((
- unicode(area.upper_left_corner.x),
- unicode(area.upper_left_corner.y),
- unicode(area.lower_right_corner.x),
- unicode(area.lower_right_corner.y)))
- if area.subcategories.filter(available=True).count() == 1:
- context_data['single_category'] = True
- context_data['checked_categories'] = area.subcategories.all()[0].pk
+ context_data['zoom'] = "[%s]" % ",".join(area.getExtent())
+ context_data['display_category_menu'] = area.display_category_menu
+ q_checked = None
+ if not area.display_category_menu:
+ if area.default_subcategories.count():
+ q_checked = area.default_subcategories
+ elif area.subcategories.count():
+ q_checked = area.subcategories
+ else:
+ q_checked = SubCategory.objects
elif area.default_subcategories.count():
- context_data['checked_categories'] = [s.pk
- for s in area.default_subcategories.all()]
+ q_checked = area.default_subcategories
+ if q_checked:
+ context_data['checked_categories'] = [
+ s.pk for s in q_checked.filter(available=True).all()]
if area.restrict_to_extent:
- context_data['restricted_extent'] = """
-var bounds = new OpenLayers.Bounds();
-bounds.extend(new OpenLayers.LonLat(%f, %f));
-bounds.extend(new OpenLayers.LonLat(%f, %f));
-""" % (area.upper_left_corner.x, area.upper_left_corner.y,
- area.lower_right_corner.x, area.lower_right_corner.y)
+ context_data['restricted_extent'] = \
+ "var bounds = new OpenLayers.Bounds();\n"\
+ "bounds.extend(new OpenLayers.LonLat(%f, %f));\n"\
+ "bounds.extend(new OpenLayers.LonLat(%f, %f));\n" % (
+ area.upper_left_corner.x, area.upper_left_corner.y,
+ area.lower_right_corner.x, area.lower_right_corner.y)
+ context_data['extra_map_def'] = area.extra_map_def or ''
context_data['subcat_layer'], c_cat = [], None
for subcat in subcat_layer.order_by('category__order', 'category').all():
if subcat.category != c_cat:
@@ -260,22 +283,23 @@ bounds.extend(new OpenLayers.LonLat(%f, %f));
c_cat = subcat.category
context_data['subcat_layer'].append(subcat)
if SubCategory.objects.filter(available=True).count() <= 1:
- context_data['single_category'] = True
if not context_data['checked_categories']:
cat = ''
if SubCategory.objects.filter(available=True).count():
cat = unicode(SubCategory.objects.filter(available=True
).all()[0].pk)
context_data['checked_categories'] = cat
- context_data['dynamic_categories'] = 'true' \
- if area and area.dynamic_categories else 'false'
+ context_data['dynamic_categories'] = \
+ 'true' if area and area.dynamic_categories else 'false'
if settings.CHIMERE_ROUTING_TRANSPORT:
- context_data['p_routing_transport'] = settings.CHIMERE_ROUTING_TRANSPORT[0][0]
+ context_data['p_routing_transport'] = \
+ settings.CHIMERE_ROUTING_TRANSPORT[0][0]
if settings.CHIMERE_ROUTING_SPEEDS and \
- context_data['p_routing_transport'] in settings.CHIMERE_ROUTING_SPEEDS:
+ context_data['p_routing_transport'] \
+ in settings.CHIMERE_ROUTING_SPEEDS:
context_data['p_routing_speed'] = \
settings.CHIMERE_ROUTING_SPEEDS[
- context_data['p_routing_transport']][0][0]
+ context_data['p_routing_transport']][0][0]
if 'request' not in context:
return context_data
request = context['request']
@@ -283,31 +307,34 @@ bounds.extend(new OpenLayers.LonLat(%f, %f));
context_data['p_current_route'] = context.get('current_route')
if request.GET:
for key in ('zoom', 'lon', 'lat', 'display_submited',
- 'current_feature', 'routing_start_lon', 'routing_start_lat',
- 'routing_end_lon', 'routing_end_lat', 'routing_steps',
- 'routing_transport', 'routing_speed'):
+ 'current_feature', 'routing_start_lon',
+ 'routing_start_lat', 'routing_end_lon', 'routing_end_lat',
+ 'routing_steps', 'routing_transport', 'routing_speed'):
p_key = 'p_' + key
if key in request.GET and request.GET[key]:
context_data[p_key] = request.GET[key]
elif p_key not in context_data:
- context_data['p_'+key] = None
+ context_data['p_' + key] = None
if 'checked_categories' in request.GET \
and request.GET['checked_categories']:
cats = request.GET['checked_categories'].split('_')
context_data['checked_categories'] = cats
return context_data
+
@register.inclusion_tag('chimere/blocks/multimedia_file.html',
takes_context=True)
def multimedia_render(context, multimedia_file):
context['multimedia_item'] = multimedia_file
return context
+
@register.inclusion_tag('chimere/blocks/alternate_multimedia.html')
def alternate_multimedia(formset_multi, formset_picture):
- return {'formsets':[formset_multi, formset_picture],
+ return {'formsets': [formset_multi, formset_picture],
"STATIC_URL": settings.STATIC_URL,
- 'auto_type_id':MultimediaType.objects.get(name='auto').pk}
+ 'auto_type_id': MultimediaType.objects.get(name='auto').pk}
+
@register.simple_tag
def get_tinyfied_url(marker, area_name=''):
@@ -316,6 +343,7 @@ def get_tinyfied_url(marker, area_name=''):
url = marker.get_absolute_url(area_name)
return url
+
@register.inclusion_tag('chimere/blocks/share_bar.html',
takes_context=True)
def share_bar(context, name='', email_only=False, rss=True):
@@ -323,17 +351,19 @@ def share_bar(context, name='', email_only=False, rss=True):
context['name'] = name
context['rss'] = rss
context['email_only'] = email_only
- context['share_networks'] = [(defaultfilters.slugify(name), url, icon)
- for name, url, icon in settings.CHIMERE_SHARE_NETWORKS]
+ context['share_networks'] = [
+ (defaultfilters.slugify(nme), url, icon)
+ for nme, url, icon in settings.CHIMERE_SHARE_NETWORKS]
return context
+
@register.filter(name='ol_map')
def ol_map(item, arg='map_id'):
- geom, geom_type = None, None
+ geom = None
if hasattr(item, 'point'):
- geom, geom_type = item.point, 'point'
+ geom = item.point
elif hasattr(item, 'route'):
- geom, geom_type = item.route, 'route'
+ geom = item.route
rendered = render_to_string('chimere/blocks/ol_map.html', {'geom': geom,
- 'map_id':arg})
+ 'map_id': arg})
return rendered
diff --git a/chimere/templatetags/unescape.py b/chimere/templatetags/unescape.py
index 59809a3..18bdf86 100644
--- a/chimere/templatetags/unescape.py
+++ b/chimere/templatetags/unescape.py
@@ -6,6 +6,7 @@ import HTMLParser
register = template.Library()
+
def unescape(value):
parser = HTMLParser.HTMLParser()
return parser.unescape(value)
@@ -13,3 +14,28 @@ def unescape(value):
register.filter(unescape)
+def raw(parser, token):
+ # Whatever is between {% raw %} and {% endraw %} will be preserved as
+ # raw, unrendered template code.
+ text = []
+ parse_until = 'endraw'
+ tag_mapping = {
+ template.TOKEN_TEXT: ('', ''),
+ template.TOKEN_VAR: ('{{', '}}'),
+ template.TOKEN_BLOCK: ('{%', '%}'),
+ template.TOKEN_COMMENT: ('{#', '#}'),
+ }
+ # By the time this template tag is called, the template system has already
+ # lexed the template into tokens. Here, we loop over the tokens until
+ # {% endraw %} and parse them to TextNodes. We have to add the start and
+ # end bits (e.g. "{{" for variables) because those have already been
+ # stripped off in a previous part of the template-parsing process.
+ while parser.tokens:
+ token = parser.next_token()
+ if token.token_type == template.TOKEN_BLOCK and \
+ token.contents == parse_until:
+ return template.TextNode(u''.join(text))
+ start, end = tag_mapping[token.token_type]
+ text.append(u'%s%s%s' % (start, token.contents, end))
+ parser.unclosed_block_tag(parse_until)
+raw = register.tag(raw)
diff --git a/chimere/urls.py b/chimere/urls.py
index 913abe1..966ef4f 100644
--- a/chimere/urls.py
+++ b/chimere/urls.py
@@ -25,25 +25,29 @@ admin.autodiscover()
from chimere.views import CategoryDirectoryView, CategoryView
from chimere.feeds import LatestPOIsByCategory, LatestPOIsBySubCategory, \
- LatestPOIs, LatestPOIsByZone, LatestPOIsByZoneID
+ LatestPOIs, LatestPOIsByZone, LatestPOIsByZoneID
def i18n_javascript(request):
return admin.site.i18n_javascript(request)
-urlpatterns = patterns('chimere.views',
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?simple$', 'index', {'simple':True},
+urlpatterns = patterns(
+ 'chimere.views',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?simple$', 'index', {'simple': True},
name="simple_index")
)
if settings.CHIMERE_FEEDS:
- urlpatterns += patterns('',
+ urlpatterns += patterns(
+ '',
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds$', 'chimere.views.rss',
name='feeds-form'),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/category/(?P<category_id>\d+)$',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/category/'
+ r'(?P<category_id>\d+)$',
LatestPOIsByCategory(), name='feeds-cat'),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/subcategory/(?P<category_id>\d+)$',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/subcategory/'
+ r'(?P<category_id>\d+)$',
LatestPOIsBySubCategory(), name='feeds-subcat'),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/global/$', LatestPOIs(),
name='feeds-global'),
@@ -56,17 +60,19 @@ if settings.CHIMERE_FEEDS:
if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') \
and settings.CHIMERE_ENABLE_ROUTING:
if not hasattr(settings, 'CHIMERE_ROUTING_TRANSPORT') \
- or not settings.CHIMERE_ROUTING_TRANSPORT:
- raise ImproperlyConfigured(u"CHIMERE_ROUTING_TRANSPORT must be set in"\
+ or not settings.CHIMERE_ROUTING_TRANSPORT:
+ raise ImproperlyConfigured(u"CHIMERE_ROUTING_TRANSPORT must be set in"
u" settings if you enable routing")
- urlpatterns += patterns('chimere.views',
- url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?route/'\
+ urlpatterns += patterns(
+ 'chimere.views',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?route/'
r'(?P<transport>(%s))/((?P<speed>[0-9][0-9]*)/)?'
- r'(?P<lon1>[-]?[0-9]+[.]?[0-9]*)_(?P<lat1>[-]?[0-9]+[.]?[0-9]*)_'\
- r'(?P<lonlat_steps>([-]?[0-9]+[.]?[0-9]*_[-]?[0-9]+[.]?[0-9]*_)*)'\
+ r'(?P<lon1>[-]?[0-9]+[.]?[0-9]*)_(?P<lat1>[-]?[0-9]+[.]?[0-9]*)_'
+ r'(?P<lonlat_steps>([-]?[0-9]+[.]?[0-9]*_[-]?[0-9]+[.]?[0-9]*_)*)'
r'(?P<lon2>[-]?[0-9]+[.]?[0-9]*)_(?P<lat2>[-]?[0-9]+[.]?[0-9]*)$' %
- ('|'.join([key for key, lbl in settings.CHIMERE_ROUTING_TRANSPORT])),
- 'route', name="route"),
+ ('|'.join([key
+ for key, lbl in settings.CHIMERE_ROUTING_TRANSPORT])),
+ 'route', name="route"),
)
if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \
@@ -74,7 +80,8 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \
from chimere.forms import SearchForm
from chimere.views import SearchView
from haystack.views import search_view_factory
- urlpatterns += patterns('chimere.views',
+ urlpatterns += patterns(
+ 'chimere.views',
url(r'^search/?$', search_view_factory(
view_class=SearchView,
template='search/search.html',
@@ -83,49 +90,66 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \
url(r'^search/autocomplete/$', 'autocomplete',
name='autocomplete-search')
)
- #urlpatterns += [url(r'^search/', include('haystack.urls')),]
+ # urlpatterns += [url(r'^search/', include('haystack.urls')),]
-urlpatterns += patterns('chimere.views',
+urlpatterns += patterns(
+ 'chimere.views',
url(r'^charte/?$', 'charte', name="charte"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?contact/?$', 'contactus',
name="contact"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit/$', 'edit',
name="edit"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit/(?P<item_id>\w+)/(?P<submited>\w+)?$',
- 'edit', name="edit-item"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-marker/'
+ r'(?P<submited>\w+)?$', 'editMarker', name="editmarker"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-marker/(?P<item_id>\w+)/'
+ r'(?P<submited>\w+)?$', 'editMarker', name="editmarker-item"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-route/$', 'editRoute',
name="editroute"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-route/(?P<item_id>\w+)/(?P<submited>\w+)?$',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-route/(?P<item_id>\w+)/'
+ r'(?P<submited>\w+)?$',
'editRoute', name="editroute-item"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDetail/(?P<marker_id>\d+)/?$', 'getDetail',
- name="get_detail"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDescriptionDetail/?(?P<category_id>\d+)/?$',
- 'getDescriptionDetail', name="get_description_detail"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getGeoObjects/'\
- r'(?P<category_ids>[a-zA-Z0-9_-]+)(/(?P<status>\w+))?$', 'getGeoObjects',
- name="getgeoobjects"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?get-marker/'\
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-polygon/$', 'editPolygon',
+ name="editpolygon"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-polygon/(?P<item_id>\w+)/'
+ r'(?P<submited>\w+)?$',
+ 'editPolygon', name="editpolygon-item"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDetail/'
+ r'(?P<key>[a-zA-Z_-]*\d+)/?$',
+ 'getDetail', name="get_detail"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDetail/undefined',
+ 'getDetailUndefined', name="get_detail_undefined"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDescriptionDetail/'
+ r'?(?P<category_id>\d+)/?$', 'getDescriptionDetail',
+ name="get_description_detail"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getGeoObjects/'
+ r'(?P<category_ids>[a-zA-Z0-9_-]+)(/(?P<status>\w+))?$',
+ 'getGeoObjects', name="getgeoobjects"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?get-marker/'
r'(?P<pk>[0-9]+)$', 'getMarker', name="get-marker"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getAvailableCategories/$',
- 'get_available_categories', name="get_categories"),
+ 'get_available_categories', name="get_categories"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getAllCategories/$',
- 'get_all_categories', name="get_all_categories"),
+ 'get_all_categories', name="get_all_categories"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getCategory/(?P<category_id>\d+)/?$',
- 'getCategory', name="get_category"),
+ 'getCategory', name="get_category"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?get-share-url/(?P<network>\w+)?$',
- 'getShareUrl', name="get-share-url"),
+ 'getShareUrl', name="get-share-url"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?ty/(?P<tiny_urn>\w+)$',
- 'redirectFromTinyURN', name="tiny"),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?upload_file/((?P<category_id>\w+)/)?$',
- 'uploadFile', name='upload_file'),
- url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?process_route_file/(?P<file_id>\d+)/$',
- 'processRouteFile', name='process_route_file'),
+ 'redirectFromTinyURN', name="tiny"),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?upload_file/'
+ r'((?P<category_id>\w+)/)?$', 'uploadFile', name='upload_file'),
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?process_route_file/'
+ r'(?P<file_id>\d+)/$', 'processRouteFile', name='process_route_file'),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?dyn/(?P<page_id>\w+)/$',
- 'extraPage', name='extra_page'),
+ 'extraPage', name='extra_page'),
url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?categories/$',
CategoryDirectoryView.as_view(), name='category-directory'),
- url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?categories/(?P<category_slug>[a-zA-Z0-9_-]+)$',
+ url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?categories/'
+ r'(?P<category_slug>[a-zA-Z0-9_-]+)$',
CategoryView.as_view(), name='category-directory-detail'),
+ url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?property-choices/'
+ r'(?P<property_slug>[a-zA-Z0-9_-]+)/$',
+ 'property_choice_list', name='property-choices'),
# At the end, because it catches large
url(r'^(?P<area_name>[a-zA-Z0-9_-]+)?', 'index', name="index"),
)
diff --git a/chimere/utils.py b/chimere/utils.py
index 01ae585..9bdff58 100644
--- a/chimere/utils.py
+++ b/chimere/utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2012-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2012-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
@@ -80,6 +80,7 @@ class ImportManager(object):
def create_or_update_item(self, cls, values, import_key, version=None,
key='', pk=None, category=None):
+ from models import PropertyModel
updated, created, item = False, False, None
import_key = unicode(import_key).replace(':', '^')
if not values.get('name'):
@@ -87,6 +88,11 @@ class ImportManager(object):
if not key:
key = self.importer_instance.importer_type
item = None
+ pms = [pm["slug"] for pm in PropertyModel.objects.values('slug').all()]
+ properties = {}
+ for k in values.keys():
+ if k in pms:
+ properties[k] = values.pop(k)
if import_key or pk:
dct_import = {
'import_key__icontains': '%s:%s;' % (key, import_key),
@@ -134,6 +140,7 @@ class ImportManager(object):
if not self.importer_instance.associate_marker_to_way\
and cls.__name__ == 'Route':
values['has_associated_marker'] = False
+
try:
item = cls.objects.create(**values)
item.modified_since_import = False
@@ -150,6 +157,8 @@ class ImportManager(object):
else:
for cat in self.importer_instance.categories.all():
item.categories.add(cat)
+ for prop in properties:
+ item.setProperty(prop, properties[prop])
return item, updated, created
@classmethod
@@ -332,8 +341,11 @@ class ShapefileManager(ImportManager):
- number of new item ;
- number of item updated ;
- error detail on error
+
+ The filtr argument allow to specify match between the shapefile cols
+ and the db. JSON format is used.
"""
- from models import Marker, Route
+ from models import Marker, Route, Polygon
new_item, updated_item, msg = 0, 0, ''
tmpdir = tempfile.mkdtemp()
sources, msg = self.get_source_file(['.shp', '.dbf', '.prj', '.shx'],
@@ -366,52 +378,92 @@ class ShapefileManager(ImportManager):
shapefilename = tmpdir + os.sep + sources[0]
ds = DataSource(shapefilename)
lyr = ds[0]
- # for this first version it is assumed that the first field is a
- # id name and the second field is the name
- id_name = lyr.fields[0] if len(lyr.fields) > 0 else None
- # test if id_name is well guess
- if id_name:
- ids = lyr.get_fields(id_name)
- if len(ids) != len(set(ids)):
- id_name = None
- lbl_name = None
- if len(lyr.fields) > 1:
- lbl_name = lyr.fields[1]
- elif id_name:
- lbl_name = id_name
- if lyr.geom_type not in ('Point', 'LineString'):
+ default_dct = {}
+ filtr = self.importer_instance.filtr
+ if filtr:
+ try:
+ filtr = json.JSONDecoder().decode(self.importer_instance.filtr)
+ except ValueError:
+ return (
+ new_item, updated_item,
+ _(u"Bad configuration: filter must be a valid "
+ u"JSON string"))
+ for k in ('id',):
+ if k not in filtr:
+ return (
+ new_item, updated_item,
+ _(u"The key \"%s\" is missing in the "
+ u"filter.") % k)
+ for k in filtr:
+ try:
+ ids = lyr.get_fields(k)
+ except:
+ return (
+ new_item, updated_item,
+ _(u"Config: {} is not an appropriate column name "
+ u"for this Shapefile. Available columns "
+ u" are: {}").format(k, u", ".join(
+ [j for j in lyr.fields])))
+ default_dct = {'origin': self.importer_instance.origin,
+ 'license': self.importer_instance.license}
+ if 'prefix_name' in filtr:
+ default_dct['name'] = filtr.pop('prefix_name')
+ if 'prefix_description' in filtr:
+ default_dct['description'] = filtr.pop('prefix_description')
+ else:
+ # if no filtr it is assumed that the first field is a
+ # id name and the second field is the name
+ id_name = lyr.fields[0] if len(lyr.fields) > 0 else None
+ # test if id_name is well guess
+ if id_name:
+ ids = lyr.get_fields(id_name)
+ if len(ids) != len(set(ids)):
+ id_name = None
+ filtr['id'] = id_name
+ if len(lyr.fields) > 1:
+ filtr["name"] = lyr.fields[1]
+ elif id_name:
+ filtr["name"] = id_name
+
+ if lyr.geom_type not in ('Point', 'LineString', 'Polygon'):
return (0, 0, _(u"Type of geographic item (%s) of this shapefile "
u"is not managed by Chimère.") % lyr.geom_type)
- geom_key = 'point' if lyr.geom_type == 'Point' else 'route'
- geom_cls = Marker if lyr.geom_type == 'Point' else Route
+ geom_key = ''
+ geom_cls = None
+ if lyr.geom_type == 'Point':
+ geom_key = 'point'
+ geom_cls = Marker
+ elif lyr.geom_type == 'Polygon':
+ geom_key = 'polygon'
+ geom_cls = Polygon
+ else:
+ geom_key = 'route'
+ geom_cls = Route
# indexes = []
for idx, feat in enumerate(lyr):
- name = unicode(idx)
- if lbl_name:
- name = feat.get(lbl_name)
+ dct = default_dct.copy()
+ for k in filtr:
+ val = feat.get(k)
try:
- name = unicode(name)
+ val = unicode(val)
except UnicodeDecodeError:
try:
- name = unicode(
- name.decode(settings.CHIMERE_SHAPEFILE_ENCODING))
+ val = unicode(
+ val.decode(settings.CHIMERE_SHAPEFILE_ENCODING))
except:
continue
+ if filtr[k] not in dct:
+ dct[filtr[k]] = ''
+ dct[filtr[k]] += val
try:
geoms = [feat.geom.wkt]
except:
return (0, 0, _(u"Bad Shapefile"))
if feat.geom.geom_type == 'MultiLineString':
geoms = [geom.wkt for geom in feat.geom]
- import_key = feat.get(id_name) if id_name and len(geoms) == 1 \
- else ''
+ import_key = dct.pop('id')
for geom in geoms:
- dct = {
- geom_key: 'SRID=%s;%s' % (srid, geom),
- 'name': name,
- 'origin': self.importer_instance.origin,
- 'license': self.importer_instance.license
- }
+ dct[geom_key] = 'SRID=%s;%s' % (srid, geom)
item, updated, created = self.create_or_update_item(
geom_cls, dct, import_key)
if updated:
diff --git a/chimere/views.py b/chimere/views.py
index 7ac7148..a95357f 100644
--- a/chimere/views.py
+++ b/chimere/views.py
@@ -27,20 +27,18 @@ Views of the project
import datetime
from itertools import groupby
import re
-import simplejson as json
from django.conf import settings
-from django.contrib.gis.geos import GEOSGeometry
+from django.contrib.gis.geos import GEOSGeometry, Polygon as GEOSPolygon
from django.contrib.gis.gdal.error import OGRException
from django.contrib.gis.measure import D
from django.contrib.sites.models import get_current_site
-from django.core import serializers
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.shortcuts import get_object_or_404, redirect, render_to_response
-from django.template import loader, RequestContext, defaultfilters
+from django.template import RequestContext, defaultfilters
from django.utils import simplejson as json
from django.utils.http import urlquote
from django.utils.translation import ugettext as _
@@ -48,17 +46,18 @@ from django.views.generic import TemplateView, ListView
from chimere.actions import actions
from chimere.models import Category, SubCategory, PropertyModel, Page,\
- Marker, Route, News, SimpleArea, Area, Color, TinyUrl, RouteFile,\
- AggregatedRoute
+ Marker, Route, Polygon, SimpleArea, Area, Color, TinyUrl, RouteFile,\
+ AggregatedRoute, AggregatedPolygon, PropertyModelChoice
-from chimere.widgets import getMapJS, PointChooserWidget, \
- RouteChooserWidget, AreaWidget
+from chimere.widgets import PointChooserWidget, RouteChooserWidget, AreaWidget,\
+ PolygonChooserWidget
from chimere.forms import MarkerForm, RouteForm, ContactForm, FileForm, \
- FullFileForm, MultimediaFileFormSet, PictureFileFormSet, notifySubmission,\
- notifyStaff, AreaForm, RoutingForm, getStaffEmails
+ FullFileForm, MultimediaFileFormSet, PictureFileFormSet, notifySubmission,\
+ notifyStaff, AreaForm, RoutingForm, PolygonForm
from chimere.route import router
+
def get_base_uri(request):
base_uri = 'http://'
if 'HTTP_REFERER' in request.META:
@@ -71,14 +70,17 @@ def get_base_uri(request):
base_uri += ":" + str(request.META['SERVER_PORT'])
return base_uri
-#TODO: convert to requestcontext
+# TODO: convert to requestcontext
+
+
def get_base_response(request, area_name=""):
"""
Get the base url
"""
- base_response_dct = {'media_path':settings.MEDIA_URL,}
- base_response_dct['MOBILE'] = settings.MOBILE_TEST or \
- get_current_site(request).domain in settings.MOBILE_DOMAINS
+ base_response_dct = {'media_path': settings.MEDIA_URL}
+ base_response_dct['MOBILE'] = \
+ settings.MOBILE_TEST or \
+ get_current_site(request).domain in settings.MOBILE_DOMAINS
base_url = reverse("chimere:index")
if not base_url.startswith('/'):
base_url = '/' + base_url
@@ -107,8 +109,8 @@ def get_base_response(request, area_name=""):
base_response_dct['area_name'] = area_name
if area and area.external_css:
base_response_dct['css_area'] = area.external_css
- base_response_dct['dynamic_categories'] = True \
- if area and area.dynamic_categories else False
+ base_response_dct['dynamic_categories'] = \
+ True if area and area.dynamic_categories else False
base_response_dct['JQUERY_JS_URLS'] = settings.JQUERY_JS_URLS
base_response_dct['JQUERY_CSS_URLS'] = settings.JQUERY_CSS_URLS
base_response_dct['PROJECT_NAME'] = settings.PROJECT_NAME
@@ -116,6 +118,7 @@ def get_base_response(request, area_name=""):
base_response_dct['EXTRA_CSS'] = settings.EXTRA_CSS
return base_response_dct, None
+
def getShareUrl(request, area_name='', network=''):
"""
Get a share url
@@ -123,9 +126,11 @@ def getShareUrl(request, area_name='', network=''):
data = getTinyfiedUrl(request, request.GET.urlencode(), area_name)
for name, url, img in settings.CHIMERE_SHARE_NETWORKS:
if defaultfilters.slugify(name) == network:
- return HttpResponse(url % {'text':data['text'], 'url':data['url']})
+ return HttpResponse(url % {'text': data['text'],
+ 'url': data['url']})
return HttpResponse('')
+
def getShareNetwork(request, area_name='', marker=None):
"""
Get URLs to share items
@@ -133,14 +138,15 @@ def getShareNetwork(request, area_name='', marker=None):
parameters = ""
if marker:
parameters = u'current_feature=%d' % marker.pk
- parameters += u"&checked_categories=%s" % "_".join([str(m.id) \
- for m in marker.categories.all()])
+ parameters += u"&checked_categories=%s" % "_".join(
+ [str(m.id) for m in marker.categories.all()])
net_dct = getTinyfiedUrl(request, parameters, area_name)
share_networks = []
for network in settings.CHIMERE_SHARE_NETWORKS:
share_networks.append((network[0], network[1] % net_dct, network[2]))
return share_networks, net_dct
+
def index(request, area_name=None, default_area=None, simple=False,
get_response=False):
"""
@@ -150,7 +156,7 @@ def index(request, area_name=None, default_area=None, simple=False,
# only if user is not came yet today
today = datetime.date.today().strftime('%y-%m-%d')
news_visible = False
- if not 'last_visit' in request.session or \
+ if 'last_visit' not in request.session or \
request.session['last_visit'] != today:
request.session['last_visit'] = today
news_visible = True
@@ -160,7 +166,7 @@ def index(request, area_name=None, default_area=None, simple=False,
# don't mess with permalink
zoomout = True
if request.GET and 'lat' in request.GET \
- and 'lon' in request.GET:
+ and 'lon' in request.GET:
zoomout = None
if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') and \
settings.CHIMERE_ENABLE_ROUTING:
@@ -174,24 +180,25 @@ def index(request, area_name=None, default_area=None, simple=False,
except:
pass
response_dct.update({
- 'actions':actions(response_dct['area_name']),
- 'action_selected':('view',),
- 'error_message':'',
- 'is_map':True,
- 'news_visible': news_visible,
- 'areas_visible': settings.CHIMERE_DISPLAY_AREAS,
- 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER,
- 'dynamic_categories':response_dct['dynamic_categories'],
- 'zoomout':zoomout,
- 'has_default_area':Area.objects.filter(default=True).count(),
- 'zoomout':zoomout,
- 'has_search':hasattr(settings, 'CHIMERE_SEARCH_ENGINE') and \
- settings.CHIMERE_SEARCH_ENGINE
- })
+ 'actions': actions(response_dct['area_name']),
+ 'action_selected': ('view',),
+ 'error_message': '',
+ 'is_map': True,
+ 'news_visible': news_visible,
+ 'areas_visible': settings.CHIMERE_DISPLAY_AREAS
+ and Area.objects.filter(available=True).count() > 1,
+ 'map_layer': settings.CHIMERE_DEFAULT_MAP_LAYER,
+ 'dynamic_categories': response_dct['dynamic_categories'],
+ 'zoomout': zoomout,
+ 'has_default_area': Area.objects.filter(default=True).count(),
+ 'zoomout': zoomout,
+ 'has_search': hasattr(settings, 'CHIMERE_SEARCH_ENGINE') and
+ settings.CHIMERE_SEARCH_ENGINE
+ })
if hasattr(settings, 'CONTACT_EMAIL') and settings.CONTACT_EMAIL:
response_dct['contact_email'] = settings.CONTACT_EMAIL
response_dct['share_networks'], net_dct = \
- getShareNetwork(request, response_dct['area_name'])
+ getShareNetwork(request, response_dct['area_name'])
tpl = 'chimere/main_map.html'
response_dct['simple'] = simple
if simple:
@@ -201,6 +208,20 @@ def index(request, area_name=None, default_area=None, simple=False,
return render_to_response(tpl, response_dct,
context_instance=RequestContext(request))
+
+def edit(request, area_name="", item_id=None, submited=False):
+ """
+ Edition page
+ """
+ response_dct, redir = get_base_response(request, area_name)
+ if redir:
+ return redir
+ current_actions = actions(response_dct['area_name'])
+ redir = action_do_redirect('edit-no-page', current_actions)
+ # a redir is always send... or there is a problem
+ return redirect(redir)
+
+
def get_edit_page(redirect_url, item_cls, item_form,
multimediafile_formset=MultimediaFileFormSet,
picturefile_formset=PictureFileFormSet):
@@ -218,19 +239,21 @@ def get_edit_page(redirect_url, item_cls, item_form,
listed_subcats = []
if subcategories:
for cat, subcats in subcategories:
- listed_subcats.append((unicode(cat),
- [(subcat.pk, subcat.name) for subcat in subcats]))
+ listed_subcats.append(
+ (unicode(cat),
+ [(subcat.pk, subcat.name) for subcat in subcats]))
# if an item_id is provided: modification
init_item, ref_item = None, None
if item_id:
try:
init_item = item_cls.objects.get(pk=item_id)
except:
- return redirect(redirect_url, area_name + '/' if area_name \
+ return redirect(redirect_url, area_name + '/' if area_name
else ''), None, None
ref_item = init_item
- modified_item = item_cls.objects.filter(ref_item=init_item,
- submiter_session_key=request.session.session_key)
+ modified_item = item_cls.objects.filter(
+ ref_item=init_item,
+ submiter_session_key=request.session.session_key)
if modified_item.count():
init_item = modified_item.all()[0]
response_dct['is_modification'] = True
@@ -238,8 +261,8 @@ def get_edit_page(redirect_url, item_cls, item_form,
init_multi = init_item.get_init_multi() if init_item else None
init_picture = init_item.get_init_picture() if init_item else None
if init_item and not request.user.is_superuser and \
- not init_item.submiter_session_key == \
- request.session.session_key:
+ not init_item.submiter_session_key == \
+ request.session.session_key:
# hide personal information
for k in ('submiter_name', 'submiter_email', 'submiter_comment'):
setattr(init_item, k, '')
@@ -248,16 +271,20 @@ def get_edit_page(redirect_url, item_cls, item_form,
if request.method == 'POST':
inst = None
# allow to directly modify only if owner or superuser
- if init_item and (request.user.is_superuser or \
- init_item.submiter_session_key == \
- request.session.session_key):
+ if init_item and (
+ request.user.is_superuser or
+ init_item.submiter_session_key ==
+ request.session.session_key):
inst = init_item
form = item_form(request.POST, request.FILES, instance=inst,
- subcategories=listed_subcats)
- formset_multi = multimediafile_formset(request.POST, request.FILES,
- initial=init_multi, prefix='multimedia')
- formset_picture = picturefile_formset(request.POST, request.FILES,
- initial=init_picture, prefix='picture')
+ subcategories=listed_subcats,
+ area_name=area_name)
+ formset_multi = multimediafile_formset(
+ request.POST, request.FILES, initial=init_multi,
+ prefix='multimedia')
+ formset_picture = picturefile_formset(
+ request.POST, request.FILES, initial=init_picture,
+ prefix='picture')
# All validation rules pass
if form.is_valid() and formset_multi.is_valid() and \
formset_picture.is_valid():
@@ -272,7 +299,7 @@ def get_edit_page(redirect_url, item_cls, item_form,
item.status = 'M'
if hasattr(ref_item, 'has_associated_marker'):
item.has_associated_marker = \
- ref_item.has_associated_marker
+ ref_item.has_associated_marker
elif not item.ref_item:
# initialisation
item.ref_item = item
@@ -284,6 +311,7 @@ def get_edit_page(redirect_url, item_cls, item_form,
marker = item
if not isinstance(marker, Marker) \
+ and hasattr(item, 'associated_marker') \
and item.associated_marker.count():
marker = item.associated_marker.all()[0]
if marker:
@@ -296,25 +324,47 @@ def get_edit_page(redirect_url, item_cls, item_form,
base_uri = get_base_uri(request)
notifySubmission(base_uri, item)
response_dct = get_base_response(request, area_name)
- return redirect(redirect_url + '-item',
- area_name + '/' if area_name else '',
- item.ref_item.pk, 'submited'), None, subcategories
+ return redirect(
+ redirect_url + '-item',
+ area_name + '/' if area_name else '',
+ item.ref_item.pk, 'submited'), None, subcategories
else:
- response_dct['error_message'] = _(u"There are missing field(s)"
- u" and/or errors in the submited form.")
+ response_dct['error_message'] = _(
+ u"There are missing field(s)"
+ u" and/or errors in the submited form.")
else:
- form = item_form(instance=init_item, subcategories=listed_subcats)
+ form = item_form(instance=init_item, subcategories=listed_subcats,
+ area_name=area_name)
formset_multi = multimediafile_formset(initial=init_multi,
- prefix='multimedia')
+ prefix='multimedia')
formset_picture = picturefile_formset(initial=init_picture,
- prefix='picture')
+ prefix='picture')
return None, (item_id, init_item, response_dct, form, formset_multi,
formset_picture), subcategories
return func
-get_edit_marker = get_edit_page('chimere:edit', Marker, MarkerForm)
-def edit(request, area_name="", item_id=None, submited=False):
+def action_do_redirect(action_name, available_actions):
+ # redirect to an edit
+ is_edit = 'edit' in action_name
+ redir = None
+ for action, subactions in available_actions:
+ if action.id == action_name:
+ return
+ if not redir and action.id != action_name:
+ redir = action.url
+ for subaction in subactions:
+ if subaction.id == action_name:
+ return
+ if is_edit and 'edit' not in redir \
+ and 'edit' in subaction.id:
+ redir = subaction.url
+ return redir
+
+get_edit_marker = get_edit_page('chimere:editmarker', Marker, MarkerForm)
+
+
+def editMarker(request, area_name="", item_id=None, submited=False):
"""
Edition page
"""
@@ -323,32 +373,40 @@ def edit(request, area_name="", item_id=None, submited=False):
if response:
return response
item_id, init_item, response_dct, form, formset_multi, formset_picture = \
- values
+ values
+
+ # verify action is available
+ current_actions = actions(response_dct['area_name'])
+ redir = action_do_redirect('edit-marker', current_actions)
+ if redir:
+ return redirect(redir)
+
# get the "manualy" declared_fields. Ie: properties
- declared_fields = form.declared_fields.keys()
- declared_fields = PropertyModel.objects.filter(available=True).all()
- filtered_properties = PropertyModel.objects.filter(available=True,
- subcategories__id__isnull=False).all()
+ querys = PropertyModel.getAvailable(area_name=area_name)
+ declared_fields, filtered_properties = [], []
+ for query in querys:
+ declared_fields += query.all()
+ filtered_properties += query.filter(
+ subcategories__id__isnull=False).all()
point_value = init_item.point if init_item else None
if request.POST and request.POST.get('point'):
point_value = request.POST.get('point')
response_dct.update({
- 'actions':actions(response_dct['area_name']),
- 'action_selected':('contribute', 'edit'),
- 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER,
- 'form':form,
- 'formset_multi':formset_multi,
- 'formset_picture':formset_picture,
- 'dated':settings.CHIMERE_DAYS_BEFORE_EVENT,
- 'extra_head':form.media,
- 'marker_id':item_id,
- 'sub_categories':sub_categories,
- 'point_widget':PointChooserWidget().render('point',
- point_value,
- area_name=response_dct['area_name']),
- 'properties':declared_fields,
- 'filtered_properties':filtered_properties,
- 'submited':submited
+ 'actions': current_actions,
+ 'action_selected': ('contribute', 'edit-marker'),
+ 'map_layer': settings.CHIMERE_DEFAULT_MAP_LAYER,
+ 'form': form,
+ 'formset_multi': formset_multi,
+ 'formset_picture': formset_picture,
+ 'dated': settings.CHIMERE_DAYS_BEFORE_EVENT,
+ 'extra_head': form.media,
+ 'marker_id': item_id,
+ 'sub_categories': sub_categories,
+ 'point_widget': PointChooserWidget().render(
+ 'point', point_value, area_name=response_dct['area_name']),
+ 'properties': declared_fields,
+ 'filtered_properties': filtered_properties,
+ 'submited': submited
})
# manualy populate the custom widget
if 'subcategory' in form.data and form.data['subcategory']:
@@ -356,6 +414,7 @@ def edit(request, area_name="", item_id=None, submited=False):
return render_to_response('chimere/edit.html', response_dct,
context_instance=RequestContext(request))
+
def uploadFile(request, category_id='', area_name=''):
response_dct, redir = get_base_response(request, area_name)
if redir:
@@ -381,17 +440,20 @@ def uploadFile(request, category_id='', area_name=''):
routefile.save()
if not category_id:
response_dct['gpx_id'] = routefile.pk
- return render_to_response('chimere/upload_file.html',
- response_dct, context_instance=RequestContext(request))
+ return render_to_response(
+ 'chimere/upload_file.html', response_dct,
+ context_instance=RequestContext(request))
routefile.process()
if not routefile.route:
- response_dct['errors'] = _(u"Bad file. Please check it with an "
- u"external software.")
- response_dct.update({'form':form})
- return render_to_response('chimere/upload_file.html',
- response_dct, context_instance=RequestContext(request))
- route = Route(name=form.cleaned_data['name'], route=routefile.route,
- associated_file=routefile, status='S')
+ response_dct['errors'] = _(
+ u"Bad file. Please check it with an external software.")
+ response_dct.update({'form': form})
+ return render_to_response(
+ 'chimere/upload_file.html', response_dct,
+ context_instance=RequestContext(request))
+ route = Route(name=form.cleaned_data['name'],
+ route=routefile.route, associated_file=routefile,
+ status='S')
route.save()
route.categories.add(category)
route.save()
@@ -400,10 +462,11 @@ def uploadFile(request, category_id='', area_name=''):
else:
# An unbound form
form = Form()
- response_dct.update({'form':form})
+ response_dct.update({'form': form})
return render_to_response('chimere/upload_file.html', response_dct,
context_instance=RequestContext(request))
+
def processRouteFile(request, area_name='', file_id=None):
if file_id:
try:
@@ -412,8 +475,8 @@ def processRouteFile(request, area_name='', file_id=None):
route = route_file.route
if not route:
return HttpResponse(status=500)
- return HttpResponse('(' + json.dumps({'wkt':route,
- 'file_id':file_id})+')',
+ return HttpResponse('(' + json.dumps({'wkt': route,
+ 'file_id': file_id}) + ')',
'application/javascript', status=200)
except OSError as e:
return HttpResponse(e.strerror, status=500)
@@ -422,16 +485,23 @@ def processRouteFile(request, area_name='', file_id=None):
get_edit_route = get_edit_page('chimere:editroute', Route, RouteForm)
+
def editRoute(request, area_name="", item_id=None, submited=False):
"""
Route edition page
"""
response, values, sub_categories = get_edit_route(request, area_name,
- item_id, ['R', 'B'])
+ item_id, ['R', 'B'])
if response:
return response
item_id, init_item, response_dct, form, formset_multi, formset_picture = \
- values
+ values
+
+ # verify action is available
+ current_actions = actions(response_dct['area_name'])
+ redir = action_do_redirect('edit-route', current_actions)
+ if redir:
+ return redirect(redir)
# get the "manualy" declared_fields. Ie: properties
declared_fields = form.declared_fields.keys()
@@ -441,20 +511,21 @@ def editRoute(request, area_name="", item_id=None, submited=False):
if request.POST and request.POST.get('route'):
route_value = request.POST.get('route')
response_dct.update({
- 'actions':actions(response_dct['area_name']),
- 'action_selected':('contribute', 'edit-route'),
- 'error_message':'',
- 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER,
- 'form':form,
- 'formset_multi':formset_multi,
- 'formset_picture':formset_picture,
- 'dated':settings.CHIMERE_DAYS_BEFORE_EVENT,
- 'extra_head':form.media,
- 'sub_categories':sub_categories,
- 'route_widget':RouteChooserWidget().render('route', route_value,
- area_name=response_dct['area_name'], routefile_id='',),
- 'properties':declared_fields,
- 'submited':submited
+ 'actions': current_actions,
+ 'action_selected': ('contribute', 'edit-route'),
+ 'error_message': '',
+ 'map_layer': settings.CHIMERE_DEFAULT_MAP_LAYER,
+ 'form': form,
+ 'formset_multi': formset_multi,
+ 'formset_picture': formset_picture,
+ 'dated': settings.CHIMERE_DAYS_BEFORE_EVENT,
+ 'extra_head': form.media,
+ 'sub_categories': sub_categories,
+ 'route_widget': RouteChooserWidget().render(
+ 'route', route_value, area_name=response_dct['area_name'],
+ routefile_id='',),
+ 'properties': declared_fields,
+ 'submited': submited
})
# manualy populate the custom widget
if 'subcategory' in form.data and form.data['subcategory']:
@@ -462,6 +533,60 @@ def editRoute(request, area_name="", item_id=None, submited=False):
return render_to_response('chimere/edit_route.html', response_dct,
context_instance=RequestContext(request))
+get_edit_polygon = get_edit_page('chimere:editpolygon', Polygon, PolygonForm)
+
+
+def editPolygon(request, area_name="", item_id=None, submited=False):
+ """
+ Polygon edition page
+ """
+ response, values, sub_categories = get_edit_polygon(request, area_name,
+ item_id, ['P'])
+ if response:
+ return response
+ item_id, init_item, response_dct, form, formset_multi, formset_picture = \
+ values
+
+ # verify action is available
+ current_actions = actions(response_dct['area_name'])
+ redir = action_do_redirect('edit-polygon', current_actions)
+ if redir:
+ return redirect(redir)
+
+ # get the "manualy" declared_fields. Ie: properties
+ querys = PropertyModel.getAvailable(area_name=area_name)
+ declared_fields, filtered_properties = [], []
+ for query in querys:
+ declared_fields += query.all()
+ filtered_properties += query.filter(
+ subcategories__id__isnull=False).all()
+ polygon_value = init_item.polygon if init_item else None
+ if request.POST and request.POST.get('polygon'):
+ polygon_value = request.POST.get('polygon')
+ response_dct.update({
+ 'actions': current_actions,
+ 'action_selected': ('contribute', 'edit-polygon'),
+ 'error_message': '',
+ 'map_layer': settings.CHIMERE_DEFAULT_MAP_LAYER,
+ 'form': form,
+ 'formset_multi': formset_multi,
+ 'formset_picture': formset_picture,
+ 'dated': settings.CHIMERE_DAYS_BEFORE_EVENT,
+ 'extra_head': form.media,
+ 'sub_categories': sub_categories,
+ 'polygon_widget': PolygonChooserWidget().render(
+ 'polygon', polygon_value, area_name=response_dct['area_name'],),
+ 'properties': declared_fields,
+ 'filtered_properties': filtered_properties,
+ 'submited': submited
+ })
+ # manualy populate the custom widget
+ if 'subcategory' in form.data and form.data['subcategory']:
+ response_dct['current_category'] = int(form.data['subcategory'])
+ return render_to_response('chimere/edit_polygon.html', response_dct,
+ context_instance=RequestContext(request))
+
+
def submited(request, area_name="", action=""):
"""
Successful submission page
@@ -469,14 +594,15 @@ def submited(request, area_name="", action=""):
response_dct, redir = get_base_response(request, area_name)
if redir:
return redir
- dct = {'actions':actions(response_dct['area_name']),
- 'action_selected':action,}
+ dct = {'actions': actions(response_dct['area_name']),
+ 'action_selected': action}
if hasattr(settings, 'CONTACT_EMAIL') and settings.CONTACT_EMAIL:
response_dct['contact_email'] = settings.CONTACT_EMAIL
response_dct.update(dct)
return render_to_response('chimere/submited.html', response_dct,
context_instance=RequestContext(request))
+
def charte(request, area_name=""):
"""
Affichage de la charte
@@ -484,11 +610,12 @@ def charte(request, area_name=""):
response_dct, redir = get_base_response(request, area_name)
if redir:
return redir
- response_dct.update({'actions':actions(response_dct['area_name']),
- 'action_selected':('charte',)})
+ response_dct.update({'actions': actions(response_dct['area_name']),
+ 'action_selected': ('charte',)})
return render_to_response('chimere/charte.html', response_dct,
context_instance=RequestContext(request))
+
def contactus(request, area_name=""):
"""
Contact page
@@ -500,11 +627,12 @@ def contactus(request, area_name=""):
form = ContactForm(request.POST)
# All validation rules pass
if form.is_valid():
- response = notifyStaff(_(u"Comments/request on the map"),
- form.cleaned_data['content'], form.cleaned_data['email'])
+ response = notifyStaff(
+ _(u"Comments/request on the map"),
+ form.cleaned_data['content'], form.cleaned_data['email'])
if response:
- msg = _(u"Thank you for your contribution. It will be taken "\
- u"into account. If you have left your email you may "\
+ msg = _(u"Thank you for your contribution. It will be taken "
+ u"into account. If you have left your email you may "
u"be contacted soon for more details.")
else:
msg = _(u"Temporary error. Renew your message later.")
@@ -513,12 +641,13 @@ def contactus(request, area_name=""):
response_dct, redir = get_base_response(request, area_name)
if redir:
return redir
- response_dct.update({'actions':actions(response_dct['area_name']),
- 'action_selected':('contact',),
- 'contact_form':form, 'message':msg})
+ response_dct.update({'actions': actions(response_dct['area_name']),
+ 'action_selected': ('contact',),
+ 'contact_form': form, 'message': msg})
return render_to_response('chimere/contactus.html', response_dct,
context_instance=RequestContext(request))
+
def extraPage(request, area_name="", page_id=""):
"""
Extra dynamic pages
@@ -530,22 +659,37 @@ def extraPage(request, area_name="", page_id=""):
response_dct, redir = get_base_response(request, area_name)
if redir:
return redir
- response_dct.update({'actions':actions(response_dct['area_name']),
- 'action_selected':(page_id,),
- 'content':page.content,
- 'title':page.title})
+ response_dct.update({'actions': actions(response_dct['area_name']),
+ 'action_selected': (page_id,),
+ 'content': page.content,
+ 'title': page.title})
tpl = page.template_path if page.template_path \
- else 'chimere/default_extra_page.html'
+ else 'chimere/default_extra_page.html'
return render_to_response(tpl, response_dct,
context_instance=RequestContext(request))
-def getDetail(request, area_name, marker_id):
+
+def getDetailUndefined(request, area_name):
+ return HttpResponse('')
+
+
+def getDetail(request, area_name, key):
'''
- Get the detail for a marker
+ Get the detail of a geographic item
'''
+ cls = Marker
+ pk = key
+ if '-' in key:
+ geo_type, pk = key.split('-')
+ if geo_type == 'route':
+ cls = Route
+ elif geo_type == 'aggroute':
+ cls = AggregatedRoute
+ elif geo_type == 'polygon':
+ cls = Polygon
try:
- marker = Marker.objects.filter(id=int(marker_id),
- status__in=['A', 'S'])[0]
+ marker = cls.objects.filter(id=int(pk),
+ status__in=['A', 'S'])[0]
except (ValueError, IndexError):
return HttpResponse('no results')
response_dct, redir = get_base_response(request, area_name)
@@ -556,21 +700,23 @@ def getDetail(request, area_name, marker_id):
if 'simple' in request.GET and request.GET['simple']:
response_dct['simple'] = True
response_dct['share_networks'], net_dct = \
- getShareNetwork(request, response_dct['area_name'], marker)
+ getShareNetwork(request, response_dct['area_name'], marker)
response_dct['share_url'] = net_dct['url']
net_dct['to'] = settings.CONTACT_EMAIL
if net_dct['to']:
net_dct["body"] = _(settings.CHIMERE_MODIF_EMAIL)
response_dct['modif_by_email'] = 'mailto:%(to)s?subject='\
- '%(text)s&body=%(body)s%(url)s' % net_dct
+ '%(text)s&body=%(body)s%(url)s' % net_dct
# to be sure there is unique IDs during a browsing
response_dct['time_now'] = datetime.datetime.now().strftime('%H%M%S')
response_dct['dated'] = settings.CHIMERE_DAYS_BEFORE_EVENT \
- and marker.start_date
+ and marker.start_date
response_dct['routing_enabled'] = settings.CHIMERE_ENABLE_ROUTING
+ response_dct['properties'] = marker.getProperties(area_name=area_name)
return render_to_response('chimere/detail.html', response_dct,
context_instance=RequestContext(request))
+
def getDescriptionDetail(request, area_name, category_id):
'''
Get the description for a category
@@ -586,6 +732,7 @@ def getDescriptionDetail(request, area_name, category_id):
return render_to_response('chimere/category_detail.html', response_dct,
context_instance=RequestContext(request))
+
def checkDate(q):
"""
Filter a queryset to manage dates
@@ -595,60 +742,127 @@ def checkDate(q):
today = datetime.date.today()
after = today + datetime.timedelta(settings.CHIMERE_DAYS_BEFORE_EVENT)
- q = q & ( Q(start_date__isnull=True)
- | Q(start_date__gte=today, start_date__lte=after)
- | Q(start_date__lte=today, end_date__gte=today)
- )
+ q = q & (Q(start_date__isnull=True) | Q(start_date__gte=today,
+ start_date__lte=after) | Q(
+ start_date__lte=today, end_date__gte=today))
return q
+
def _getGeoObjects(area_name, category_ids, status='A', getjson=True,
- item_types=('Marker', 'Route')):
+ item_types=('Marker', 'Route', 'Polygon'),
+ bounding_box=None, zoom_level=None):
'''
- Get markers and routes
+ Get geo objects
'''
+ zoom_need_reload = None
items = []
- current_cat, colors, idx = None, None, 0
empty = [] if not getjson else {}
+ subcategories = list(
+ SubCategory.getAvailable(None, area_name, public=True,
+ instance=True).all())
+ aggregated_category_ids = []
+ try:
+ zoom_level = int(zoom_level)
+ except ValueError:
+ zoom_level = None
+ if zoom_level:
+ # pop from main category list
+ len_subcats = len(subcategories)
+ for idx, subcat in enumerate(reversed(subcategories)):
+ if not subcat.min_zoom:
+ continue
+ if zoom_level < subcat.min_zoom:
+ if not zoom_need_reload or zoom_need_reload > subcat.min_zoom:
+ zoom_need_reload = subcat.min_zoom
+ aggregated_category_ids.append(
+ subcategories.pop(len_subcats - 1 - idx).pk)
+
+ category_ids = [subcat.pk for subcat in subcategories]
# marker
if 'Marker' in item_types:
try:
q = checkDate(Q(status__in=status, categories__in=category_ids))
- query = Marker.objects.filter(q).distinct('pk').order_by('-pk')
+ query = Marker.objects.filter(q)
+ if bounding_box:
+ query = query.filter(point__contained=bounding_box)
+ query = query.distinct('pk').order_by('-pk')
except:
- return empty
+ return empty, zoom_need_reload
- category_ids = [int(cat_id) for cat_id in category_ids]
if getjson:
for geo_object in list(query):
items += json.loads(geo_object.getGeoJSON(category_ids))
else:
items += list(query)
+ # polygon
+ if 'Polygon' in item_types:
+ try:
+ q = checkDate(Q(status__in=status, categories__in=category_ids))
+ query = Polygon.objects.filter(q)
+ if bounding_box:
+ query = query.filter(polygon__contained=bounding_box)
+ query = query.distinct('pk').order_by('-pk')
+ except:
+ return empty, zoom_need_reload
+
+ if aggregated_category_ids:
+ query = AggregatedPolygon.objects.filter(
+ status__in=status,
+ subcategory__in=aggregated_category_ids).order_by(
+ 'subcategory', '-pk')
+ # no bounding box filter
+ if getjson:
+ for poly in query.all():
+ items.append(json.loads(poly.getGeoJSON()))
+ else:
+ items += list(query)
+ else:
+ if getjson:
+ current_cat, colors, idx = None, None, 0
+ items += Polygon.getGeoJSONs(
+ query, limit_to_categories=category_ids)
+ else:
+ items += list(query)
+
# routes
if 'Route' in item_types:
- query = AggregatedRoute.objects.filter(status__in=status,
- subcategory__in=category_ids).order_by('subcategory', '-pk')
+ # TODO: manage non aggregated and bounding box in non-aggregated
+ query = AggregatedRoute.objects.filter(
+ status__in=status, subcategory__in=category_ids).order_by(
+ 'subcategory', '-pk')
if getjson:
+ current_cat, colors, idx = None, None, 0
for route in query.all():
- c_cat = route.subcategory
- if not current_cat or current_cat != c_cat:
- idx = 0
- current_cat = c_cat
- colors = list(Color.objects.filter(
- color_theme=c_cat.color_theme))
- if colors:
- items.append(json.loads(
- route.getGeoJSON(color=colors[idx % len(colors)].code)))
- else:
- items.append(json.loads(route.getGeoJSON(color='000')))
- idx += 1
+ color = ""
+ # aggregated view has no color and no categories
+ if hasattr(route, 'color') and route.color:
+ color = route.color
+ elif hasattr(route, 'categories'):
+ c_cat = None
+ for cat in route.categories.all():
+ if cat.id in category_ids:
+ c_cat = cat
+ break
+ if c_cat and not current_cat or current_cat != c_cat:
+ idx = 0
+ current_cat = c_cat
+ colors = list(Color.objects.filter(
+ color_theme=c_cat.color_theme))
+ if colors:
+ color = colors[idx % len(colors)].code
+ idx += 1
+ else:
+ color = "#000"
+ items.append(json.loads(route.getGeoJSON(color=color)))
else:
items += list(query)
if not items:
- return empty
- return items
+ return empty, zoom_need_reload
+ return items, zoom_need_reload
+
def getGeoObjects(request, area_name, category_ids, status):
'''
@@ -659,12 +873,27 @@ def getGeoObjects(request, area_name, category_ids, status):
status = status.split('_')
category_ids = unicode(category_ids).split('_')
- jsons = _getGeoObjects(area_name, category_ids, status)
+ bounding_box = []
+ for attr in ['min_lon', 'min_lat', 'max_lon', 'max_lat']:
+ value = request.GET.get(attr, None)
+ if not value:
+ bounding_box = None
+ break
+ bounding_box.append(value)
+ if bounding_box:
+ bounding_box = GEOSPolygon.from_bbox(bounding_box)
+ zoom_level = request.GET.get('zoom_level', None)
+
+ jsons, zoom_need_reload = _getGeoObjects(
+ area_name, category_ids, status, bounding_box=bounding_box,
+ zoom_level=zoom_level)
if not jsons:
- return HttpResponse('no results')
- data = json.dumps({"type": "FeatureCollection", "features":jsons})
+ return HttpResponse("[]", content_type="application/json")
+ data = json.dumps({"type": "FeatureCollection", "features": jsons,
+ "zoom_need_reload": zoom_need_reload or ''})
return HttpResponse(data, content_type="application/json")
+
def getMarker(request, area_name, pk):
q = Marker.objects.filter(pk=pk, status='A')
if not q.count():
@@ -672,6 +901,7 @@ def getMarker(request, area_name, pk):
data = q.all()[0].getGeoJSON()
return HttpResponse(data, content_type="application/json")
+
def get_all_categories(request, area_name=None):
'''
Get all available categories in JSON
@@ -680,16 +910,17 @@ def get_all_categories(request, area_name=None):
area = context_data["area"]
subcategories = []
if area:
- subcategories = list(area.getCategories('A',
- area_name=context_data['area_name']))
+ subcategories = list(area.getCategories(
+ 'A', area_name=context_data['area_name']))
else:
categories = SubCategory.getAvailable()
for cat, subcats in categories:
subcategories += subcats
subcats = [subcat.getJSONDict() for subcat in subcategories]
- jsons = json.dumps({'categories':subcats})
+ jsons = json.dumps({'categories': subcats})
return HttpResponse(jsons)
+
def get_available_categories(request, area_name=None, area=None, status='A',
force=None):
'''
@@ -700,21 +931,23 @@ def get_available_categories(request, area_name=None, area=None, status='A',
if redir:
return redir
if area and area.dynamic_categories and \
- not "current_extent" in request.GET:
+ "current_extent" not in request.GET:
context_data['sub_categories'] = []
- return render_to_response('chimere/blocks/categories.html', context_data,
- context_instance=RequestContext(request))
+ return render_to_response(
+ 'chimere/blocks/categories.html', context_data,
+ context_instance=RequestContext(request))
if not area or not area.dynamic_categories:
# Categories are not updated dynamicaly when the user move the map
# so we return ALL the categories
subcategories = SubCategory.getAvailable(
- area_name=context_data['area_name'])
+ area_name=context_data['area_name'])
context_data['sub_categories'] = subcategories
- return render_to_response('chimere/blocks/categories.html', context_data,
- context_instance=RequestContext(request))
+ return render_to_response(
+ 'chimere/blocks/categories.html', context_data,
+ context_instance=RequestContext(request))
default_message = "<p class='warning'>%s</p>" % \
- _("No category available in this area.")
- if not "status" in request.GET: # there must be a status
+ _("No category available in this area.")
+ if "status" not in request.GET: # there must be a status
status = 'A'
try:
status = status.split('_')
@@ -725,18 +958,20 @@ def get_available_categories(request, area_name=None, area=None, status='A',
# bad extent format
return HttpResponse(default_message)
# if not force and area.isIn(SimpleArea(cookie.AREA):return
- categories = area.getCategories(status, area_name=context_data['area_name'])
+ categories = area.getCategories(
+ status, area_name=context_data['area_name'])
if not categories:
return HttpResponse(default_message)
get_cat = lambda subcat: subcat.category
get_cat_order = lambda subcat: (subcat.category.order, subcat.category.pk,
subcat.order)
categories = sorted(categories, key=get_cat_order)
- subcategories = [(cat, list(subcats)) \
- for cat, subcats in groupby(categories, get_cat)]
+ subcategories = [(cat, list(subcats))
+ for cat, subcats in groupby(categories, get_cat)]
context_data['sub_categories'] = subcategories
return render_to_response('chimere/blocks/categories.html', context_data,
- context_instance=RequestContext(request))
+ context_instance=RequestContext(request))
+
def getCategory(request, area_name='', category_id=0):
'''
@@ -745,14 +980,15 @@ def getCategory(request, area_name='', category_id=0):
try:
category = SubCategory.objects.get(pk=category_id)
except ObjectDoesNotExist:
- return HttpResponse('no results')
- return HttpResponse(category.getJSON())
+ return HttpResponse('[]', content_type="application/json")
+ return HttpResponse(category.getJSON(), content_type="application/json")
+
def getTinyfiedUrl(request, parameters, area_name=''):
'''
Get the tinyfied version of parameters
'''
- data = {"urn": "", "url":"", "text":""}
+ data = {"urn": "", "url": "", "text": ""}
try:
urn = TinyUrl.getUrnByParameters(parameters)
except:
@@ -760,8 +996,8 @@ def getTinyfiedUrl(request, parameters, area_name=''):
response_dct, redir = get_base_response(request, area_name)
if redir:
return redir
- url = reverse('chimere:tiny', args=[(response_dct['area_name'] \
- if response_dct['area_name'] else '') + '/', urn])
+ url = reverse('chimere:tiny', args=[(response_dct['area_name']
+ if response_dct['area_name'] else '') + '/', urn])
if not url.startswith('http'):
url = get_base_uri(request) + url
url = re.sub("([^:])\/\/", "\g<1>/", url)
@@ -778,6 +1014,7 @@ def getTinyfiedUrl(request, parameters, area_name=''):
data["text"] = urlquote(text)
return data
+
def redirectFromTinyURN(request, area_name='', tiny_urn=''):
"""
Redirect from a tiny Urn
@@ -788,6 +1025,7 @@ def redirectFromTinyURN(request, area_name='', tiny_urn=''):
return redir
return HttpResponseRedirect(response_dct['extra_url'] + parameters)
+
class CategoryDirectoryView(ListView):
template_name = "chimere/category_directory.html"
@@ -796,26 +1034,27 @@ class CategoryDirectoryView(ListView):
if self.area_name:
self.area_name = self.area_name.split('/')[0]
area = get_object_or_404(Area, urn=self.area_name, available=True)
- q = area.subcategories.filter(available=True,
- category__available=True
- ).order_by('category__order', 'category__id', 'order')
+ q = area.subcategories.filter(
+ available=True, category__available=True).order_by(
+ 'category__order', 'category__id', 'order')
if q.count():
return q
- return SubCategory.objects.filter(available=True,
- category__available=True
- ).order_by('category__order', 'category__id', 'order')
+ return SubCategory.objects.filter(
+ available=True, category__available=True).order_by(
+ 'category__order', 'category__id', 'order')
def get_context_data(self, *args, **kwargs):
context = super(CategoryDirectoryView, self).get_context_data(
- *args, **kwargs)
+ *args, **kwargs)
new_context, redirect = get_base_response(self.request, self.area_name)
context.update(new_context)
context.update({
- 'actions':actions(self.area_name),
- 'action_selected':('categories',),
+ 'actions': actions(self.area_name),
+ 'action_selected': ('categories',),
})
return context
+
class CategoryView(TemplateView):
template_name = "chimere/category_directory_detail.html"
@@ -842,24 +1081,26 @@ class CategoryView(TemplateView):
if not self.category:
raise Http404(_("Category does not exist"))
- items = _getGeoObjects(self.area_name, [unicode(self.category.pk)],
- getjson=False, item_types=('Marker',))
+ items, zoom_need_reload = _getGeoObjects(
+ self.area_name, [unicode(self.category.pk)], getjson=False,
+ item_types=('Marker',))
return items
def get_context_data(self, *args, **kwargs):
context = super(CategoryView, self).get_context_data(
- *args, **kwargs)
+ *args, **kwargs)
self.items = self.get_geo_items()
new_context, redirect = get_base_response(self.request, self.area_name)
context.update(new_context)
context.update({
- 'actions':actions(self.area_name),
- 'action_selected':('categories',),
- 'category':self.category,
- 'items':self.items
+ 'actions': actions(self.area_name),
+ 'action_selected': ('categories',),
+ 'category': self.category,
+ 'items': self.items
})
return context
+
def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
transport='foot', speed=''):
'''
@@ -870,7 +1111,8 @@ def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
lon2, lat2 = float(lon2), float(lat2)
steps = [float(lonlat) for lonlat in lonlat_steps.split('_') if lonlat]
# regroup by 2
- steps = [(steps[i*2], steps[i*2+1]) for i in range(len(steps)/2)]
+ steps = [(steps[i * 2], steps[i * 2 + 1])
+ for i in range(len(steps) / 2)]
except ValueError:
return HttpResponse('no results')
@@ -879,8 +1121,9 @@ def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
transport = settings.CHIMERE_ROUTING_TRANSPORT[0][0]
if speed:
speed = unicode(speed)
- available_speed = [unicode(sp)
- for sp, lbl in settings.CHIMERE_ROUTING_SPEEDS[transport]]
+ available_speed = [
+ unicode(sp)
+ for sp, lbl in settings.CHIMERE_ROUTING_SPEEDS[transport]]
if speed not in available_speed:
speed = None
if not speed:
@@ -903,12 +1146,12 @@ def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
message = ''
if cats.count():
st_string = '{"type":"Feature", "geometry":{ "type": "Point", '\
- '"coordinates": [ %f, %f ] }, "properties":{"icon_path":"%s",'\
- '"icon_width":%d, "icon_height":%d}}'
+ '"coordinates": [ %f, %f ] }, "properties":{"icon_path":"%s",'\
+ '"icon_width":%d, "icon_height":%d}}'
points = [(m.point, m.categories.all()[0].icon)
- for m in list(Marker.objects.filter(status='A',
- categories__in=cats, point__distance_lte=(route, D(m=15))
- ).all())]
+ for m in list(Marker.objects.filter(
+ status='A', categories__in=cats,
+ point__distance_lte=(route, D(m=15))).all())]
for pt, icon in points:
st = st_string % (pt.x, pt.y, icon.image.url, icon.image.width,
icon.image.height)
@@ -924,21 +1167,22 @@ def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
if pts:
pt = pts[0]
st = st_string % (pt.x, pt.y, icon.image.url, icon.image.width,
- icon.image.height)
+ icon.image.height)
jsons.append(st)
if points or intersect:
message = getattr(settings, 'CHIMERE_ROUTING_WARN_MESSAGE', '')
if message:
message = ', "message":%s' % jsonencoder.encode(
- "%s" % _(message))
+ "%s" % _(message))
else:
message = ''
data = '{"properties":{"transport":%s, "total":%s, "description":%s}, '\
'"type": "FeatureCollection", "features":[%s]%s}' % (
- jsonencoder.encode(transport), total, desc, ",".join(jsons),
- message)
+ jsonencoder.encode(transport), total, desc, ",".join(jsons),
+ message)
return HttpResponse(data)
+
def rss(request, area_name=''):
'''
Redirect to RSS subscription page
@@ -946,15 +1190,15 @@ def rss(request, area_name=''):
response_dct, redir = get_base_response(request, area_name)
if redir:
return redir
- response_dct.update({'actions':actions(response_dct['area_name']),
- 'action_selected':('rss',),
- 'category_rss_feed':'',})
+ response_dct.update({'actions': actions(response_dct['area_name']),
+ 'action_selected': ('rss',),
+ 'category_rss_feed': ''})
# If the form has been submited
if request.method == "POST":
# User has defined the kind of POI he is interested in : POI in a area
# (GET method is used for the link with RSS icon in the browser)
if 'rss_category' in request.POST:
- #User wants to follow all the new POI
+ # User wants to follow all the new POI
if request.POST['rss_category'] == 'global':
feeds_link = reverse('chimere:feeds-global')
return redirect(feeds_link)
@@ -962,59 +1206,60 @@ def rss(request, area_name=''):
elif request.POST['rss_category'] == 'poi':
response_dct['category_rss_feed'] = 'category'
response_dct['sub_categories'] = SubCategory.getAvailable()
- return render_to_response('chimere/feeds/rss.html',
- response_dct,
- context_instance=RequestContext(request))
+ return render_to_response(
+ 'chimere/feeds/rss.html', response_dct,
+ context_instance=RequestContext(request))
# User wants to follow all the new POI situated in a defined area
elif request.POST['rss_category'] == 'area':
# An unbound form
form = AreaForm()
area_widget = AreaWidget().render('area', None)
response_dct.update({
- 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER,
- 'extra_head':form.media,
- 'form':form,
- 'category_rss_feed':'area',
- 'area_id':Area.getAvailable(),
- 'area_widget':area_widget
+ 'map_layer': settings.CHIMERE_DEFAULT_MAP_LAYER,
+ 'extra_head': form.media,
+ 'form': form,
+ 'category_rss_feed': 'area',
+ 'area_id': Area.getAvailable(),
+ 'area_widget': area_widget
})
- return render_to_response('chimere/feeds/rss.html',
- response_dct,
- context_instance=RequestContext(request))
+ return render_to_response(
+ 'chimere/feeds/rss.html', response_dct,
+ context_instance=RequestContext(request))
# Error when submitting the form
else:
error = _("Incorrect choice in the list")
- response_dct.update({'error_message':error,
- 'category_rss_feed':'',
- 'sub_categories':SubCategory.getAvailable()})
- return render_to_response('chimere/feeds/rss.html',
- response_dct,
- context_instance=RequestContext(request))
+ response_dct.update({
+ 'error_message': error,
+ 'category_rss_feed': '',
+ 'sub_categories': SubCategory.getAvailable()})
+ return render_to_response(
+ 'chimere/feeds/rss.html', response_dct,
+ context_instance=RequestContext(request))
# User has specified the category or subcategory he wants to follow =>
# we redirect him towards the related rss feed
if 'subcategory' in request.POST and request.POST['subcategory'] != '':
cat_id = request.POST['subcategory']
- if cat_id.find("cat_") != -1 :
+ if cat_id.find("cat_") != -1:
cat_id = cat_id.split('_')[1]
feeds_link = reverse('chimere:feeds-cat',
- kwargs={'category_id':cat_id})
+ kwargs={'category_id': cat_id})
return redirect(feeds_link)
else:
feeds_link = reverse('chimere:feeds-subcat',
- kwargs={'category_id':cat_id})
+ kwargs={'category_id': cat_id})
return redirect(feeds_link)
# User has specified the ID of the area he wants to follow
if 'id_area' in request.POST and request.POST['id_area'] != '':
feeds_link = reverse('chimere:feeds-areaid',
- kwargs={'area_id':request.POST['id_area']})
+ kwargs={'area_id': request.POST['id_area']})
return redirect(feeds_link)
# User has specified the area he wants to follow => we redirect him
# towards the related rss feed (using upper left and lower right
- # coordinates)
+ # coordinates)
elif 'upper_left_lat' in request.POST and \
request.POST['upper_left_lat'] != '' and \
'upper_left_lon' in request.POST and \
@@ -1022,13 +1267,13 @@ def rss(request, area_name=''):
'lower_right_lon' in request.POST and \
request.POST['lower_right_lon'] != '' and \
'lower_right_lat' in request.POST and \
- request.POST['lower_right_lat'] != '' :
+ request.POST['lower_right_lat'] != '':
coords = request.POST['upper_left_lat'] + '_' + \
- request.POST['upper_left_lon'] + '_' + \
- request.POST['lower_right_lat'] + '_' + \
- request.POST['lower_right_lon']
+ request.POST['upper_left_lon'] + '_' + \
+ request.POST['lower_right_lat'] + '_' + \
+ request.POST['lower_right_lon']
feeds_link = reverse('chimere:feeds-area',
- kwargs={'area':coords})
+ kwargs={'area': coords})
return redirect(feeds_link)
# GET method is used for linking with the RSS icon in the browser when user
@@ -1039,18 +1284,20 @@ def rss(request, area_name=''):
return redirect(feeds_link)
if request.GET['rss_category'] == 'poi':
response_dct['category_rss_feed'] = 'category'
- response_dct['sub_categories'] = SubCategory.getAvailable(['M','B'])
+ response_dct['sub_categories'] = SubCategory.getAvailable(
+ ['M', 'B'])
return render_to_response('chimere/feeds/rss.html', response_dct,
context_instance=RequestContext(request))
if request.GET['rss_category'] == 'area':
# An unbound form
form = AreaForm()
- response_dct.update({'map_layer':settings.MAP_LAYER,
- 'extra_head':form.media,
- 'form':form,
- 'category_rss_feed':'area',
- 'area_id':Area.getAvailable(),
- 'area_widget':AreaWidget().render('area', None)})
+ response_dct.update({
+ 'map_layer': settings.MAP_LAYER,
+ 'extra_head': form.media,
+ 'form': form,
+ 'category_rss_feed': 'area',
+ 'area_id': Area.getAvailable(),
+ 'area_widget': AreaWidget().render('area', None)})
return render_to_response('chimere/feeds/rss.html', response_dct,
context_instance=RequestContext(request))
@@ -1059,7 +1306,27 @@ def rss(request, area_name=''):
return render_to_response('chimere/feeds/rss.html', response_dct,
context_instance=RequestContext(request))
-from django.core.paginator import Paginator, InvalidPage
+# from django.core.paginator import Paginator, InvalidPage
+
+
+def property_choice_list(request, area_name='', property_slug=''):
+ data = {}
+ try:
+ pm = PropertyModel.objects.get(slug=property_slug, available=True)
+ except PropertyModel.DoesNotExist:
+ return HttpResponse(json.dumps(data),
+ content_type="application/json")
+ if not request.GET or not request.GET.get('term') or \
+ pm.areas.count() and not pm.areas.filter(urn=area_name).count():
+ return HttpResponse(json.dumps(data),
+ content_type="application/json")
+ fltr = {'propertymodel': pm, 'available': True,
+ 'value__icontains': request.GET.get('term')}
+ q = PropertyModelChoice.objects.filter(**fltr).order_by('value')
+ data = [{"id": p.pk, "value": p.value} for p in q.all()]
+ return HttpResponse(json.dumps(data),
+ content_type="application/json")
+
SearchView = None
autocomplete = None
@@ -1067,25 +1334,28 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \
and settings.CHIMERE_SEARCH_ENGINE:
from haystack.views import SearchView as HaystackSearchView
from haystack.query import SearchQuerySet
+
class SearchView(HaystackSearchView):
def extra_context(self, *args, **kwargs):
context = super(SearchView, self).extra_context(*args, **kwargs)
- context["autocomplete"] = settings.HAYSTACK_AUTOCOMPLETE \
- if hasattr(settings, 'HAYSTACK_AUTOCOMPLETE') else False
+ context["autocomplete"] = \
+ settings.HAYSTACK_AUTOCOMPLETE \
+ if hasattr(settings, 'HAYSTACK_AUTOCOMPLETE') else False
return context
+
def autocomplete(request):
sqs = SearchQuerySet().autocomplete(
- content_auto=request.GET.get('q', ''))[:5]
+ content_auto=request.GET.get('q', ''))[:5]
suggestions = [result.object.name for result in sqs if result.object]
spelling = []
if not suggestions:
spelling = SearchQuerySet().spelling_suggestion(
- request.GET.get('q', '')) or []
+ request.GET.get('q', '')) or []
# convert to list spelling...
# make sure it returns a JSON object, not a bare list.
# otherwise, it could be vulnerable to an XSS attack.
the_data = json.dumps({
'results': suggestions,
- 'spelling':spelling,
+ 'spelling': spelling,
})
return HttpResponse(the_data, content_type='application/json')
diff --git a/chimere/widgets.py b/chimere/widgets.py
index f501e23..6d61965 100644
--- a/chimere/widgets.py
+++ b/chimere/widgets.py
@@ -20,34 +20,36 @@
"""
Extra widgets and fields
"""
-from django import conf
+
+from json import JSONEncoder
+
from django import forms
from django.conf import settings
from django.contrib.gis.db import models
from django.contrib.gis.geos import fromstr
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
-from django.forms.widgets import RadioInput, RadioFieldRenderer
-from django.utils.encoding import force_unicode
-from django.utils.html import conditional_escape
+from django.forms.widgets import RadioInput, RadioFieldRenderer, flatatt
+from django.utils.encoding import force_unicode, smart_unicode
+from django.utils.html import conditional_escape, escape
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
from django.template.loader import render_to_string
import re
+
def getMapJS(area_name=''):
'''Variable initialization for drawing the map
'''
# projection, center and bounds definitions
- js = u"var epsg_display_projection = new OpenLayers.Projection('EPSG:%d')"\
- u";\n" % settings.CHIMERE_EPSG_DISPLAY_PROJECTION
- js += u"OpenLayers.ImgPath = '%schimere/img/';\n" % settings.STATIC_URL
- js += u"var epsg_projection = new OpenLayers.Projection('EPSG:%d');\n" % \
- settings.CHIMERE_EPSG_PROJECTION
- js += u"var centerLonLat = new OpenLayers.LonLat(%f,"\
- u"%f).transform(epsg_display_projection, epsg_projection);\n" % \
- settings.CHIMERE_DEFAULT_CENTER
+ js = u"var epsg_display_projection = 'EPSG:%d';\n" \
+ % settings.CHIMERE_EPSG_DISPLAY_PROJECTION
+ js += u"var epsg_projection = 'EPSG:%d';\n" % \
+ settings.CHIMERE_EPSG_PROJECTION
+ js += u"var centerLonLat = ol.proj.transform("\
+ u"[%f, %f], epsg_display_projection, epsg_projection);\n" % \
+ settings.CHIMERE_DEFAULT_CENTER
js += u"var media_path = '%s';\n" % settings.MEDIA_URL
js += u"var static_path = '%s';\n" % settings.STATIC_URL
js += u"var map_layer = %s;\n" % settings.CHIMERE_DEFAULT_MAP_LAYER
@@ -59,7 +61,8 @@ def getMapJS(area_name=''):
u"%s// !--></script>\n" % js
return js
-def get_map_layers(area_name=''):
+
+def get_map_layers(area_name='', get_area_zoom=False):
from chimere.models import Area
area = None
if area_name:
@@ -74,8 +77,9 @@ def get_map_layers(area_name=''):
pass
map_layers, default = [], None
if area and area.layers.count():
- map_layers = [[layer.name, layer.layer_code, False]
- for layer in area.layers.order_by('arealayers__order').all()]
+ map_layers = [
+ [layer.name, layer.layer_code, False, layer.extra_js_code or '']
+ for layer in area.layers.order_by('arealayers__order').all()]
def_layer = area.layers.filter(arealayers__default=True)
if def_layer.count():
def_layer = def_layer.all()[0]
@@ -87,34 +91,46 @@ def get_map_layers(area_name=''):
map_layers[0][2] = True
elif settings.CHIMERE_DEFAULT_MAP_LAYER:
map_layers = [(_(u"Default layer"), settings.CHIMERE_DEFAULT_MAP_LAYER,
- True)]
+ True, '')]
else:
- map_layers = [(u"Mapnik", "new OpenLayers.Layer.OSM.Mapnik('Mapnik')",
- True)]
- return map_layers, default
+ map_layers = [(u"OSM", """new ol.layer.Tile({
+ style: 'Road',
+ source: new ol.source.OSM()
+})""", True, '')]
+ if not get_area_zoom:
+ return map_layers, default
+ if not area:
+ return map_layers, default, settings.CHIMERE_DEFAULT_ZOOM
+ zoom = "[%s]" % ",".join(area.getExtent())
+ return map_layers, default, zoom
+
class ChosenSelectWidget(forms.Select):
"""
Chosen select widget.
"""
class Media:
- js = ["%schosen/chosen/chosen.jquery.min.js" % settings.STATIC_URL,]
- css = {'all':
- ["%schosen/chosen/chosen.css" % settings.STATIC_URL,]
- }
+ js = ["%schosen/chosen/chosen.jquery.min.js" % settings.STATIC_URL]
+ css = {
+ 'all':
+ ["%schosen/chosen/chosen.css" % settings.STATIC_URL]
+ }
+
def render(self, *args, **kwargs):
if 'attrs' not in kwargs:
kwargs['attrs'] = {}
kwargs['attrs'].update({'class': 'chzn-select'})
rendered = super(ChosenSelectWidget, self).render(*args, **kwargs)
rendered += u"\n<script type='text/javascript'>\n"\
- u" $('#%s').chosen();\n"\
- u"</script>\n" % kwargs['attrs']['id']
+ u" $('#%s').chosen();\n"\
+ u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
"""
JQuery UI button select widget.
"""
+
+
class ButtonRadioInput(RadioInput):
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
@@ -127,13 +143,18 @@ class ButtonRadioInput(RadioInput):
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'%s <label%s>%s</label>' % (self.tag(), label_for,
choice_label))
+
+
class ButtonRadioFieldRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
yield ButtonRadioInput(self.name, self.value, self.attrs.copy(),
choice, i)
+
def render(self):
return mark_safe(u'\n'.join([force_unicode(w) for w in self]))
+
+
class ButtonSelectWidget(forms.RadioSelect):
def __init__(self, *args, **kwargs):
self.renderer = ButtonRadioFieldRenderer
@@ -143,22 +164,36 @@ class ButtonSelectWidget(forms.RadioSelect):
rendered = "<div id='%s'>\n" % kwargs['attrs']['id']
rendered += super(ButtonSelectWidget, self).render(*args, **kwargs)
rendered += u"\n<script type='text/javascript'>\n"\
- u" $('#%s').buttonset();\n"\
- u"</script>\n</div>\n" % kwargs['attrs']['id']
+ u" $('#%s').buttonset();\n"\
+ u"</script>\n</div>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+
class ImporterChoicesWidget(forms.Select):
'''
Importer select widget.
'''
class Media:
- js = ["%schimere/js/importer_interface.js" % settings.STATIC_URL,]
+ js = ["%schimere/js/importer_interface.js" % settings.STATIC_URL]
+
+TINYMCE_JS, FULL_TINY_JS, ADMIN_TINY_JS = [], [], []
+
+if settings.TINYMCE_URL:
+ TINYMCE_JS = ["%stiny_mce.js" % settings.TINYMCE_URL]
+ FULL_TINY_JS = TINYMCE_JS[:] + \
+ ["%schimere/js/textareas.js" % settings.STATIC_URL]
+ ADMIN_TINY_JS = TINYMCE_JS[:] + \
+ ["%schimere/js/textareas_admin.js" % settings.STATIC_URL]
+
class TextareaWidgetBase(forms.Textarea):
"""
Manage the edition of a text using TinyMCE
"""
def render(self, *args, **kwargs):
+ if not TINYMCE_JS:
+ rendered = super(TextareaWidgetBase, self).render(*args, **kwargs)
+ return mark_safe(rendered)
if 'attrs' not in kwargs:
kwargs['attrs'] = {}
if 'class' not in kwargs['attrs']:
@@ -169,14 +204,19 @@ class TextareaWidgetBase(forms.Textarea):
rendered = super(TextareaWidgetBase, self).render(*args, **kwargs)
return mark_safe(rendered)
+
class FullTextareaWidget(TextareaWidgetBase):
"""
Manage the edition of a text using TinyMCE
"""
class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL]
+ js = TINYMCE_JS
def render(self, *args, **kwargs):
+ if not TINYMCE_JS:
+ rendered = super(FullTextareaWidget, self).render(*args, **kwargs)
+ return mark_safe(rendered)
+
if 'attrs' not in kwargs:
kwargs['attrs'] = {}
if 'class' not in kwargs['attrs']:
@@ -196,18 +236,19 @@ tinyMCE.init({
"""
return mark_safe(rendered)
+
class TextareaWidget(TextareaWidgetBase):
"""
Manage the edition of a text using TinyMCE
"""
class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL,
- "%schimere/js/textareas.js" % settings.STATIC_URL,]
+ js = FULL_TINY_JS
+
class TextareaAdminWidget(TextareaWidgetBase):
class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL,
- "%schimere/js/textareas_admin.js" % settings.STATIC_URL,]
+ js = ADMIN_TINY_JS
+
class DatePickerWidget(forms.TextInput):
"""
@@ -218,18 +259,85 @@ class DatePickerWidget(forms.TextInput):
def render(self, *args, **kwargs):
rendered = super(DatePickerWidget, self).render(*args, **kwargs)
rendered += u"\n<script type='text/javascript'>\n"\
- u" $(function() {$('#%s').datepicker({ dateFormat: 'yy-mm-dd' });});\n"\
- u"</script>\n" % kwargs['attrs']['id']
+ u" $(function() {$('#%s').datepicker("\
+ u"{ dateFormat: 'yy-mm-dd' });});\n"\
+ u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+
+class JQueryAutoComplete(forms.TextInput):
+ TEMPLATE = "chimere/blocks/JQueryAutoComplete.html"
+
+ def __init__(self, slug, options={}, attrs={}):
+ """
+ Source can be a list containing the autocomplete values or a
+ string containing the url used for the request.
+ """
+ self.options = None
+ self.attrs = {}
+ self.slug = slug
+ if len(options) > 0:
+ self.options = JSONEncoder().encode(options)
+ self.attrs.update(attrs)
+
+ def get_source(self):
+ # Strange... to be fixed
+ source = reverse('chimere:property-choices',
+ kwargs={'property_slug': self.slug})
+ return "'{}'".format(source)
+
+ def render(self, name, value=None, attrs=None):
+ attrs_hidden = self.build_attrs(attrs, name=name)
+ attrs_select = self.build_attrs(attrs)
+ selected_value, rendered_value = "", ""
+
+ if value:
+ val = escape(smart_unicode(value))
+ attrs_hidden['value'] = val
+ attrs_select['value'] = val
+ selected_value = val
+ if val:
+ from chimere.models import PropertyModelChoice
+ try:
+ attrs_select['value'] = unicode(
+ PropertyModelChoice.objects.get(
+ pk=value, propertymodel__slug=self.slug))
+ rendered_value = attrs_select['value']
+ except:
+ attrs_select['value'] = ""
+ if 'id' not in self.attrs:
+ attrs_hidden['id'] = 'id_%s' % name
+ attrs_select['id'] = 'id_select_%s' % name
+ if 'class' not in attrs_select:
+ attrs_select['class'] = 'autocomplete'
+ dct = {
+ 'attrs_select': flatatt(attrs_select),
+ 'attrs_hidden': flatatt(attrs_hidden),
+ 'field_id': name,
+ 'min_field_id': name.replace('_', ''),
+ 'options': self.options,
+ 'source': self.get_source(),
+ 'selected_value': selected_value,
+ 'rendered_value': rendered_value
+ }
+
+ return mark_safe(
+ render_to_string(self.TEMPLATE, dct))
+
+
class NominatimWidget(forms.TextInput):
class Media:
js = ["%schimere/js/nominatim-widget.js" % settings.STATIC_URL]
+
def render(self, name, value, attrs=None, area_name=''):
+ dct = {'id': name, 'nominatim_url': settings.NOMINATIM_URL,
+ 'label': _(u"Street, City, Country")}
+
tpl = u"""
<input type='hidden' name='nominatim_%(id)s_lat' id='nominatim_%(id)s_lat'/>
<input type='hidden' name='nominatim_%(id)s_lon' id='nominatim_%(id)s_lon'/>
-<input type='text' class='nominatim-widget' name='nominatim_%(id)s' id='nominatim_%(id)s' value=""/>
+<input type='text' class='nominatim-widget' name='nominatim_%(id)s'
+ id='nominatim_%(id)s' value=""/>
<label class='nominatim-label' id='nominatim_%(id)s_label'>&nbsp;</label>
<script type='text/javascript'>
var default_nominatim_lbl = "%(label)s";
@@ -239,21 +347,21 @@ $("#nominatim_%(id)s").click(function(){
$("#nominatim_%(id)s").val('');
});
</script>
-""" % {'id':name, 'nominatim_url':settings.NOMINATIM_URL,
- 'label':_(u"Street, City, Country")}
+""" % dct
return mark_safe(tpl)
+
class PointChooserWidget(forms.TextInput):
"""
Manage the edition of point on a map
"""
class Media:
css = {
- "all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + list(settings.JQUERY_JS_URLS) + \
- ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL]
+ js = settings.MAP_JS_URLS + list(settings.JQUERY_JS_URLS) + \
+ ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL]
def render(self, name, value, attrs=None, area_name='', initialized=True):
'''
@@ -273,9 +381,12 @@ class PointChooserWidget(forms.TextInput):
value = None
else:
value = None
- map_layers, default_area = get_map_layers(area_name)
- map_layers = [js for n, js, default in map_layers]
- #TODO: manage area
+ map_layers, default_area, zoom = get_map_layers(area_name,
+ get_area_zoom=True)
+ extra_js = [extra_js for n, js, default, extra_js in map_layers
+ if extra_js]
+ map_layers = [js for n, js, default, xtra_js in map_layers if js]
+ # TODO: manage area
return mark_safe(
render_to_string('chimere/blocks/live_coordinates.html',
{'lat': _("Latitude"),
@@ -285,18 +396,23 @@ class PointChooserWidget(forms.TextInput):
'name': name,
'val': val,
'initialized': initialized,
+ 'extra_js': "\n".join(extra_js),
'isvalue': bool(value),
- 'default_area': "true" if default_area else "false",
- }) % \
+ 'default_area': "true" if default_area
+ else "false",
+ }) %
(settings.STATIC_URL,
settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
settings.CHIMERE_EPSG_PROJECTION,
- settings.CHIMERE_DEFAULT_CENTER,
+ "[{}, {}]".format(settings.CHIMERE_DEFAULT_CENTER[0],
+ settings.CHIMERE_DEFAULT_CENTER[1]),
settings.CHIMERE_DEFAULT_ZOOM,
settings.STATIC_URL,
- ", ".join(map_layers)
+ ", ".join(map_layers),
+ zoom
)
- )
+ )
+
class HiddenPointChooserWidget(PointChooserWidget):
"""
@@ -307,13 +423,14 @@ class HiddenPointChooserWidget(PointChooserWidget):
kwargs['initialized'] = False
return super(HiddenPointChooserWidget, self).render(*args, **kwargs)
+
class PointField(models.PointField):
'''
Set the widget for the form field
'''
def __init__(self, *args, **kwargs):
self.widget = kwargs.pop('widget') if 'widget' in kwargs \
- else PointChooserWidget
+ else PointChooserWidget
return super(PointField, self).__init__(*args, **kwargs)
def formfield(self, **keys):
@@ -323,21 +440,23 @@ class PointField(models.PointField):
def clean(self, value, instance=None):
if len(value) != 2 and self.required:
- raise ValidationError(_("Invalid point"))
+ raise forms.ValidationError(_("Invalid point"))
return value
+
class RouteChooserWidget(forms.TextInput):
"""
Manage the edition of route on a map
"""
class Media:
- css = {"all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ css = {
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + list(settings.JQUERY_JS_URLS) + \
- ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL,
- "%schimere/js/edit_route_map.js" % settings.STATIC_URL,
- "%schimere/js/base.js" % settings.STATIC_URL,]
+ js = settings.MAP_JS_URLS + list(settings.JQUERY_JS_URLS) + \
+ ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL,
+ "%schimere/js/edit_route_map.js" % settings.STATIC_URL,
+ "%schimere/js/base.js" % settings.STATIC_URL]
def render(self, name, value, attrs=None, area_name='', routefile_id=None):
'''
@@ -345,67 +464,80 @@ class RouteChooserWidget(forms.TextInput):
'''
tpl = getMapJS(area_name)
map_layers, default_area = get_map_layers(area_name)
- map_layers = [js for nm, js, default in map_layers]
- js = """
+ extra_js = [extra_js for n, js, default, extra_js in map_layers
+ if extra_js]
+ map_layers = [js for nm, js, default, ext_js in map_layers]
+ js = u"""
var resolutions;
var zoomOffset;
var extra_url = "%s";
- OpenLayers.ImgPath = '%schimere/img/';
- var EPSG_DISPLAY_PROJECTION = epsg_display_projection = new OpenLayers.Projection('EPSG:%s');
- var EPSG_PROJECTION = epsg_projection = new OpenLayers.Projection('EPSG:%s');
- var CENTER_LONLAT = centerLonLat = new OpenLayers.LonLat%s.transform(epsg_display_projection, epsg_projection);
+ epsg_display_projection = 'EPSG:%s';
+ var EPSG_DISPLAY_PROJECTION = epsg_display_projection;
+ epsg_projection = 'EPSG:%s';
+ var EPSG_PROJECTION = epsg_projection;
+ centerLonLat = ol.proj.transform([%f %f],
+ epsg_display_projection, epsg_projection);
+ var CENTER_LONLAT = centerLonLat;
var DEFAULT_ZOOM = %s;
var chimere_init_options = {};
+ %s
chimere_init_options["map_layers"] = [%s];
chimere_init_options['dynamic_categories'] = false;
chimere_init_options['edition'] = true;
chimere_init_options['edition_type_is_route'] = true;
chimere_init_options["checked_categories"] = [];
- """ % (reverse("chimere:index"), settings.STATIC_URL,
- settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- settings.CHIMERE_EPSG_PROJECTION, settings.CHIMERE_DEFAULT_CENTER,
- settings.CHIMERE_DEFAULT_ZOOM, ", ".join(map_layers))
+ """ % (reverse("chimere:index"),
+ settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ settings.CHIMERE_EPSG_PROJECTION,
+ settings.CHIMERE_DEFAULT_CENTER[0],
+ settings.CHIMERE_DEFAULT_CENTER[1],
+ settings.CHIMERE_DEFAULT_ZOOM,
+ u"\n".join(extra_js),
+ u", ".join(map_layers))
if default_area:
- js += "chimere_init_options['selected_map_layer'] = %d;\n" % \
+ js += u"chimere_init_options['selected_map_layer'] = %d;\n" % \
default_area
tpl = u"<script type='text/javascript'><!--\n"\
u"%s// !--></script>\n" % js
- #TODO: manage area
+ # TODO: manage area
help_create = ''
if not value:
help_create = u"<h3>%s</h3>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n" % (
+ _(u"Creation mode"),
+ _(u"To start drawing the route click on the toggle "
+ u"button: \"Draw\"."),
+ _(u"Then click on the map to begin the drawing."),
+ _(u"You can add points by clicking again."),
+ _(u"To finish the drawing double click. When the drawing "
+ u"is finished you can edit it."),
+ _(u"While creating to undo a drawing click again on the "
+ u"toggle button \"Stop drawing\"."))
+ help_modify = u"<h3>%s</h3>\n"\
u"<p>%s</p>\n"\
u"<p>%s</p>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n" % (_(u"Creation mode"),
- _(u"To start drawing the route click on the toggle button: "\
- u"\"Draw\"."),
- _(u"Then click on the map to begin the drawing."),
- _(u"You can add points by clicking again."),
- _(u"To finish the drawing double click. When the drawing is "\
- u"finished you can edit it."),
- _(u"While creating to undo a drawing click again on the toggle "\
- u"button \"Stop drawing\"."))
- help_modify = u"<h3>%s</h3>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n" % (_(u"Modification mode"),
- _(u"To move a point click on it and drag it to the desired position."),
- _(u"To delete a point move the mouse cursor over it and press the "\
- u"\"d\" or \"Del\" key."),
- _(u"To add a point click in the middle of a segment and drag the new "\
- u"point to the desired position"))
+ u"<p>%s</p>\n" % (
+ _(u"Modification mode"),
+ _(u"To move a point click on it and drag it to the desired "
+ u"position."),
+ _(u"To delete a point move the mouse cursor over it and press "
+ u"the \"d\" or \"Del\" key."),
+ _(u"To add a point click in the middle of a segment and drag "
+ u"the new point to the desired position"))
if not value:
# upload a file
tpl += u"<script type='text/javascript'><!--\n"\
u" var error_msg = \"%s\";"\
- u"// --></script>" % (
- _(u"Give a name and set category before uploading a file."))
+ u"// --></script>" % \
+ _(u"Give a name and set category before uploading a file.")
tpl += u'<div id="upload"><a href="#" class="upload-button" '\
- u'onclick="uploadFile(error_msg);return false;">%s</a></div>' % (
- _(u"Upload a route file (GPX or KML)"))
+ u'onclick="uploadFile(error_msg);return false;">%s</a></div>' \
+ % (_(u"Upload a route file (GPX or KML)"))
tpl += u"\n<p id='draw-or'>%s</p>\n" % _(u"or")
tpl += u"<div id='draw-label'><div id='draw-toggle-off' "\
u"onclick='toggleDraw();'>\n"\
@@ -416,25 +548,26 @@ class RouteChooserWidget(forms.TextInput):
if value:
style = " style='display:block'"
tpl += u"\n<div class='help-route' id='help-route-modify'%s>%s</div>"\
- u"\n<hr class='spacer'/>\n"\
- u"<input type='hidden' name='%s' id='id_%s' value=\"%s\"/>\n"\
- u"<input type='hidden' name='associated_file_id' "\
- u"id='id_associated_file_id' value=\"%s\"/>\n" % (
- style, help_modify, name, name, value, routefile_id)
+ u"\n<hr class='spacer'/>\n"\
+ u"<input type='hidden' name='%s' id='id_%s' value=\"%s\"/>\n"\
+ u"<input type='hidden' name='associated_file_id' "\
+ u"id='id_associated_file_id' value=\"%s\"/>\n" % (
+ style, help_modify, name, name, value, routefile_id)
if value:
tpl += u"\n<div id='map_edit'></div>"
else:
tpl += "\n<div class='help-route' id='help-route-create'>%s</div>"\
% help_create
- tpl += u"\n<div id='map_edit'>\n"\
- u" <div class='map_button'>\n"\
- u" <a href='#' id='button-move-map' class='toggle-button "\
- u"toggle-button-active' onclick='toggleDrawOff();return false;'>%s"\
- u"</a>\n"\
- u"<a href='#' id='button-draw-map' class='toggle-button "\
- u"toggle-button-inactive' onclick='toggleDrawOn();return false;'>"\
- u"%s</a></div>\n"\
- u" </div>" % (_(u"Move on the map"), _(u"Draw"))
+ tpl += \
+ u"\n<div id='layerSwitcher'></div>\n<div id='map_edit'>\n"\
+ u" <div class='map_button'>\n"\
+ u" <a href='#' id='button-move-map' class='toggle-button "\
+ u"toggle-button-active' "\
+ u"onclick='toggleDrawOff();return false;'>%s</a>\n"\
+ u"<a href='#' id='button-draw-map' class='toggle-button "\
+ u"toggle-button-inactive' "\
+ u"onclick='toggleDrawOn();return false;'>%s</a></div>\n"\
+ u" </div>" % (_(u"Move on the map"), _(u"Draw"))
tpl += u"<script type='text/javascript'><!--\n"
if not value:
tpl += u"jQuery('#map_edit').hide();"
@@ -453,6 +586,7 @@ class RouteChooserWidget(forms.TextInput):
tpl += u"\n// --></script>\n"
return mark_safe(tpl)
+
class RouteField(models.LineStringField):
'''
Set the widget for the form field
@@ -462,18 +596,19 @@ class RouteField(models.LineStringField):
keys.update(defaults)
return super(RouteField, self).formfield(**keys)
+
class AreaWidget(forms.TextInput):
"""
Manage the edition of an area on the map
"""
class Media:
css = {
- "all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + [
- "%schimere/js/edit_area.js" % settings.STATIC_URL,
- "%schimere/js/base.js" % settings.STATIC_URL,]
+ js = settings.MAP_JS_URLS + [
+ "%schimere/js/edit_area.js" % settings.STATIC_URL,
+ "%schimere/js/base.js" % settings.STATIC_URL]
def get_bounding_box_from_value(self, value):
'''
@@ -483,7 +618,7 @@ class AreaWidget(forms.TextInput):
lower_right_lat, lower_right_lon = 0, 0
if not value:
return upper_left_lat, upper_left_lon, lower_right_lat, \
- lower_right_lon
+ lower_right_lon
if len(value) == 2:
upper_left = value[0]
lower_right = value[1]
@@ -497,7 +632,7 @@ class AreaWidget(forms.TextInput):
pass
if hasattr(lower_right, 'x') and hasattr(lower_right, 'y'):
lower_right_lon, lower_right_lat = lower_right.x, \
- lower_right.y
+ lower_right.y
elif len(lower_right) == 2:
lower_right_lon, lower_right_lat = lower_right
try:
@@ -512,29 +647,29 @@ class AreaWidget(forms.TextInput):
Render a map
"""
upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon = \
- self.get_bounding_box_from_value(value)
+ self.get_bounding_box_from_value(value)
tpl = getMapJS()
tpl += u"</div>\n"\
- u"<input type='hidden' name='upper_left_lat' id='upper_left_lat' "\
- u"value='%f'/>\n"\
- u"<input type='hidden' name='upper_left_lon' id='upper_left_lon' "\
- u"value='%f'/>\n"\
- u"<input type='hidden' name='lower_right_lat' id='lower_right_lat' "\
- u"value='%f'/>\n"\
- u"<input type='hidden' name='lower_right_lon' id='lower_right_lon' "\
- u"value='%f'/>\n" % (
- upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon)
+ u"<input type='hidden' name='upper_left_lat' id='upper_left_lat' "\
+ u"value='%f'/>\n"\
+ u"<input type='hidden' name='upper_left_lon' id='upper_left_lon' "\
+ u"value='%f'/>\n"\
+ u"<input type='hidden' name='lower_right_lat' id='lower_right_lat'"\
+ u" value='%f'/>\n"\
+ u"<input type='hidden' name='lower_right_lon' id='lower_right_lon'"\
+ u" value='%f'/>\n" % (
+ upper_left_lat, upper_left_lon, lower_right_lat,
+ lower_right_lon)
help_msg = _(u"Hold CTRL, click and drag to select area on the map")
tpl += u"<p class='help-osm'>%s</p>\n" % help_msg
tpl += u"<script type='text/javascript'>\n"
tpl += u"function init_map_form (){\ninit('map_edit_area');\n"
if value:
- tpl += u"var extent = new OpenLayers.Bounds(%f, %f, %f, %f);\n"\
- u"extent.transform(epsg_display_projection, epsg_projection);\n"\
- u"updateForm(extent);\n"\
- u"area_map.zoomToExtent(extent, true);\n"\
- u"area_map.zoomOut();" % (upper_left_lon, upper_left_lat,
- lower_right_lon, lower_right_lat)
+ tpl += u"extent = ol.proj.transformExtent([%f, %f, %f, %f], "\
+ u"epsg_display_projection, epsg_projection);\n"\
+ u"initArea(extent);\n" % (
+ upper_left_lon, upper_left_lat, lower_right_lon,
+ lower_right_lat)
tpl += u"}\n"
if initialized:
tpl += u"$(document).ready(function($) {init_map_form()});\n"
@@ -558,8 +693,61 @@ class AreaWidget(forms.TextInput):
values.append(value)
return values
-RE_XAPI = re.compile('(node|way)\[(.*=.*)\]\[bbox='\
- '(-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*)\]')
+
+class PolygonChooserWidget(forms.TextInput):
+ """
+ Manage the edition of polygon on a map
+ """
+ class Media:
+ css = {
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
+ }
+ js = settings.MAP_JS_URLS + list(settings.JQUERY_JS_URLS) + \
+ ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL]
+
+ def render(self, name, value, attrs=None, area_name='', initialized=True):
+ val = ''
+ if value:
+ val = str(value)
+ map_layers, default_area, zoom = get_map_layers(area_name,
+ get_area_zoom=True)
+ extra_js = [extra_js for n, js, default, extra_js in map_layers
+ if extra_js]
+ map_layers = [js for n, js, default, ext_js in map_layers
+ if 'OpenLayers' not in js]
+ tpl = render_to_string(
+ 'chimere/blocks/polygon_edit.html',
+ {'name': name, 'val': val, 'initialized': initialized,
+ 'isvalue': bool(value),
+ 'default_area': "true" if default_area else "false",
+ 'value': value
+ }
+ )
+ return mark_safe(tpl.format(
+ static_url=settings.STATIC_URL,
+ display_projection=settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ projection=settings.CHIMERE_EPSG_PROJECTION,
+ center=list(settings.CHIMERE_DEFAULT_CENTER),
+ zoom=zoom,
+ map_layers=u", ".join(map_layers),
+ extra_js=u"\n".join(extra_js),
+ ))
+
+
+class PolygonField(models.PolygonField):
+ '''
+ Set the widget for the form field
+ '''
+ def formfield(self, **keys):
+ defaults = {'widget': PolygonChooserWidget}
+ keys.update(defaults)
+ return super(PolygonField, self).formfield(**keys)
+
+RE_XAPI = re.compile(
+ '(node|way)\[(.*=.*)\]\[bbox='
+ '(-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*)\]')
+
class ImportFiltrWidget(AreaWidget):
"""
@@ -567,59 +755,61 @@ class ImportFiltrWidget(AreaWidget):
"""
class Media:
css = {
- "all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + [
- "%schimere/js/edit_area.js" % settings.STATIC_URL,
- "%schimere/js/base.js" % settings.STATIC_URL,]
+ js = settings.MAP_JS_URLS + [
+ "%schimere/js/edit_area.js" % settings.STATIC_URL,
+ "%schimere/js/base.js" % settings.STATIC_URL]
def render(self, name, value, attrs=None):
"""
Render a map
"""
tpl = super(ImportFiltrWidget, self).render(name, value, attrs,
- initialized=False)
+ initialized=False)
tpl += u"</div><hr class='spacer'/>"
- vals = {'lbl':_(u"Type:"), 'name':name, 'node':_(u"Node"),
- 'way':_(u"Way")}
+ vals = {'lbl': _(u"Type:"), 'name': name, 'node': _(u"Node"),
+ 'way': _(u"Way")}
vals['way_selected'] = ' checked="checked"'\
- if self.xapi_type == 'way' else ''
+ if self.xapi_type == 'way' else ''
vals['node_selected'] = ' checked="checked"'\
- if self.xapi_type == 'node' else ''
+ if self.xapi_type == 'node' else ''
tpl += u"<div class='input-osm'><label>%(lbl)s</label>"\
- u"<input type='radio' name='id_%(name)s_type' id='id_%(name)s_node'"\
- u" value='node'%(node_selected)s/> <label for='id_%(name)s_node'>"\
- u"%(node)s</label> <input type='radio' name='id_%(name)s_type' "\
- u"id='id_%(name)s_way' value='way'%(way_selected)s/> <label "\
- u"for='id_%(name)s_way'>%(way)s</label></div>" % vals
- help_msg = _(u"Enter an OSM \"tag=value\" string such as "\
- u"\"amenity=pub\". A list of common tag is available "\
- u"<a href='https://wiki.openstreetmap.org/wiki/Map_Features' "\
- u" target='_blank'>here</a>.")
+ u"<input type='radio' name='id_%(name)s_type' "\
+ u"id='id_%(name)s_node' value='node'%(node_selected)s/> "\
+ u"<label for='id_%(name)s_node'>"\
+ u"%(node)s</label> <input type='radio' name='id_%(name)s_type' "\
+ u"id='id_%(name)s_way' value='way'%(way_selected)s/> <label "\
+ u"for='id_%(name)s_way'>%(way)s</label></div>" % vals
+ help_msg = _(
+ u"Enter an OSM \"tag=value\" string such as "
+ u"\"amenity=pub\". A list of common tag is available "
+ u"<a href='https://wiki.openstreetmap.org/wiki/Map_Features' "
+ u" target='_blank'>here</a>.")
tpl += u"<p class='help-osm'>%s</p>\n" % help_msg
tpl += u"<div class='input-osm'><label for='id_%s_tag'>%s</label>"\
u"<input type='text' id='id_%s_tag' value=\"%s\"/></div>" % (
- name, _(u"Tag:"), name, self.xapi_tag)
+ name, _(u"Tag:"), name, self.xapi_tag)
tpl += u"<script type='text/javascript'>\n"
tpl += u"var default_xapi='%s';" % settings.CHIMERE_XAPI_URL
tpl += u'var msg_missing_area = "%s";' % \
- _(u"You have to select an area.")
+ _(u"You have to select an area.")
tpl += u'var msg_missing_type = "%s";' % \
- _(u"You have to select a type.")
+ _(u"You have to select a type.")
tpl += u'var msg_missing_filtr = "%s";' % \
- _(u"You have to insert a filter tag.")
+ _(u"You have to insert a filter tag.")
tpl += u"</script>\n"
- help_msg = _(u"If you change the above form don't forget to refresh "\
+ help_msg = _(u"If you change the above form don't forget to refresh "
u"before submit!")
tpl += u"<p class='help-osm errornote'>%s</p>\n" % help_msg
- help_msg = _(u"You can put a Folder name of the KML file to filter on "\
+ help_msg = _(u"You can put a Folder name of the KML file to filter on "
u"it.")
tpl += u"<p class='help-kml'>%s</p>\n" % help_msg
if not value:
value = ''
- tpl += u"<div><input type='text' id='id_%s' name='id_%s' "\
- u"value=\"%s\"/> <input type='button' id='id_refresh_%s' "\
+ tpl += u"<div><textarea id='id_%s' name='id_%s' "\
+ u">%s</textarea> <input type='button' id='id_refresh_%s' "\
u"value='%s' class='input-osm'/>" % (name, name, value, name,
_(u"Refresh"))
return mark_safe(tpl)
@@ -628,7 +818,7 @@ class ImportFiltrWidget(AreaWidget):
"""
Return the appropriate values
"""
- return data.get('id_'+name, None)
+ return data.get('id_' + name, None)
def get_bounding_box_from_value(self, value):
'''
@@ -640,17 +830,18 @@ class ImportFiltrWidget(AreaWidget):
self.xapi_type, self.xapi_tag, self.bounding_box = None, '', None
if not value:
return upper_left_lat, upper_left_lon, lower_right_lat, \
- lower_right_lon
+ lower_right_lon
xapi_m = RE_XAPI.match(value)
if not xapi_m:
return upper_left_lat, upper_left_lon, lower_right_lat, \
- lower_right_lon
+ lower_right_lon
# as the regexp pass, we could be pretty confident
self.xapi_type, self.xapi_tag, self.bounding_box = xapi_m.groups()
upper_left_lon, lower_right_lat, lower_right_lon, upper_left_lat = \
- self.bounding_box.split(',')
+ self.bounding_box.split(',')
return float(upper_left_lat), float(upper_left_lon), \
- float(lower_right_lat), float(lower_right_lon)
+ float(lower_right_lat), float(lower_right_lon)
+
class AreaField(forms.MultiValueField):
'''
@@ -663,33 +854,36 @@ class AreaField(forms.MultiValueField):
return None
return data_list
+
class MultiSelectWidget(forms.SelectMultiple):
class Media:
css = {'all': list(settings.JQUERY_CSS_URLS) + [
settings.STATIC_URL + 'bsmSelect/css/jquery.bsmselect.css',
settings.STATIC_URL + 'bsmSelect/css/jquery.bsmselect.custom.css',
- ]
+ ]
}
js = list(settings.JQUERY_JS_URLS) + [
settings.STATIC_URL + 'bsmSelect/js/jquery.bsmselect.js',
- settings.STATIC_URL + 'bsmSelect/js/jquery.bsmselect.compatibility.js',
- ]
+ settings.STATIC_URL +
+ 'bsmSelect/js/jquery.bsmselect.compatibility.js',
+ ]
def render(self, name, value, attrs=None):
rendered = super(MultiSelectWidget, self).render(name, value, attrs)
rendered += u"<hr class='spacer'/><script type='text/javascript'>\n"\
- u"$.bsmSelect.conf['title'] = \"%(title)s\";\n"\
- u"$(\"#id_%(name)s\").bsmSelect({\n"\
- u" removeLabel: '<strong>X</strong>',\n"\
- u" containerClass: 'bsmContainer',\n"\
- u" listClass: 'bsmList-custom',\n"\
- u" listItemClass: 'bsmListItem-custom',\n"\
- u" listItemLabelClass: 'bsmListItemLabel-custom',\n"\
- u" removeClass: 'bsmListItemRemove-custom'\n"\
- u"});\n"\
- u"</script>\n" % {'name':name, 'title':_("Select...")}
+ u"$.bsmSelect.conf['title'] = \"%(title)s\";\n"\
+ u"$(\"#id_%(name)s\").bsmSelect({\n"\
+ u" removeLabel: '<strong>X</strong>',\n"\
+ u" containerClass: 'bsmContainer',\n"\
+ u" listClass: 'bsmList-custom',\n"\
+ u" listItemClass: 'bsmListItem-custom',\n"\
+ u" listItemLabelClass: 'bsmListItemLabel-custom',\n"\
+ u" removeClass: 'bsmListItemRemove-custom'\n"\
+ u"});\n"\
+ u"</script>\n" % {'name': name, 'title': _("Select...")}
return mark_safe(rendered)
+
class SelectMultipleField(models.ManyToManyField):
'''
Set the widget for the category field
@@ -704,3 +898,4 @@ from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^chimere\.widgets\.PointField"])
add_introspection_rules([], ["^chimere\.widgets\.SelectMultipleField"])
add_introspection_rules([], ["^chimere\.widgets\.RouteField"])
+add_introspection_rules([], ["^chimere\.widgets\.PolygonField"])
diff --git a/chimere_example_project/.gitignore b/chimere_example_project/.gitignore
new file mode 100644
index 0000000..9b310ff
--- /dev/null
+++ b/chimere_example_project/.gitignore
@@ -0,0 +1,10 @@
+*.pyc
+*.swp
+*.bak
+*.mo
+*.ignore
+static
+local_settings.py
+media/*
+static/*
+*.pyc
diff --git a/chimere_example_project/__init__.py b/chimere_example_project/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chimere_example_project/__init__.py
diff --git a/chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.css b/chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.css
new file mode 100644
index 0000000..a553c4f
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v3.0.0
+ *
+ * Copyright 2013 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world by @mdo and @fat.
+ *//*! normalize.css v2.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}button,input,select[multiple],textarea{background-image:none}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16.099999999999998px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-warning{color:#c09853}.text-danger{color:#b94a48}.text-success{color:#468847}.text-info{color:#3a87ad}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}h1 small,.h1 small{font-size:24px}h2 small,.h2 small{font-size:18px}h3 small,.h3 small,h4 small,.h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.428571429}code,pre{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-1{width:8.333333333333332%}.col-xs-2{width:16.666666666666664%}.col-xs-3{width:25%}.col-xs-4{width:33.33333333333333%}.col-xs-5{width:41.66666666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333333333336%}.col-xs-8{width:66.66666666666666%}.col-xs-9{width:75%}.col-xs-10{width:83.33333333333334%}.col-xs-11{width:91.66666666666666%}.col-xs-12{width:100%}@media(min-width:768px){.container{max-width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-1{width:8.333333333333332%}.col-sm-2{width:16.666666666666664%}.col-sm-3{width:25%}.col-sm-4{width:33.33333333333333%}.col-sm-5{width:41.66666666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333333333336%}.col-sm-8{width:66.66666666666666%}.col-sm-9{width:75%}.col-sm-10{width:83.33333333333334%}.col-sm-11{width:91.66666666666666%}.col-sm-12{width:100%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-11{left:91.66666666666666%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-11{margin-left:91.66666666666666%}}@media(min-width:992px){.container{max-width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-1{width:8.333333333333332%}.col-md-2{width:16.666666666666664%}.col-md-3{width:25%}.col-md-4{width:33.33333333333333%}.col-md-5{width:41.66666666666667%}.col-md-6{width:50%}.col-md-7{width:58.333333333333336%}.col-md-8{width:66.66666666666666%}.col-md-9{width:75%}.col-md-10{width:83.33333333333334%}.col-md-11{width:91.66666666666666%}.col-md-12{width:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333333333332%}.col-md-push-2{left:16.666666666666664%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333333333333%}.col-md-push-5{left:41.66666666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333333333336%}.col-md-push-8{left:66.66666666666666%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333333333334%}.col-md-push-11{left:91.66666666666666%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-11{right:91.66666666666666%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-11{margin-left:91.66666666666666%}}@media(min-width:1200px){.container{max-width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-1{width:8.333333333333332%}.col-lg-2{width:16.666666666666664%}.col-lg-3{width:25%}.col-lg-4{width:33.33333333333333%}.col-lg-5{width:41.66666666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333333333336%}.col-lg-8{width:66.66666666666666%}.col-lg-9{width:75%}.col-lg-10{width:83.33333333333334%}.col-lg-11{width:91.66666666666666%}.col-lg-12{width:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-11{left:91.66666666666666%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed thead>tr>th,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed tbody>tr>td,.table-condensed tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8;border-color:#d6e9c6}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td{background-color:#d0e9c6;border-color:#c9e2b3}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede;border-color:#eed3d7}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td{background-color:#ebcccc;border-color:#e6c1c7}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3;border-color:#fbeed5}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td{background-color:#faf2cc;border-color:#f8e5be}@media(max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{padding-top:7px;margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-print:before{content:"\e045"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-briefcase:before{content:"\1f4bc"}.glyphicon-calendar:before{content:"\1f4c5"}.glyphicon-pushpin:before{content:"\1f4cc"}.glyphicon-paperclip:before{content:"\1f4ce"}.glyphicon-camera:before{content:"\1f4f7"}.glyphicon-lock:before{content:"\1f512"}.glyphicon-bell:before{content:"\1f514"}.glyphicon-bookmark:before{content:"\1f516"}.glyphicon-fire:before{content:"\1f525"}.glyphicon-wrench:before{content:"\1f527"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent;content:""}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#428bca}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}}.nav-tabs.nav-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs.nav-justified>.active>a{border-bottom-color:#fff}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs-justified>.active>a{border-bottom-color:#fff}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;z-index:1000;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;border-width:0 0 1px}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;z-index:1030}.navbar-fixed-bottom{bottom:0;margin-bottom:0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e6e6e6}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%}a.thumbnail:hover,a.thumbnail:focus{border-color:#428bca}.thumbnail>img{margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table{margin-bottom:0}.panel>.panel-body+.table{border-top:1px solid #ddd}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#fbeed5}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#fbeed5}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#fbeed5}.panel-danger{border-color:#eed3d7}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#eed3d7}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#eed3d7}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}body.modal-open,.modal-open .navbar-fixed-top,.modal-open .navbar-fixed-bottom{margin-right:15px}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{right:auto;left:50%;width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;left:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.affix{position:fixed}@-ms-viewport{width:device-width}@media screen and (max-width:400px){@-ms-viewport{width:320px}}.hidden{display:none!important;visibility:hidden!important}.visible-xs{display:none!important}tr.visible-xs{display:none!important}th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm{display:none!important}tr.visible-sm{display:none!important}th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md{display:none!important}tr.visible-md{display:none!important}th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg{display:none!important}tr.visible-lg{display:none!important}th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs{display:none!important}tr.hidden-xs{display:none!important}th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm{display:none!important}tr.hidden-xs.hidden-sm{display:none!important}th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md{display:none!important}tr.hidden-xs.hidden-md{display:none!important}th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg{display:none!important}tr.hidden-xs.hidden-lg{display:none!important}th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs{display:none!important}tr.hidden-sm.hidden-xs{display:none!important}th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}tr.hidden-sm{display:none!important}th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md{display:none!important}tr.hidden-sm.hidden-md{display:none!important}th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg{display:none!important}tr.hidden-sm.hidden-lg{display:none!important}th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs{display:none!important}tr.hidden-md.hidden-xs{display:none!important}th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm{display:none!important}tr.hidden-md.hidden-sm{display:none!important}th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}tr.hidden-md{display:none!important}th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg{display:none!important}tr.hidden-md.hidden-lg{display:none!important}th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs{display:none!important}tr.hidden-lg.hidden-xs{display:none!important}th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm{display:none!important}tr.hidden-lg.hidden-sm{display:none!important}th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md{display:none!important}tr.hidden-lg.hidden-md{display:none!important}th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}tr.hidden-lg{display:none!important}th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print{display:none!important}tr.visible-print{display:none!important}th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print{display:none!important}tr.hidden-print{display:none!important}th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file
diff --git a/chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.js b/chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.js
new file mode 100644
index 0000000..1765631
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/bootstrap/bootstrap.min.js
@@ -0,0 +1,6 @@
+/**
+* bootstrap.js v3.0.0 by @fat and @mdo
+* Copyright 2013 Twitter Inc.
+* http://www.apache.org/licenses/LICENSE-2.0
+*/
+if(!jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(window.jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(window.jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(window.jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("dropdown");d||c.data("dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(window.jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(window.jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(window.jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery); \ No newline at end of file
diff --git a/chimere_example_project/chimere_example_static/chimere/css/extra-styles.css b/chimere_example_project/chimere_example_static/chimere/css/extra-styles.css
new file mode 100644
index 0000000..22915a3
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/css/extra-styles.css
@@ -0,0 +1,474 @@
+#content{
+ border:0 solid transparent;
+ margin-top:40px;
+}
+
+ul.share a span.fa, ul.share, .nav-pills > li > a > .fa,
+a, a:link, a:visited, legend, #footer .map-footer a, #footer .map-footer a:link,
+#footer .map-footer a:visited, .detail_footer a, caption,
+#categories li#display_submited, h4, .simple .cloud h2 {
+ color: #99CA3C;
+}
+
+.nav-pills > li#simple_button-lnk > a > .fa{
+ color:#777;
+}
+
+.pager li a,
+.detail_amendment a, .detail_amendment a:visited,
+.nav-pills > li.active > a > .fa{
+ color:#fff;
+}
+
+#frm_categories {
+ background-color: #fff;
+}
+
+.pager li a,
+.detail_amendment,
+.nav-pills > li.active > a, .nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ background-color: #99CA3C;
+}
+
+.pager li a:hover{
+ background-color: #327E04;
+}
+
+.pager li a:hover{
+ border-color: #327E04;
+}
+
+h2, h3 {
+ color: #449506;
+ background-color: transparent;
+}
+
+a:hover, a:focus {
+ color: #327E04;
+}
+
+.modal-backdrop.in {
+ opacity: 0.1;
+}
+
+#footer a, #footer a:link, #footer a:visited{
+ color:#327E04;
+}
+
+#news{
+ background-color:transparent;
+}
+
+@media (min-width: 1000px) {
+ .modal-lg {
+ width: 900px;
+ }
+}
+
+.control_image {
+ vertical-align: -1px;
+}
+
+input{
+ display:inline-block;
+}
+
+.nav-pills{
+ margin-top:5px;
+}
+
+.nav.navbar-nav >li > a{
+ padding-top:15px;
+ padding-bottom:15px;
+}
+
+.nav-pills > li.active > a, .nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ background-color: #327E04;
+}
+
+#permalink{
+ display:inherit;
+ margin:0;
+ margin-left:2px;
+ padding:inherit;
+ width:inherit;
+}
+
+label.labelSpan.olButton{
+ margin:0;
+ margin-left:5px;
+}
+
+.baseLayersDiv input{
+ margin-left:5px;
+}
+
+#content .olControlLayerSwitcher .layersDiv {
+ border-radius: 0;
+ border:1px solid;
+ border-color: #E6E6E6;
+}
+
+.container{
+ max-width:none;
+ padding-right: 0;
+}
+
+#utils-div{
+ border-color: #DDD;
+}
+
+#search-box {
+ position: relative;
+ z-index: 200;
+ left: auto;
+ top: auto;
+ border: 0px solid transparent;
+ display:none;
+}
+
+.ac-results{
+ position: absolute;
+ background-color: white;
+ border: 1px solid #CCC;
+ padding: 0.2em 0.4em;
+}
+
+#content .olControlLayerSwitcher .layersDiv, #panel, #detail-wrapper{
+ background-color: #F8F8F8;
+}
+
+#panel{
+ max-height:none;
+ left:0;
+ bottom:0;
+ border:0 transparent;
+ border-left:1px solid #E7E7E7;
+ padding:16px;
+ padding-top:60px;
+ width:400px;
+ background-image:url('../img/logo.jpg');
+ background-position:bottom center;
+ background-repeat:no-repeat;
+ z-index:12;
+}
+
+#detail {
+ position:static;
+ border:0 transparent;
+}
+
+#detail div {
+ margin:auto;
+}
+
+#detail-wrapper div {
+ margin: 4px 8px;
+}
+
+#detail-wrapper{
+ position:absolute;
+ z-index:5;
+ left:auto;
+ right:0;
+ bottom:0;
+ top:0;
+ width:400px;
+ padding-top:50px;
+ border:0 transparent;
+ border-right:1px solid #E7E7E7;
+ border-top:1px solid #E7E7E7;
+}
+
+#categories input{
+ display:None;
+}
+
+.category_name{
+ font-weight:bold;
+}
+
+.subcategory label{
+ padding: 0 0.5em;
+ border-radius:5px;
+ font-weight:normal;
+}
+
+.subcategory.selected label{
+ background-color:rgb(175, 231, 175);
+}
+
+#panel #categories,
+#categories > ul {
+ width:auto;
+}
+
+#categories{
+ display:none;
+}
+
+.cat_image{
+ display:inline-block;
+ width:30px;
+}
+
+@media (min-height: 500px) {
+ #category-directory{
+ width:50%;
+ }
+}
+
+#search-nav{
+ position:absolute;
+ bottom:0;
+ width:100%;
+ background-color:#F8F8F8;
+ border-top:1px solid #E6E6E6;
+ padding: 0 10px;
+ left: 0;
+}
+
+#main-map {
+ height: auto;
+ bottom: 0px;
+ top:50px;
+}
+
+#footer .map-footer {
+ bottom: 0;
+ right: 420px;
+ margin:0;
+ background-color:#fff;
+ opacity:0.8;
+}
+
+#layer_selection {
+ display:none;
+}
+
+.olControlPanPanel {
+ top: 60px;
+}
+
+.olControlZoomPanel {
+ top: 125px;
+}
+
+a#news_button{
+ padding:0 10px;
+ margin:0;
+}
+
+span#permalink, .navbar-nav .lbl, #areas-div label, #permalink, #simple_button,
+#categories-lnk, #search-lnk, .fa-chimere-action, #news-lnk a,
+.nav-pills > li#news-lnk > a > .fa{
+ font-variant: small-caps;
+ font-size: 1.1em;
+ margin-left: 0.3em;
+ color:#777;
+ padding-left:0;
+ font-weight:normal;
+}
+
+.nav > li > a, #simple_button{
+ padding:10px;
+}
+
+#areas-div{
+ line-height: 32px;
+}
+
+#areas-div, span#permalink, #simple_button{
+ display: inline;
+ padding: 0px;
+}
+
+#news-lnk, #permalink-lnk, #simple_button{
+ line-height: 42px;
+}
+
+#news-lnk, #permalink-lnk{
+ padding: 0px 0px 0px 10px;
+}
+
+#news-lnk .lbl{
+ padding: 0px 0px 0px 0.5em;
+}
+
+#permalink, #simple_button-lnk lbl{
+ padding: 0 0.8em;
+}
+
+#areas-div{
+ line-height:42px;
+}
+
+.nav-pills > li#simple_button-lnk > a > .fa{
+ color:#777;
+}
+
+.nav-pills > li > a > .fa{
+ color: #54C200;
+}
+
+.nav-pills > li.active > a > .fa{
+ color:#fff;
+}
+
+.navbar-default .navbar-brand{
+ color:#54C200;
+ font-size:1em;
+}
+
+.fa{
+ font-size:1.4em;
+}
+
+.fa-chimere-facebook:before{
+ content:"\f082";
+}
+
+.fa-chimere-twitter:before{
+ content:"\f081";
+}
+
+.fa-chimere-view:before{
+ content:"\f06e";
+}
+
+.fa-chimere-contribute:before{
+ content:"\f040";
+}
+
+.fa-chimere-categories:before{
+ content:"\f03a";
+}
+
+.fa-chimere-rss:before{
+ content:"\f09e";
+}
+
+.fa-chimere-email:before,
+.fa-chimere-contact:before{
+ content:"\f1fa";
+}
+
+.fa-chimere-maps:before{
+ content:"\f14e";
+}
+
+#maps-lnk label, #contact-lnk .lbl, #simple_button-lnk .lbl, #rss-lnk .lbl{
+ display:none;
+}
+
+@media (min-width: 1552px) {
+ #maps-lnk label,
+ #contact-lnk .lbl{
+ display:inline;
+ }
+}
+
+@media (min-width: 1200px) {
+ #simple_button-lnk .lbl{
+ display:inline;
+ }
+}
+
+@media (min-width: 1100px) {
+ #panel{
+ padding-top:16px;
+ }
+ #detail{
+ padding-top:50px;
+ }
+}
+
+@media (max-width: 767px) {
+ #news-lnk .lbl, #simple_button-lnk .lbl, #maps-lnk label, #contact-lnk .lbl{
+ display:inline-block;
+ }
+ .selection-sep{
+ width: 80%;
+ border-bottom: 1px solid #CCC;
+ margin: 0 0 0.5em 0;
+ display:block;
+ clear:both;
+ }
+ #news-lnk .lbl,
+ #permalink-lnk,
+ #simple_button{
+ line-height: 50px;
+ }
+ #panel{
+ padding-top:16px;
+ }
+ #detail{
+ padding-top:50px;
+ }
+ #categories-lnk{
+ clear:both;
+ }
+}
+
+.show-hide-panel{
+ position:absolute;
+ left: 400px;
+ top: 0;
+ bottom: 0;
+ background-color:#eee;
+ width:20px;
+ z-index:10;
+ color:#666;
+}
+
+.show-hide-panel:hover{
+ cursor:pointer;
+}
+
+.show-hide-panel span {
+ position:absolute;
+ left:2px;
+ top:200px;
+ color:#449506;
+}
+
+#show-panel{
+ left:0;
+ display:none;
+}
+
+@media (max-width: 767px) {
+ #show-panel{
+ display:block;
+ }
+ #panel, #hide-panel{
+ display:none;
+ }
+ #footer .map-footer {
+ right:20px;
+ }
+}
+
+@media (min-height: 400px) {
+ .show-hide-panel span {
+ top:300px;
+ }
+}
+
+#content .olControlSimplePanZoom{
+ top: 58px !important;
+ left: auto !important;
+ right:50px !important;
+}
+
+#content .olControlLayerSwitcher .maximizeDiv{
+ left: -60px !important;
+}
+
+#content #main-map .olControlLayerSwitcher {
+ left: auto !important;
+ right:50px !important;
+ top:10px !important;
+}
diff --git a/chimere_example_project/chimere_example_static/chimere/css/form-compat.css b/chimere_example_project/chimere_example_static/chimere/css/form-compat.css
new file mode 100644
index 0000000..f83672f
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/css/form-compat.css
@@ -0,0 +1,69 @@
+input:-moz-placeholder {
+ color: #999999;
+}
+
+input::-moz-placeholder {
+ color: #999999;
+}
+
+input:-ms-input-placeholder {
+ color: #999999;
+}
+
+input::-webkit-input-placeholder {
+ color: #999999;
+}
+
+textarea,
+input {
+ display: block;
+ font-size: 14px;
+ line-height: 1.428571429;
+ color: #555555;
+ vertical-align: middle;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+ transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
+}
+
+input{
+ padding: 6px 12px;
+}
+
+textarea:focus,
+input:focus {
+ border-color: #81cf57;
+ outline: 0;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+
+input[disabled],
+input[readonly],
+fieldset[disabled] input {
+ cursor: not-allowed;
+ background-color: #eeeeee;
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ display: inline;
+}
+
+.alert-error {
+ color: #b94a48;
+ background-color: #f2dede;
+ border-color: #eed3d7;
+}
+
+.alert-error hr {
+ border-top-color: #e6c1c7;
+}
+
+.alert-error .alert-link {
+ color: #953b39;
+}
diff --git a/chimere_example_project/chimere_example_static/chimere/img/layer-switcher-maximize.png b/chimere_example_project/chimere_example_static/chimere/img/layer-switcher-maximize.png
new file mode 100644
index 0000000..326f243
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/img/layer-switcher-maximize.png
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/chimere/img/logo.jpg b/chimere_example_project/chimere_example_static/chimere/img/logo.jpg
new file mode 100644
index 0000000..cc2ff36
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/img/logo.jpg
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/chimere/img/minus.png b/chimere_example_project/chimere_example_static/chimere/img/minus.png
new file mode 100755
index 0000000..e8ebf51
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/img/minus.png
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/chimere/img/plus.png b/chimere_example_project/chimere_example_static/chimere/img/plus.png
new file mode 100755
index 0000000..b26a6f9
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/img/plus.png
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/chimere/js/interface.js b/chimere_example_project/chimere_example_static/chimere/js/interface.js
new file mode 100644
index 0000000..c0c00bf
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/chimere/js/interface.js
@@ -0,0 +1,73 @@
+$(function(){
+
+ if (has_search){
+ $('a[href=#categories]').click(function(){
+ show_panel(display_categories);
+ });
+ $('a[href=#search-box]').click(function(){
+ show_panel(display_search);
+ });
+ $('a[href=#search-box]').click();
+ } else {
+ $("#categories").fadeIn();
+ }
+ highlight_selected_categories();
+ $('.subcategory label').click(highlight_selected_categories);
+ $('#categories-lnk, #search-lnk').click(function(){
+ if($('.navbar-toggle').css('display') !='none'){
+ $(".navbar-toggle").click();
+ }
+ });
+ $('#hide-panel').click(hide_panel);
+ $('#show-panel').click(show_panel);
+ $('#close-detail').click(function(){
+ $('#detail').fadeOut();
+ });
+});
+
+function display_categories(){
+ $('a[href=#categories]').parent().parent().children().removeClass('active');
+ $('a[href=#categories]').parent().addClass('active');
+ $("#search-box").fadeOut(400,
+ function(){ $("#categories").fadeIn(); });
+}
+
+function display_search(){
+ $('a[href=#search-box]').parent().parent().children().removeClass('active');
+ $('a[href=#search-box]').parent().addClass('active');
+ $("#categories").fadeOut(400,
+ function(){ $("#search-box").fadeIn(); $('#id_q').focus(); });
+}
+
+function show_panel(fct){
+ if(!fct) fct = function(){};
+ if($('#panel').css('display') == 'none'){
+ $('#show-panel').fadeOut(200, function(){
+ $('#hide-panel').fadeIn(500);
+ $("#panel").fadeIn(500);
+ $("#panel").fadeIn(500, fct);
+ });
+ } else {
+ fct();
+ }
+}
+
+function hide_panel(){
+ if($('#panel').css('display') != 'none'){
+ $('#hide-panel').fadeOut(500);
+ $("#panel").fadeOut(500, function(){
+ $('#show-panel').fadeIn();
+ });
+ }
+}
+
+function highlight_selected_categories(){
+ $('.subcategory input').each(function(){
+ var lbl = $(this).parent();
+ if($(this).is(':checked')){
+ lbl.addClass('selected');
+ }else{
+ lbl.removeClass('selected');
+ }
+ });
+}
diff --git a/chimere_example_project/chimere_example_static/font-awesome/LICENSE b/chimere_example_project/chimere_example_static/font-awesome/LICENSE
new file mode 100644
index 0000000..2e5e82e
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/LICENSE
@@ -0,0 +1 @@
+Font Awesome licensed under SIL OFL 1.1 · Code licensed under MIT License · Documentation licensed under CC BY 3.0
diff --git a/chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.css b/chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.css
new file mode 100644
index 0000000..2dcdc22
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.css
@@ -0,0 +1,1801 @@
+/*!
+ * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+/* FONT PATH
+ * -------------------------- */
+@font-face {
+ font-family: 'FontAwesome';
+ src: url('../fonts/fontawesome-webfont.eot?v=4.3.0');
+ src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+.fa {
+ display: inline-block;
+ font: normal normal normal 14px/1 FontAwesome;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ transform: translate(0, 0);
+}
+/* makes the font 33% larger relative to the icon container */
+.fa-lg {
+ font-size: 1.33333333em;
+ line-height: 0.75em;
+ vertical-align: -15%;
+}
+.fa-2x {
+ font-size: 2em;
+}
+.fa-3x {
+ font-size: 3em;
+}
+.fa-4x {
+ font-size: 4em;
+}
+.fa-5x {
+ font-size: 5em;
+}
+.fa-fw {
+ width: 1.28571429em;
+ text-align: center;
+}
+.fa-ul {
+ padding-left: 0;
+ margin-left: 2.14285714em;
+ list-style-type: none;
+}
+.fa-ul > li {
+ position: relative;
+}
+.fa-li {
+ position: absolute;
+ left: -2.14285714em;
+ width: 2.14285714em;
+ top: 0.14285714em;
+ text-align: center;
+}
+.fa-li.fa-lg {
+ left: -1.85714286em;
+}
+.fa-border {
+ padding: .2em .25em .15em;
+ border: solid 0.08em #eeeeee;
+ border-radius: .1em;
+}
+.pull-right {
+ float: right;
+}
+.pull-left {
+ float: left;
+}
+.fa.pull-left {
+ margin-right: .3em;
+}
+.fa.pull-right {
+ margin-left: .3em;
+}
+.fa-spin {
+ -webkit-animation: fa-spin 2s infinite linear;
+ animation: fa-spin 2s infinite linear;
+}
+.fa-pulse {
+ -webkit-animation: fa-spin 1s infinite steps(8);
+ animation: fa-spin 1s infinite steps(8);
+}
+@-webkit-keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg);
+ }
+}
+@keyframes fa-spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg);
+ }
+}
+.fa-rotate-90 {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
+ -webkit-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
+.fa-rotate-180 {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+ -webkit-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ transform: rotate(180deg);
+}
+.fa-rotate-270 {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+ -webkit-transform: rotate(270deg);
+ -ms-transform: rotate(270deg);
+ transform: rotate(270deg);
+}
+.fa-flip-horizontal {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
+ -webkit-transform: scale(-1, 1);
+ -ms-transform: scale(-1, 1);
+ transform: scale(-1, 1);
+}
+.fa-flip-vertical {
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
+ -webkit-transform: scale(1, -1);
+ -ms-transform: scale(1, -1);
+ transform: scale(1, -1);
+}
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical {
+ filter: none;
+}
+.fa-stack {
+ position: relative;
+ display: inline-block;
+ width: 2em;
+ height: 2em;
+ line-height: 2em;
+ vertical-align: middle;
+}
+.fa-stack-1x,
+.fa-stack-2x {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ text-align: center;
+}
+.fa-stack-1x {
+ line-height: inherit;
+}
+.fa-stack-2x {
+ font-size: 2em;
+}
+.fa-inverse {
+ color: #ffffff;
+}
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+ readers do not read off random characters that represent icons */
+.fa-glass:before {
+ content: "\f000";
+}
+.fa-music:before {
+ content: "\f001";
+}
+.fa-search:before {
+ content: "\f002";
+}
+.fa-envelope-o:before {
+ content: "\f003";
+}
+.fa-heart:before {
+ content: "\f004";
+}
+.fa-star:before {
+ content: "\f005";
+}
+.fa-star-o:before {
+ content: "\f006";
+}
+.fa-user:before {
+ content: "\f007";
+}
+.fa-film:before {
+ content: "\f008";
+}
+.fa-th-large:before {
+ content: "\f009";
+}
+.fa-th:before {
+ content: "\f00a";
+}
+.fa-th-list:before {
+ content: "\f00b";
+}
+.fa-check:before {
+ content: "\f00c";
+}
+.fa-remove:before,
+.fa-close:before,
+.fa-times:before {
+ content: "\f00d";
+}
+.fa-search-plus:before {
+ content: "\f00e";
+}
+.fa-search-minus:before {
+ content: "\f010";
+}
+.fa-power-off:before {
+ content: "\f011";
+}
+.fa-signal:before {
+ content: "\f012";
+}
+.fa-gear:before,
+.fa-cog:before {
+ content: "\f013";
+}
+.fa-trash-o:before {
+ content: "\f014";
+}
+.fa-home:before {
+ content: "\f015";
+}
+.fa-file-o:before {
+ content: "\f016";
+}
+.fa-clock-o:before {
+ content: "\f017";
+}
+.fa-road:before {
+ content: "\f018";
+}
+.fa-download:before {
+ content: "\f019";
+}
+.fa-arrow-circle-o-down:before {
+ content: "\f01a";
+}
+.fa-arrow-circle-o-up:before {
+ content: "\f01b";
+}
+.fa-inbox:before {
+ content: "\f01c";
+}
+.fa-play-circle-o:before {
+ content: "\f01d";
+}
+.fa-rotate-right:before,
+.fa-repeat:before {
+ content: "\f01e";
+}
+.fa-refresh:before {
+ content: "\f021";
+}
+.fa-list-alt:before {
+ content: "\f022";
+}
+.fa-lock:before {
+ content: "\f023";
+}
+.fa-flag:before {
+ content: "\f024";
+}
+.fa-headphones:before {
+ content: "\f025";
+}
+.fa-volume-off:before {
+ content: "\f026";
+}
+.fa-volume-down:before {
+ content: "\f027";
+}
+.fa-volume-up:before {
+ content: "\f028";
+}
+.fa-qrcode:before {
+ content: "\f029";
+}
+.fa-barcode:before {
+ content: "\f02a";
+}
+.fa-tag:before {
+ content: "\f02b";
+}
+.fa-tags:before {
+ content: "\f02c";
+}
+.fa-book:before {
+ content: "\f02d";
+}
+.fa-bookmark:before {
+ content: "\f02e";
+}
+.fa-print:before {
+ content: "\f02f";
+}
+.fa-camera:before {
+ content: "\f030";
+}
+.fa-font:before {
+ content: "\f031";
+}
+.fa-bold:before {
+ content: "\f032";
+}
+.fa-italic:before {
+ content: "\f033";
+}
+.fa-text-height:before {
+ content: "\f034";
+}
+.fa-text-width:before {
+ content: "\f035";
+}
+.fa-align-left:before {
+ content: "\f036";
+}
+.fa-align-center:before {
+ content: "\f037";
+}
+.fa-align-right:before {
+ content: "\f038";
+}
+.fa-align-justify:before {
+ content: "\f039";
+}
+.fa-list:before {
+ content: "\f03a";
+}
+.fa-dedent:before,
+.fa-outdent:before {
+ content: "\f03b";
+}
+.fa-indent:before {
+ content: "\f03c";
+}
+.fa-video-camera:before {
+ content: "\f03d";
+}
+.fa-photo:before,
+.fa-image:before,
+.fa-picture-o:before {
+ content: "\f03e";
+}
+.fa-pencil:before {
+ content: "\f040";
+}
+.fa-map-marker:before {
+ content: "\f041";
+}
+.fa-adjust:before {
+ content: "\f042";
+}
+.fa-tint:before {
+ content: "\f043";
+}
+.fa-edit:before,
+.fa-pencil-square-o:before {
+ content: "\f044";
+}
+.fa-share-square-o:before {
+ content: "\f045";
+}
+.fa-check-square-o:before {
+ content: "\f046";
+}
+.fa-arrows:before {
+ content: "\f047";
+}
+.fa-step-backward:before {
+ content: "\f048";
+}
+.fa-fast-backward:before {
+ content: "\f049";
+}
+.fa-backward:before {
+ content: "\f04a";
+}
+.fa-play:before {
+ content: "\f04b";
+}
+.fa-pause:before {
+ content: "\f04c";
+}
+.fa-stop:before {
+ content: "\f04d";
+}
+.fa-forward:before {
+ content: "\f04e";
+}
+.fa-fast-forward:before {
+ content: "\f050";
+}
+.fa-step-forward:before {
+ content: "\f051";
+}
+.fa-eject:before {
+ content: "\f052";
+}
+.fa-chevron-left:before {
+ content: "\f053";
+}
+.fa-chevron-right:before {
+ content: "\f054";
+}
+.fa-plus-circle:before {
+ content: "\f055";
+}
+.fa-minus-circle:before {
+ content: "\f056";
+}
+.fa-times-circle:before {
+ content: "\f057";
+}
+.fa-check-circle:before {
+ content: "\f058";
+}
+.fa-question-circle:before {
+ content: "\f059";
+}
+.fa-info-circle:before {
+ content: "\f05a";
+}
+.fa-crosshairs:before {
+ content: "\f05b";
+}
+.fa-times-circle-o:before {
+ content: "\f05c";
+}
+.fa-check-circle-o:before {
+ content: "\f05d";
+}
+.fa-ban:before {
+ content: "\f05e";
+}
+.fa-arrow-left:before {
+ content: "\f060";
+}
+.fa-arrow-right:before {
+ content: "\f061";
+}
+.fa-arrow-up:before {
+ content: "\f062";
+}
+.fa-arrow-down:before {
+ content: "\f063";
+}
+.fa-mail-forward:before,
+.fa-share:before {
+ content: "\f064";
+}
+.fa-expand:before {
+ content: "\f065";
+}
+.fa-compress:before {
+ content: "\f066";
+}
+.fa-plus:before {
+ content: "\f067";
+}
+.fa-minus:before {
+ content: "\f068";
+}
+.fa-asterisk:before {
+ content: "\f069";
+}
+.fa-exclamation-circle:before {
+ content: "\f06a";
+}
+.fa-gift:before {
+ content: "\f06b";
+}
+.fa-leaf:before {
+ content: "\f06c";
+}
+.fa-fire:before {
+ content: "\f06d";
+}
+.fa-eye:before {
+ content: "\f06e";
+}
+.fa-eye-slash:before {
+ content: "\f070";
+}
+.fa-warning:before,
+.fa-exclamation-triangle:before {
+ content: "\f071";
+}
+.fa-plane:before {
+ content: "\f072";
+}
+.fa-calendar:before {
+ content: "\f073";
+}
+.fa-random:before {
+ content: "\f074";
+}
+.fa-comment:before {
+ content: "\f075";
+}
+.fa-magnet:before {
+ content: "\f076";
+}
+.fa-chevron-up:before {
+ content: "\f077";
+}
+.fa-chevron-down:before {
+ content: "\f078";
+}
+.fa-retweet:before {
+ content: "\f079";
+}
+.fa-shopping-cart:before {
+ content: "\f07a";
+}
+.fa-folder:before {
+ content: "\f07b";
+}
+.fa-folder-open:before {
+ content: "\f07c";
+}
+.fa-arrows-v:before {
+ content: "\f07d";
+}
+.fa-arrows-h:before {
+ content: "\f07e";
+}
+.fa-bar-chart-o:before,
+.fa-bar-chart:before {
+ content: "\f080";
+}
+.fa-twitter-square:before {
+ content: "\f081";
+}
+.fa-facebook-square:before {
+ content: "\f082";
+}
+.fa-camera-retro:before {
+ content: "\f083";
+}
+.fa-key:before {
+ content: "\f084";
+}
+.fa-gears:before,
+.fa-cogs:before {
+ content: "\f085";
+}
+.fa-comments:before {
+ content: "\f086";
+}
+.fa-thumbs-o-up:before {
+ content: "\f087";
+}
+.fa-thumbs-o-down:before {
+ content: "\f088";
+}
+.fa-star-half:before {
+ content: "\f089";
+}
+.fa-heart-o:before {
+ content: "\f08a";
+}
+.fa-sign-out:before {
+ content: "\f08b";
+}
+.fa-linkedin-square:before {
+ content: "\f08c";
+}
+.fa-thumb-tack:before {
+ content: "\f08d";
+}
+.fa-external-link:before {
+ content: "\f08e";
+}
+.fa-sign-in:before {
+ content: "\f090";
+}
+.fa-trophy:before {
+ content: "\f091";
+}
+.fa-github-square:before {
+ content: "\f092";
+}
+.fa-upload:before {
+ content: "\f093";
+}
+.fa-lemon-o:before {
+ content: "\f094";
+}
+.fa-phone:before {
+ content: "\f095";
+}
+.fa-square-o:before {
+ content: "\f096";
+}
+.fa-bookmark-o:before {
+ content: "\f097";
+}
+.fa-phone-square:before {
+ content: "\f098";
+}
+.fa-twitter:before {
+ content: "\f099";
+}
+.fa-facebook-f:before,
+.fa-facebook:before {
+ content: "\f09a";
+}
+.fa-github:before {
+ content: "\f09b";
+}
+.fa-unlock:before {
+ content: "\f09c";
+}
+.fa-credit-card:before {
+ content: "\f09d";
+}
+.fa-rss:before {
+ content: "\f09e";
+}
+.fa-hdd-o:before {
+ content: "\f0a0";
+}
+.fa-bullhorn:before {
+ content: "\f0a1";
+}
+.fa-bell:before {
+ content: "\f0f3";
+}
+.fa-certificate:before {
+ content: "\f0a3";
+}
+.fa-hand-o-right:before {
+ content: "\f0a4";
+}
+.fa-hand-o-left:before {
+ content: "\f0a5";
+}
+.fa-hand-o-up:before {
+ content: "\f0a6";
+}
+.fa-hand-o-down:before {
+ content: "\f0a7";
+}
+.fa-arrow-circle-left:before {
+ content: "\f0a8";
+}
+.fa-arrow-circle-right:before {
+ content: "\f0a9";
+}
+.fa-arrow-circle-up:before {
+ content: "\f0aa";
+}
+.fa-arrow-circle-down:before {
+ content: "\f0ab";
+}
+.fa-globe:before {
+ content: "\f0ac";
+}
+.fa-wrench:before {
+ content: "\f0ad";
+}
+.fa-tasks:before {
+ content: "\f0ae";
+}
+.fa-filter:before {
+ content: "\f0b0";
+}
+.fa-briefcase:before {
+ content: "\f0b1";
+}
+.fa-arrows-alt:before {
+ content: "\f0b2";
+}
+.fa-group:before,
+.fa-users:before {
+ content: "\f0c0";
+}
+.fa-chain:before,
+.fa-link:before {
+ content: "\f0c1";
+}
+.fa-cloud:before {
+ content: "\f0c2";
+}
+.fa-flask:before {
+ content: "\f0c3";
+}
+.fa-cut:before,
+.fa-scissors:before {
+ content: "\f0c4";
+}
+.fa-copy:before,
+.fa-files-o:before {
+ content: "\f0c5";
+}
+.fa-paperclip:before {
+ content: "\f0c6";
+}
+.fa-save:before,
+.fa-floppy-o:before {
+ content: "\f0c7";
+}
+.fa-square:before {
+ content: "\f0c8";
+}
+.fa-navicon:before,
+.fa-reorder:before,
+.fa-bars:before {
+ content: "\f0c9";
+}
+.fa-list-ul:before {
+ content: "\f0ca";
+}
+.fa-list-ol:before {
+ content: "\f0cb";
+}
+.fa-strikethrough:before {
+ content: "\f0cc";
+}
+.fa-underline:before {
+ content: "\f0cd";
+}
+.fa-table:before {
+ content: "\f0ce";
+}
+.fa-magic:before {
+ content: "\f0d0";
+}
+.fa-truck:before {
+ content: "\f0d1";
+}
+.fa-pinterest:before {
+ content: "\f0d2";
+}
+.fa-pinterest-square:before {
+ content: "\f0d3";
+}
+.fa-google-plus-square:before {
+ content: "\f0d4";
+}
+.fa-google-plus:before {
+ content: "\f0d5";
+}
+.fa-money:before {
+ content: "\f0d6";
+}
+.fa-caret-down:before {
+ content: "\f0d7";
+}
+.fa-caret-up:before {
+ content: "\f0d8";
+}
+.fa-caret-left:before {
+ content: "\f0d9";
+}
+.fa-caret-right:before {
+ content: "\f0da";
+}
+.fa-columns:before {
+ content: "\f0db";
+}
+.fa-unsorted:before,
+.fa-sort:before {
+ content: "\f0dc";
+}
+.fa-sort-down:before,
+.fa-sort-desc:before {
+ content: "\f0dd";
+}
+.fa-sort-up:before,
+.fa-sort-asc:before {
+ content: "\f0de";
+}
+.fa-envelope:before {
+ content: "\f0e0";
+}
+.fa-linkedin:before {
+ content: "\f0e1";
+}
+.fa-rotate-left:before,
+.fa-undo:before {
+ content: "\f0e2";
+}
+.fa-legal:before,
+.fa-gavel:before {
+ content: "\f0e3";
+}
+.fa-dashboard:before,
+.fa-tachometer:before {
+ content: "\f0e4";
+}
+.fa-comment-o:before {
+ content: "\f0e5";
+}
+.fa-comments-o:before {
+ content: "\f0e6";
+}
+.fa-flash:before,
+.fa-bolt:before {
+ content: "\f0e7";
+}
+.fa-sitemap:before {
+ content: "\f0e8";
+}
+.fa-umbrella:before {
+ content: "\f0e9";
+}
+.fa-paste:before,
+.fa-clipboard:before {
+ content: "\f0ea";
+}
+.fa-lightbulb-o:before {
+ content: "\f0eb";
+}
+.fa-exchange:before {
+ content: "\f0ec";
+}
+.fa-cloud-download:before {
+ content: "\f0ed";
+}
+.fa-cloud-upload:before {
+ content: "\f0ee";
+}
+.fa-user-md:before {
+ content: "\f0f0";
+}
+.fa-stethoscope:before {
+ content: "\f0f1";
+}
+.fa-suitcase:before {
+ content: "\f0f2";
+}
+.fa-bell-o:before {
+ content: "\f0a2";
+}
+.fa-coffee:before {
+ content: "\f0f4";
+}
+.fa-cutlery:before {
+ content: "\f0f5";
+}
+.fa-file-text-o:before {
+ content: "\f0f6";
+}
+.fa-building-o:before {
+ content: "\f0f7";
+}
+.fa-hospital-o:before {
+ content: "\f0f8";
+}
+.fa-ambulance:before {
+ content: "\f0f9";
+}
+.fa-medkit:before {
+ content: "\f0fa";
+}
+.fa-fighter-jet:before {
+ content: "\f0fb";
+}
+.fa-beer:before {
+ content: "\f0fc";
+}
+.fa-h-square:before {
+ content: "\f0fd";
+}
+.fa-plus-square:before {
+ content: "\f0fe";
+}
+.fa-angle-double-left:before {
+ content: "\f100";
+}
+.fa-angle-double-right:before {
+ content: "\f101";
+}
+.fa-angle-double-up:before {
+ content: "\f102";
+}
+.fa-angle-double-down:before {
+ content: "\f103";
+}
+.fa-angle-left:before {
+ content: "\f104";
+}
+.fa-angle-right:before {
+ content: "\f105";
+}
+.fa-angle-up:before {
+ content: "\f106";
+}
+.fa-angle-down:before {
+ content: "\f107";
+}
+.fa-desktop:before {
+ content: "\f108";
+}
+.fa-laptop:before {
+ content: "\f109";
+}
+.fa-tablet:before {
+ content: "\f10a";
+}
+.fa-mobile-phone:before,
+.fa-mobile:before {
+ content: "\f10b";
+}
+.fa-circle-o:before {
+ content: "\f10c";
+}
+.fa-quote-left:before {
+ content: "\f10d";
+}
+.fa-quote-right:before {
+ content: "\f10e";
+}
+.fa-spinner:before {
+ content: "\f110";
+}
+.fa-circle:before {
+ content: "\f111";
+}
+.fa-mail-reply:before,
+.fa-reply:before {
+ content: "\f112";
+}
+.fa-github-alt:before {
+ content: "\f113";
+}
+.fa-folder-o:before {
+ content: "\f114";
+}
+.fa-folder-open-o:before {
+ content: "\f115";
+}
+.fa-smile-o:before {
+ content: "\f118";
+}
+.fa-frown-o:before {
+ content: "\f119";
+}
+.fa-meh-o:before {
+ content: "\f11a";
+}
+.fa-gamepad:before {
+ content: "\f11b";
+}
+.fa-keyboard-o:before {
+ content: "\f11c";
+}
+.fa-flag-o:before {
+ content: "\f11d";
+}
+.fa-flag-checkered:before {
+ content: "\f11e";
+}
+.fa-terminal:before {
+ content: "\f120";
+}
+.fa-code:before {
+ content: "\f121";
+}
+.fa-mail-reply-all:before,
+.fa-reply-all:before {
+ content: "\f122";
+}
+.fa-star-half-empty:before,
+.fa-star-half-full:before,
+.fa-star-half-o:before {
+ content: "\f123";
+}
+.fa-location-arrow:before {
+ content: "\f124";
+}
+.fa-crop:before {
+ content: "\f125";
+}
+.fa-code-fork:before {
+ content: "\f126";
+}
+.fa-unlink:before,
+.fa-chain-broken:before {
+ content: "\f127";
+}
+.fa-question:before {
+ content: "\f128";
+}
+.fa-info:before {
+ content: "\f129";
+}
+.fa-exclamation:before {
+ content: "\f12a";
+}
+.fa-superscript:before {
+ content: "\f12b";
+}
+.fa-subscript:before {
+ content: "\f12c";
+}
+.fa-eraser:before {
+ content: "\f12d";
+}
+.fa-puzzle-piece:before {
+ content: "\f12e";
+}
+.fa-microphone:before {
+ content: "\f130";
+}
+.fa-microphone-slash:before {
+ content: "\f131";
+}
+.fa-shield:before {
+ content: "\f132";
+}
+.fa-calendar-o:before {
+ content: "\f133";
+}
+.fa-fire-extinguisher:before {
+ content: "\f134";
+}
+.fa-rocket:before {
+ content: "\f135";
+}
+.fa-maxcdn:before {
+ content: "\f136";
+}
+.fa-chevron-circle-left:before {
+ content: "\f137";
+}
+.fa-chevron-circle-right:before {
+ content: "\f138";
+}
+.fa-chevron-circle-up:before {
+ content: "\f139";
+}
+.fa-chevron-circle-down:before {
+ content: "\f13a";
+}
+.fa-html5:before {
+ content: "\f13b";
+}
+.fa-css3:before {
+ content: "\f13c";
+}
+.fa-anchor:before {
+ content: "\f13d";
+}
+.fa-unlock-alt:before {
+ content: "\f13e";
+}
+.fa-bullseye:before {
+ content: "\f140";
+}
+.fa-ellipsis-h:before {
+ content: "\f141";
+}
+.fa-ellipsis-v:before {
+ content: "\f142";
+}
+.fa-rss-square:before {
+ content: "\f143";
+}
+.fa-play-circle:before {
+ content: "\f144";
+}
+.fa-ticket:before {
+ content: "\f145";
+}
+.fa-minus-square:before {
+ content: "\f146";
+}
+.fa-minus-square-o:before {
+ content: "\f147";
+}
+.fa-level-up:before {
+ content: "\f148";
+}
+.fa-level-down:before {
+ content: "\f149";
+}
+.fa-check-square:before {
+ content: "\f14a";
+}
+.fa-pencil-square:before {
+ content: "\f14b";
+}
+.fa-external-link-square:before {
+ content: "\f14c";
+}
+.fa-share-square:before {
+ content: "\f14d";
+}
+.fa-compass:before {
+ content: "\f14e";
+}
+.fa-toggle-down:before,
+.fa-caret-square-o-down:before {
+ content: "\f150";
+}
+.fa-toggle-up:before,
+.fa-caret-square-o-up:before {
+ content: "\f151";
+}
+.fa-toggle-right:before,
+.fa-caret-square-o-right:before {
+ content: "\f152";
+}
+.fa-euro:before,
+.fa-eur:before {
+ content: "\f153";
+}
+.fa-gbp:before {
+ content: "\f154";
+}
+.fa-dollar:before,
+.fa-usd:before {
+ content: "\f155";
+}
+.fa-rupee:before,
+.fa-inr:before {
+ content: "\f156";
+}
+.fa-cny:before,
+.fa-rmb:before,
+.fa-yen:before,
+.fa-jpy:before {
+ content: "\f157";
+}
+.fa-ruble:before,
+.fa-rouble:before,
+.fa-rub:before {
+ content: "\f158";
+}
+.fa-won:before,
+.fa-krw:before {
+ content: "\f159";
+}
+.fa-bitcoin:before,
+.fa-btc:before {
+ content: "\f15a";
+}
+.fa-file:before {
+ content: "\f15b";
+}
+.fa-file-text:before {
+ content: "\f15c";
+}
+.fa-sort-alpha-asc:before {
+ content: "\f15d";
+}
+.fa-sort-alpha-desc:before {
+ content: "\f15e";
+}
+.fa-sort-amount-asc:before {
+ content: "\f160";
+}
+.fa-sort-amount-desc:before {
+ content: "\f161";
+}
+.fa-sort-numeric-asc:before {
+ content: "\f162";
+}
+.fa-sort-numeric-desc:before {
+ content: "\f163";
+}
+.fa-thumbs-up:before {
+ content: "\f164";
+}
+.fa-thumbs-down:before {
+ content: "\f165";
+}
+.fa-youtube-square:before {
+ content: "\f166";
+}
+.fa-youtube:before {
+ content: "\f167";
+}
+.fa-xing:before {
+ content: "\f168";
+}
+.fa-xing-square:before {
+ content: "\f169";
+}
+.fa-youtube-play:before {
+ content: "\f16a";
+}
+.fa-dropbox:before {
+ content: "\f16b";
+}
+.fa-stack-overflow:before {
+ content: "\f16c";
+}
+.fa-instagram:before {
+ content: "\f16d";
+}
+.fa-flickr:before {
+ content: "\f16e";
+}
+.fa-adn:before {
+ content: "\f170";
+}
+.fa-bitbucket:before {
+ content: "\f171";
+}
+.fa-bitbucket-square:before {
+ content: "\f172";
+}
+.fa-tumblr:before {
+ content: "\f173";
+}
+.fa-tumblr-square:before {
+ content: "\f174";
+}
+.fa-long-arrow-down:before {
+ content: "\f175";
+}
+.fa-long-arrow-up:before {
+ content: "\f176";
+}
+.fa-long-arrow-left:before {
+ content: "\f177";
+}
+.fa-long-arrow-right:before {
+ content: "\f178";
+}
+.fa-apple:before {
+ content: "\f179";
+}
+.fa-windows:before {
+ content: "\f17a";
+}
+.fa-android:before {
+ content: "\f17b";
+}
+.fa-linux:before {
+ content: "\f17c";
+}
+.fa-dribbble:before {
+ content: "\f17d";
+}
+.fa-skype:before {
+ content: "\f17e";
+}
+.fa-foursquare:before {
+ content: "\f180";
+}
+.fa-trello:before {
+ content: "\f181";
+}
+.fa-female:before {
+ content: "\f182";
+}
+.fa-male:before {
+ content: "\f183";
+}
+.fa-gittip:before,
+.fa-gratipay:before {
+ content: "\f184";
+}
+.fa-sun-o:before {
+ content: "\f185";
+}
+.fa-moon-o:before {
+ content: "\f186";
+}
+.fa-archive:before {
+ content: "\f187";
+}
+.fa-bug:before {
+ content: "\f188";
+}
+.fa-vk:before {
+ content: "\f189";
+}
+.fa-weibo:before {
+ content: "\f18a";
+}
+.fa-renren:before {
+ content: "\f18b";
+}
+.fa-pagelines:before {
+ content: "\f18c";
+}
+.fa-stack-exchange:before {
+ content: "\f18d";
+}
+.fa-arrow-circle-o-right:before {
+ content: "\f18e";
+}
+.fa-arrow-circle-o-left:before {
+ content: "\f190";
+}
+.fa-toggle-left:before,
+.fa-caret-square-o-left:before {
+ content: "\f191";
+}
+.fa-dot-circle-o:before {
+ content: "\f192";
+}
+.fa-wheelchair:before {
+ content: "\f193";
+}
+.fa-vimeo-square:before {
+ content: "\f194";
+}
+.fa-turkish-lira:before,
+.fa-try:before {
+ content: "\f195";
+}
+.fa-plus-square-o:before {
+ content: "\f196";
+}
+.fa-space-shuttle:before {
+ content: "\f197";
+}
+.fa-slack:before {
+ content: "\f198";
+}
+.fa-envelope-square:before {
+ content: "\f199";
+}
+.fa-wordpress:before {
+ content: "\f19a";
+}
+.fa-openid:before {
+ content: "\f19b";
+}
+.fa-institution:before,
+.fa-bank:before,
+.fa-university:before {
+ content: "\f19c";
+}
+.fa-mortar-board:before,
+.fa-graduation-cap:before {
+ content: "\f19d";
+}
+.fa-yahoo:before {
+ content: "\f19e";
+}
+.fa-google:before {
+ content: "\f1a0";
+}
+.fa-reddit:before {
+ content: "\f1a1";
+}
+.fa-reddit-square:before {
+ content: "\f1a2";
+}
+.fa-stumbleupon-circle:before {
+ content: "\f1a3";
+}
+.fa-stumbleupon:before {
+ content: "\f1a4";
+}
+.fa-delicious:before {
+ content: "\f1a5";
+}
+.fa-digg:before {
+ content: "\f1a6";
+}
+.fa-pied-piper:before {
+ content: "\f1a7";
+}
+.fa-pied-piper-alt:before {
+ content: "\f1a8";
+}
+.fa-drupal:before {
+ content: "\f1a9";
+}
+.fa-joomla:before {
+ content: "\f1aa";
+}
+.fa-language:before {
+ content: "\f1ab";
+}
+.fa-fax:before {
+ content: "\f1ac";
+}
+.fa-building:before {
+ content: "\f1ad";
+}
+.fa-child:before {
+ content: "\f1ae";
+}
+.fa-paw:before {
+ content: "\f1b0";
+}
+.fa-spoon:before {
+ content: "\f1b1";
+}
+.fa-cube:before {
+ content: "\f1b2";
+}
+.fa-cubes:before {
+ content: "\f1b3";
+}
+.fa-behance:before {
+ content: "\f1b4";
+}
+.fa-behance-square:before {
+ content: "\f1b5";
+}
+.fa-steam:before {
+ content: "\f1b6";
+}
+.fa-steam-square:before {
+ content: "\f1b7";
+}
+.fa-recycle:before {
+ content: "\f1b8";
+}
+.fa-automobile:before,
+.fa-car:before {
+ content: "\f1b9";
+}
+.fa-cab:before,
+.fa-taxi:before {
+ content: "\f1ba";
+}
+.fa-tree:before {
+ content: "\f1bb";
+}
+.fa-spotify:before {
+ content: "\f1bc";
+}
+.fa-deviantart:before {
+ content: "\f1bd";
+}
+.fa-soundcloud:before {
+ content: "\f1be";
+}
+.fa-database:before {
+ content: "\f1c0";
+}
+.fa-file-pdf-o:before {
+ content: "\f1c1";
+}
+.fa-file-word-o:before {
+ content: "\f1c2";
+}
+.fa-file-excel-o:before {
+ content: "\f1c3";
+}
+.fa-file-powerpoint-o:before {
+ content: "\f1c4";
+}
+.fa-file-photo-o:before,
+.fa-file-picture-o:before,
+.fa-file-image-o:before {
+ content: "\f1c5";
+}
+.fa-file-zip-o:before,
+.fa-file-archive-o:before {
+ content: "\f1c6";
+}
+.fa-file-sound-o:before,
+.fa-file-audio-o:before {
+ content: "\f1c7";
+}
+.fa-file-movie-o:before,
+.fa-file-video-o:before {
+ content: "\f1c8";
+}
+.fa-file-code-o:before {
+ content: "\f1c9";
+}
+.fa-vine:before {
+ content: "\f1ca";
+}
+.fa-codepen:before {
+ content: "\f1cb";
+}
+.fa-jsfiddle:before {
+ content: "\f1cc";
+}
+.fa-life-bouy:before,
+.fa-life-buoy:before,
+.fa-life-saver:before,
+.fa-support:before,
+.fa-life-ring:before {
+ content: "\f1cd";
+}
+.fa-circle-o-notch:before {
+ content: "\f1ce";
+}
+.fa-ra:before,
+.fa-rebel:before {
+ content: "\f1d0";
+}
+.fa-ge:before,
+.fa-empire:before {
+ content: "\f1d1";
+}
+.fa-git-square:before {
+ content: "\f1d2";
+}
+.fa-git:before {
+ content: "\f1d3";
+}
+.fa-hacker-news:before {
+ content: "\f1d4";
+}
+.fa-tencent-weibo:before {
+ content: "\f1d5";
+}
+.fa-qq:before {
+ content: "\f1d6";
+}
+.fa-wechat:before,
+.fa-weixin:before {
+ content: "\f1d7";
+}
+.fa-send:before,
+.fa-paper-plane:before {
+ content: "\f1d8";
+}
+.fa-send-o:before,
+.fa-paper-plane-o:before {
+ content: "\f1d9";
+}
+.fa-history:before {
+ content: "\f1da";
+}
+.fa-genderless:before,
+.fa-circle-thin:before {
+ content: "\f1db";
+}
+.fa-header:before {
+ content: "\f1dc";
+}
+.fa-paragraph:before {
+ content: "\f1dd";
+}
+.fa-sliders:before {
+ content: "\f1de";
+}
+.fa-share-alt:before {
+ content: "\f1e0";
+}
+.fa-share-alt-square:before {
+ content: "\f1e1";
+}
+.fa-bomb:before {
+ content: "\f1e2";
+}
+.fa-soccer-ball-o:before,
+.fa-futbol-o:before {
+ content: "\f1e3";
+}
+.fa-tty:before {
+ content: "\f1e4";
+}
+.fa-binoculars:before {
+ content: "\f1e5";
+}
+.fa-plug:before {
+ content: "\f1e6";
+}
+.fa-slideshare:before {
+ content: "\f1e7";
+}
+.fa-twitch:before {
+ content: "\f1e8";
+}
+.fa-yelp:before {
+ content: "\f1e9";
+}
+.fa-newspaper-o:before {
+ content: "\f1ea";
+}
+.fa-wifi:before {
+ content: "\f1eb";
+}
+.fa-calculator:before {
+ content: "\f1ec";
+}
+.fa-paypal:before {
+ content: "\f1ed";
+}
+.fa-google-wallet:before {
+ content: "\f1ee";
+}
+.fa-cc-visa:before {
+ content: "\f1f0";
+}
+.fa-cc-mastercard:before {
+ content: "\f1f1";
+}
+.fa-cc-discover:before {
+ content: "\f1f2";
+}
+.fa-cc-amex:before {
+ content: "\f1f3";
+}
+.fa-cc-paypal:before {
+ content: "\f1f4";
+}
+.fa-cc-stripe:before {
+ content: "\f1f5";
+}
+.fa-bell-slash:before {
+ content: "\f1f6";
+}
+.fa-bell-slash-o:before {
+ content: "\f1f7";
+}
+.fa-trash:before {
+ content: "\f1f8";
+}
+.fa-copyright:before {
+ content: "\f1f9";
+}
+.fa-at:before {
+ content: "\f1fa";
+}
+.fa-eyedropper:before {
+ content: "\f1fb";
+}
+.fa-paint-brush:before {
+ content: "\f1fc";
+}
+.fa-birthday-cake:before {
+ content: "\f1fd";
+}
+.fa-area-chart:before {
+ content: "\f1fe";
+}
+.fa-pie-chart:before {
+ content: "\f200";
+}
+.fa-line-chart:before {
+ content: "\f201";
+}
+.fa-lastfm:before {
+ content: "\f202";
+}
+.fa-lastfm-square:before {
+ content: "\f203";
+}
+.fa-toggle-off:before {
+ content: "\f204";
+}
+.fa-toggle-on:before {
+ content: "\f205";
+}
+.fa-bicycle:before {
+ content: "\f206";
+}
+.fa-bus:before {
+ content: "\f207";
+}
+.fa-ioxhost:before {
+ content: "\f208";
+}
+.fa-angellist:before {
+ content: "\f209";
+}
+.fa-cc:before {
+ content: "\f20a";
+}
+.fa-shekel:before,
+.fa-sheqel:before,
+.fa-ils:before {
+ content: "\f20b";
+}
+.fa-meanpath:before {
+ content: "\f20c";
+}
+.fa-buysellads:before {
+ content: "\f20d";
+}
+.fa-connectdevelop:before {
+ content: "\f20e";
+}
+.fa-dashcube:before {
+ content: "\f210";
+}
+.fa-forumbee:before {
+ content: "\f211";
+}
+.fa-leanpub:before {
+ content: "\f212";
+}
+.fa-sellsy:before {
+ content: "\f213";
+}
+.fa-shirtsinbulk:before {
+ content: "\f214";
+}
+.fa-simplybuilt:before {
+ content: "\f215";
+}
+.fa-skyatlas:before {
+ content: "\f216";
+}
+.fa-cart-plus:before {
+ content: "\f217";
+}
+.fa-cart-arrow-down:before {
+ content: "\f218";
+}
+.fa-diamond:before {
+ content: "\f219";
+}
+.fa-ship:before {
+ content: "\f21a";
+}
+.fa-user-secret:before {
+ content: "\f21b";
+}
+.fa-motorcycle:before {
+ content: "\f21c";
+}
+.fa-street-view:before {
+ content: "\f21d";
+}
+.fa-heartbeat:before {
+ content: "\f21e";
+}
+.fa-venus:before {
+ content: "\f221";
+}
+.fa-mars:before {
+ content: "\f222";
+}
+.fa-mercury:before {
+ content: "\f223";
+}
+.fa-transgender:before {
+ content: "\f224";
+}
+.fa-transgender-alt:before {
+ content: "\f225";
+}
+.fa-venus-double:before {
+ content: "\f226";
+}
+.fa-mars-double:before {
+ content: "\f227";
+}
+.fa-venus-mars:before {
+ content: "\f228";
+}
+.fa-mars-stroke:before {
+ content: "\f229";
+}
+.fa-mars-stroke-v:before {
+ content: "\f22a";
+}
+.fa-mars-stroke-h:before {
+ content: "\f22b";
+}
+.fa-neuter:before {
+ content: "\f22c";
+}
+.fa-facebook-official:before {
+ content: "\f230";
+}
+.fa-pinterest-p:before {
+ content: "\f231";
+}
+.fa-whatsapp:before {
+ content: "\f232";
+}
+.fa-server:before {
+ content: "\f233";
+}
+.fa-user-plus:before {
+ content: "\f234";
+}
+.fa-user-times:before {
+ content: "\f235";
+}
+.fa-hotel:before,
+.fa-bed:before {
+ content: "\f236";
+}
+.fa-viacoin:before {
+ content: "\f237";
+}
+.fa-train:before {
+ content: "\f238";
+}
+.fa-subway:before {
+ content: "\f239";
+}
+.fa-medium:before {
+ content: "\f23a";
+}
diff --git a/chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.min.css b/chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.min.css
new file mode 100644
index 0000000..24fcc04
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} \ No newline at end of file
diff --git a/chimere_example_project/chimere_example_static/font-awesome/fonts/FontAwesome.otf b/chimere_example_project/chimere_example_static/font-awesome/fonts/FontAwesome.otf
new file mode 100644
index 0000000..f7936cc
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/fonts/FontAwesome.otf
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.eot b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..33b2bb8
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.eot
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.svg b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000..1ee89d4
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.svg
@@ -0,0 +1,565 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" " horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#xd8;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" horiz-adv-x="1537" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" horiz-adv-x="1537" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf082;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf0d4;" d="M829 318q0 -76 -58.5 -112.5t-139.5 -36.5q-41 0 -80.5 9.5t-75.5 28.5t-58 53t-22 78q0 46 25 80t65.5 51.5t82 25t84.5 7.5q20 0 31 -2q2 -1 23 -16.5t26 -19t23 -18t24.5 -22t19 -22.5t17 -26t9 -26.5t4.5 -31.5zM755 863q0 -60 -33 -99.5t-92 -39.5q-53 0 -93 42.5 t-57.5 96.5t-17.5 106q0 61 32 104t92 43q53 0 93.5 -45t58 -101t17.5 -107zM861 1120l88 64h-265q-85 0 -161 -32t-127.5 -98t-51.5 -153q0 -93 64.5 -154.5t158.5 -61.5q22 0 43 3q-13 -29 -13 -54q0 -44 40 -94q-175 -12 -257 -63q-47 -29 -75.5 -73t-28.5 -95 q0 -43 18.5 -77.5t48.5 -56.5t69 -37t77.5 -21t76.5 -6q60 0 120.5 15.5t113.5 46t86 82.5t33 117q0 49 -20 89.5t-49 66.5t-58 47.5t-49 44t-20 44.5t15.5 42.5t37.5 39.5t44 42t37.5 59.5t15.5 82.5q0 60 -22.5 99.5t-72.5 90.5h83zM1152 672h128v64h-128v128h-64v-128 h-128v-64h128v-160h64v160zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M735 740q0 -36 32 -70.5t77.5 -68t90.5 -73.5t77 -104t32 -142q0 -90 -48 -173q-72 -122 -211 -179.5t-298 -57.5q-132 0 -246.5 41.5t-171.5 137.5q-37 60 -37 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 42 -47.5 74t-15.5 73q0 36 21 85q-46 -4 -68 -4 q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q77 66 182.5 98t217.5 32h418l-138 -88h-131q74 -63 112 -133t38 -160q0 -72 -24.5 -129.5t-59 -93t-69.5 -65t-59.5 -61.5t-24.5 -66zM589 836q38 0 78 16.5t66 43.5q53 57 53 159q0 58 -17 125t-48.5 129.5 t-84.5 103.5t-117 41q-42 0 -82.5 -19.5t-65.5 -52.5q-47 -59 -47 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26zM591 -37q58 0 111.5 13t99 39t73 73t27.5 109q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -48 2 q-53 0 -105 -7t-107.5 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -70 35 -123.5t91.5 -83t119 -44t127.5 -14.5zM1401 839h213v-108h-213v-219h-105v219h-212v108h212v217h105v-217z" />
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+<glyph unicode="&#xf110;" horiz-adv-x="1792" d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5 q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
+<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
+<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
+<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
+<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+<glyph unicode="&#xf1a0;" horiz-adv-x="1280" d="M981 197q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -49 2q-53 0 -104.5 -7t-107 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -56 23.5 -102t61 -75.5t87 -50t100 -29t101.5 -8.5q58 0 111.5 13t99 39t73 73t27.5 109zM864 1055 q0 59 -17 125.5t-48 129t-84 103.5t-117 41q-42 0 -82.5 -19.5t-66.5 -52.5q-46 -59 -46 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26q37 0 77.5 16.5t65.5 43.5q53 56 53 159zM752 1536h417l-137 -88h-132q75 -63 113 -133t38 -160q0 -72 -24.5 -129.5 t-59.5 -93t-69.5 -65t-59 -61.5t-24.5 -66q0 -36 32 -70.5t77 -68t90.5 -73.5t77.5 -104t32 -142q0 -91 -49 -173q-71 -122 -209.5 -179.5t-298.5 -57.5q-132 0 -246.5 41.5t-172.5 137.5q-36 59 -36 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 41 -47.5 73.5 t-15.5 73.5q0 40 21 85q-46 -4 -68 -4q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q76 66 182 98t218 32z" />
+<glyph unicode="&#xf1a1;" horiz-adv-x="2304" d="M1509 107q0 -14 -12 -29q-52 -59 -147.5 -83t-196.5 -24q-252 0 -346 107q-12 15 -12 29q0 17 12 29.5t29 12.5q15 0 30 -12q58 -49 125.5 -66t159.5 -17t160 17t127 66q15 12 30 12q17 0 29 -12.5t12 -29.5zM978 498q0 -61 -43 -104t-104 -43q-60 0 -104.5 43.5 t-44.5 103.5q0 61 44 105t105 44t104 -44t43 -105zM1622 498q0 -61 -43 -104t-104 -43q-60 0 -104.5 43.5t-44.5 103.5q0 61 44 105t105 44t104 -44t43 -105zM415 793q-39 27 -88 27q-66 0 -113 -47t-47 -113q0 -72 54 -121q53 141 194 254zM2020 382q0 222 -249 387 q-128 85 -291.5 126.5t-331.5 41.5t-331.5 -41.5t-292.5 -126.5q-249 -165 -249 -387t249 -387q129 -85 292.5 -126.5t331.5 -41.5t331.5 41.5t291.5 126.5q249 165 249 387zM2137 660q0 66 -47 113t-113 47q-50 0 -93 -30q140 -114 192 -256q61 48 61 126zM1993 1335 q0 49 -34.5 83.5t-82.5 34.5q-49 0 -83.5 -34.5t-34.5 -83.5q0 -48 34.5 -82.5t83.5 -34.5q48 0 82.5 34.5t34.5 82.5zM2220 660q0 -65 -33 -122t-89 -90q5 -35 5 -66q0 -139 -79 -255.5t-208 -201.5q-140 -92 -313.5 -136.5t-354.5 -44.5t-355 44.5t-314 136.5 q-129 85 -208 201.5t-79 255.5q0 36 6 71q-53 33 -83.5 88.5t-30.5 118.5q0 100 71 171.5t172 71.5q91 0 159 -60q265 170 638 177l144 456q10 29 40 29q24 0 384 -90q24 55 74 88t110 33q82 0 141 -59t59 -142t-59 -141.5t-141 -58.5q-83 0 -141.5 58.5t-59.5 140.5 l-339 80l-125 -395q349 -15 603 -179q71 63 163 63q101 0 172 -71.5t71 -171.5z" />
+<glyph unicode="&#xf1a2;" d="M950 393q7 7 17.5 7t17.5 -7t7 -18t-7 -18q-65 -64 -208 -64h-1h-1q-143 0 -207 64q-8 7 -8 18t8 18q7 7 17.5 7t17.5 -7q49 -51 172 -51h1h1q122 0 173 51zM671 613q0 -37 -26 -64t-63 -27t-63 27t-26 64t26 63t63 26t63 -26t26 -63zM1214 1049q-29 0 -50 21t-21 50 q0 30 21 51t50 21q30 0 51 -21t21 -51q0 -29 -21 -50t-51 -21zM1216 1408q132 0 226 -94t94 -227v-894q0 -133 -94 -227t-226 -94h-896q-132 0 -226 94t-94 227v894q0 133 94 227t226 94h896zM1321 596q35 14 57 45.5t22 70.5q0 51 -36 87.5t-87 36.5q-60 0 -98 -48 q-151 107 -375 115l83 265l206 -49q1 -50 36.5 -85t84.5 -35q50 0 86 35.5t36 85.5t-36 86t-86 36q-36 0 -66 -20.5t-45 -53.5l-227 54q-9 2 -17.5 -2.5t-11.5 -14.5l-95 -302q-224 -4 -381 -113q-36 43 -93 43q-51 0 -87 -36.5t-36 -87.5q0 -37 19.5 -67.5t52.5 -45.5 q-7 -25 -7 -54q0 -98 74 -181.5t201.5 -132t278.5 -48.5q150 0 277.5 48.5t201.5 132t74 181.5q0 27 -6 54zM971 702q37 0 63 -26t26 -63t-26 -64t-63 -27t-63 27t-26 64t26 63t63 26z" />
+<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
+<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
+<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
+<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
+<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
+<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
+<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
+<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
+<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
+<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
+<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
+<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
+<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
+<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
+<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
+<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
+<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1bd;" horiz-adv-x="1024" d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" />
+<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
+<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
+<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
+<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
+<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
+<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
+<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
+<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
+<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
+<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
+<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
+<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348q0 222 101 414.5t276.5 317t390.5 155.5v-260q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 q0 230 -145.5 406t-366.5 221v260q215 -31 390.5 -155.5t276.5 -317t101 -414.5z" />
+<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
+<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
+<glyph unicode="&#xf1d4;" d="M825 547l343 588h-150q-21 -39 -63.5 -118.5t-68 -128.5t-59.5 -118.5t-60 -128.5h-3q-21 48 -44.5 97t-52 105.5t-46.5 92t-54 104.5t-49 95h-150l323 -589v-435h134v436zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
+<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
+<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
+<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
+<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
+<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
+<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
+<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
+<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
+<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
+<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
+<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
+<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1ed;" horiz-adv-x="1792" d="M1112 1090q0 159 -237 159h-70q-32 0 -59.5 -21.5t-34.5 -52.5l-63 -276q-2 -5 -2 -16q0 -24 17 -39.5t41 -15.5h53q69 0 128.5 13t112.5 41t83.5 81.5t30.5 126.5zM1716 938q0 -265 -220 -428q-219 -161 -612 -161h-61q-32 0 -59 -21.5t-34 -52.5l-73 -316 q-8 -36 -40.5 -61.5t-69.5 -25.5h-213q-31 0 -53 20t-22 51q0 10 13 65h151q34 0 64 23.5t38 56.5l73 316q8 33 37.5 57t63.5 24h61q390 0 607 160t217 421q0 129 -51 207q183 -92 183 -335zM1533 1123q0 -264 -221 -428q-218 -161 -612 -161h-60q-32 0 -59.5 -22t-34.5 -53 l-73 -315q-8 -36 -40 -61.5t-69 -25.5h-214q-31 0 -52.5 19.5t-21.5 51.5q0 8 2 20l300 1301q8 36 40.5 61.5t69.5 25.5h444q68 0 125 -4t120.5 -15t113.5 -30t96.5 -50.5t77.5 -74t49.5 -103.5t18.5 -136z" />
+<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
+<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
+<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
+<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M322 689h-15q-19 0 -19 18q0 28 19 85q5 15 15 19.5t28 4.5q77 0 77 -49q0 -41 -30.5 -59.5t-74.5 -18.5zM664 528q-47 0 -47 29q0 62 123 62l3 -3q-5 -88 -79 -88zM1438 687h-15q-19 0 -19 19q0 28 19 85q5 15 14.5 19t28.5 4q77 0 77 -49q0 -41 -30.5 -59.5 t-74.5 -18.5zM1780 527q-47 0 -47 30q0 62 123 62l3 -3q-5 -89 -79 -89zM373 894h-128q-8 0 -14.5 -4t-8.5 -7.5t-7 -12.5q-3 -7 -45 -190t-42 -192q0 -7 5.5 -12.5t13.5 -5.5h62q25 0 32.5 34.5l15 69t32.5 34.5q47 0 87.5 7.5t80.5 24.5t63.5 52.5t23.5 84.5 q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM719 798q-38 0 -74 -6q-2 0 -8.5 -1t-9 -1.5l-7.5 -1.5t-7.5 -2t-6.5 -3t-6.5 -4t-5 -5t-4.5 -7t-4 -9q-9 -29 -9 -39t9 -10q5 0 21.5 5t19.5 6q30 8 58 8q74 0 74 -36q0 -11 -10 -14q-8 -2 -18 -3t-21.5 -1.5t-17.5 -1.5 q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5q0 -38 26 -59.5t64 -21.5q24 0 45.5 6.5t33 13t38.5 23.5q-3 -7 -3 -15t5.5 -13.5t12.5 -5.5h56q1 1 7 3.5t7.5 3.5t5 3.5t5 5.5t2.5 8l45 194q4 13 4 30q0 81 -145 81zM1247 793h-74q-22 0 -39 -23q-5 -7 -29.5 -51 t-46.5 -81.5t-26 -38.5l-5 4q0 77 -27 166q-1 5 -3.5 8.5t-6 6.5t-6.5 5t-8.5 3t-8.5 1.5t-9.5 1t-9 0.5h-10h-8.5q-38 0 -38 -21l1 -5q5 -53 25 -151t25 -143q2 -16 2 -24q0 -19 -30.5 -61.5t-30.5 -58.5q0 -13 40 -13q61 0 76 25l245 415q10 20 10 26q0 9 -8 9zM1489 892 h-129q-18 0 -29 -23q-6 -13 -46.5 -191.5t-40.5 -190.5q0 -20 43 -20h7.5h9h9t9.5 1t8.5 2t8.5 3t6.5 4.5t5.5 6t3 8.5l21 91q2 10 10.5 17t19.5 7q47 0 87.5 7t80.5 24.5t63.5 52.5t23.5 84q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM1835 798q-26 0 -74 -6 q-38 -6 -48 -16q-7 -8 -11 -19q-8 -24 -8 -39q0 -10 8 -10q1 0 41 12q30 8 58 8q74 0 74 -36q0 -12 -10 -14q-4 -1 -57 -7q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5t26 -58.5t64 -21.5q24 0 45 6t34 13t38 24q-3 -15 -3 -16q0 -5 2 -8.5t6.5 -5.5t8 -3.5 t10.5 -2t9.5 -0.5h9.5h8q42 0 48 25l45 194q3 15 3 31q0 81 -145 81zM2157 889h-55q-25 0 -33 -40q-10 -44 -36.5 -167t-42.5 -190v-5q0 -16 16 -18h1h57q10 0 18.5 6.5t10.5 16.5l83 374h-1l1 5q0 7 -5.5 12.5t-13.5 5.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048 q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
+<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
+<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
+<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
+<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
+<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
+<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
+<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
+<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
+<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
+<glyph unicode="&#xf20d;" d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" />
+<glyph unicode="&#xf20e;" horiz-adv-x="2048" d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5 q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360q2 0 4.5 -1t5.5 -2.5l5 -2.5l188 199v347l-187 194 q-13 -8 -29 -10zM986 1438h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13 zM552 226h402l64 66l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224 l213 -225zM1023 946l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196 l-48 -227l130 227h-82zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" />
+<glyph unicode="&#xf210;" d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" />
+<glyph unicode="&#xf211;" d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" />
+<glyph unicode="&#xf212;" horiz-adv-x="2048" d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25 q209 0 374 -102q172 107 374 102z" />
+<glyph unicode="&#xf213;" horiz-adv-x="2048" d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284 q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" />
+<glyph unicode="&#xf214;" d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114 v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378 v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51 h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5 t-43 -34t-16.5 -53.5z" />
+<glyph unicode="&#xf215;" horiz-adv-x="2048" d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" />
+<glyph unicode="&#xf216;" horiz-adv-x="2048" d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126.5t-103.5 132.5t-108.5 126t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113 t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5 q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" />
+<glyph unicode="&#xf217;" horiz-adv-x="1664" d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf218;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920 q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf219;" horiz-adv-x="2048" d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" />
+<glyph unicode="&#xf21a;" horiz-adv-x="2048" d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83 q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314 v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" />
+<glyph unicode="&#xf21b;" d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5 q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31 t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" />
+<glyph unicode="&#xf21c;" horiz-adv-x="2304" d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105 l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226 t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" />
+<glyph unicode="&#xf21d;" d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384 q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5 t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf21e;" horiz-adv-x="1792" d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124 t127 -344z" />
+<glyph unicode="&#xf221;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" />
+<glyph unicode="&#xf222;" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h416q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-419 -420q87 -104 129.5 -236.5t30.5 -276.5q-22 -250 -200.5 -431t-428.5 -206q-163 -17 -314 39.5t-256.5 162t-162 256.5t-39.5 314q25 250 206 428.5 t431 200.5q144 12 276.5 -30.5t236.5 -129.5l419 419h-261q-14 0 -23 9t-9 23v64zM704 -128q117 0 223.5 45.5t184 123t123 184t45.5 223.5t-45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123 t223.5 -45.5z" />
+<glyph unicode="&#xf223;" horiz-adv-x="1280" d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf224;" d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5 t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf225;" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9 t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf226;" horiz-adv-x="1792" d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391 q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391 q0 -226 -154 -391q103 -57 218 -57z" />
+<glyph unicode="&#xf227;" horiz-adv-x="1920" d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9 t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128 q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -29 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" />
+<glyph unicode="&#xf228;" horiz-adv-x="2048" d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9 t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5 t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" />
+<glyph unicode="&#xf229;" horiz-adv-x="1792" d="M1728 1536q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-229 -230l156 -156q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-156 157l-99 -100q87 -104 129.5 -236.5t30.5 -276.5q-22 -250 -200.5 -431t-428.5 -206q-163 -17 -314 39.5 t-256.5 162t-162 256.5t-39.5 314q25 250 206 428.5t431 200.5q144 12 276.5 -30.5t236.5 -129.5l99 99l-156 156q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l156 -156l229 229h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM1280 448q0 117 -45.5 223.5t-123 184t-184 123 t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5z" />
+<glyph unicode="&#xf22a;" horiz-adv-x="1280" d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5 t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22b;" horiz-adv-x="2048" d="M2029 685q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-131q-12 -119 -67 -226t-139 -183.5t-196.5 -121.5t-234.5 -45q-180 0 -330.5 91t-234.5 247 t-74 337q8 162 94 300t226.5 219.5t302.5 85.5q166 4 310.5 -71.5t235.5 -208.5t107 -296h131v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM640 128q104 0 198.5 40.5t163.5 109.5t109.5 163.5 t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf22c;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf22e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf22f;" horiz-adv-x="1792" />
+<glyph unicode="&#xf230;" d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" />
+<glyph unicode="&#xf231;" horiz-adv-x="1280" d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5 q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" />
+<glyph unicode="&#xf232;" d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233 l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" />
+<glyph unicode="&#xf233;" horiz-adv-x="1792" d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" />
+<glyph unicode="&#xf234;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" />
+<glyph unicode="&#xf235;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69 t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" />
+<glyph unicode="&#xf236;" horiz-adv-x="2048" d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 q-26 0 -45 -19t-19 -45v-384h1152z" />
+<glyph unicode="&#xf237;" d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" />
+<glyph unicode="&#xf238;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" />
+<glyph unicode="&#xf239;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" />
+<glyph unicode="&#xf23a;" horiz-adv-x="1792" d="M1792 204v-209h-642v209h134v926h-6l-314 -1135h-243l-310 1135h-8v-926h135v-209h-538v209h69q21 0 43 19.5t22 37.5v881q0 18 -22 40t-43 22h-69v209h672l221 -821h6l223 821h670v-209h-71q-19 0 -41 -22t-22 -40v-881q0 -18 21.5 -37.5t41.5 -19.5h71z" />
+<glyph unicode="&#xf23b;" horiz-adv-x="1792" />
+<glyph unicode="&#xf23c;" horiz-adv-x="1792" />
+<glyph unicode="&#xf23d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf23e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.ttf b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..ed9372f
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.ttf
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..8b280b9
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff2 b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..3311d58
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/font-awesome/fonts/fontawesome-webfont.woff2
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.eot b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..4a4ca86
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.svg b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..89d2909
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata/>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200">
+<font-face units-per-em="1200" ascent="960" descent="-240"/>
+<missing-glyph horiz-adv-x="500"/>
+<glyph/>
+<glyph/>
+<glyph unicode=" "/>
+<glyph unicode=" "/>
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z"/>
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z"/>
+<glyph unicode=" "/>
+<glyph unicode=" " horiz-adv-x="652"/>
+<glyph unicode=" " horiz-adv-x="1304"/>
+<glyph unicode=" " horiz-adv-x="652"/>
+<glyph unicode=" " horiz-adv-x="1304"/>
+<glyph unicode=" " horiz-adv-x="434"/>
+<glyph unicode=" " horiz-adv-x="326"/>
+<glyph unicode=" " horiz-adv-x="217"/>
+<glyph unicode=" " horiz-adv-x="217"/>
+<glyph unicode=" " horiz-adv-x="163"/>
+<glyph unicode=" " horiz-adv-x="260"/>
+<glyph unicode=" " horiz-adv-x="72"/>
+<glyph unicode=" " horiz-adv-x="260"/>
+<glyph unicode=" " horiz-adv-x="326"/>
+<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z"/>
+<glyph unicode="−" d="M200 400h900v300h-900v-300z"/>
+<glyph unicode="◼" horiz-adv-x="500" d="M0 0z"/>
+<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z"/>
+<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z"/>
+<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z"/>
+<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z"/>
+<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z"/>
+<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z"/>
+<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z"/>
+<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z"/>
+<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z"/>
+<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z"/>
+<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z"/>
+<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z"/>
+<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z"/>
+<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z"/>
+<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z"/>
+<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z"/>
+<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z"/>
+<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z"/>
+<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z"/>
+<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z"/>
+<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z"/>
+<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z"/>
+<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z"/>
+<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z"/>
+<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z"/>
+<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z"/>
+<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z"/>
+<glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z"/>
+<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z"/>
+<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z"/>
+<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z"/>
+<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z"/>
+<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z"/>
+<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z"/>
+<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z"/>
+<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z"/>
+<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z"/>
+<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z"/>
+<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z"/>
+<glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z"/>
+<glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z"/>
+<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z"/>
+<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z"/>
+<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z"/>
+<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z"/>
+<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z"/>
+<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z"/>
+<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z"/>
+<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z "/>
+<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z"/>
+<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z"/>
+<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z"/>
+<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z"/>
+<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z"/>
+<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z"/>
+<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z"/>
+<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z"/>
+<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z"/>
+<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z "/>
+<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z"/>
+<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z"/>
+<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z"/>
+<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z"/>
+<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z"/>
+<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z"/>
+<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z"/>
+<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z"/>
+<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z"/>
+<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z"/>
+<glyph unicode="" d="M200 0l900 550l-900 550v-1100z"/>
+<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z"/>
+<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z"/>
+<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z"/>
+<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z"/>
+<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z"/>
+<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z"/>
+<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z"/>
+<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z"/>
+<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z"/>
+<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z"/>
+<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z"/>
+<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z"/>
+<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z"/>
+<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z"/>
+<glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z"/>
+<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z"/>
+<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z"/>
+<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z"/>
+<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z"/>
+<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z"/>
+<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z"/>
+<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z"/>
+<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z"/>
+<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z"/>
+<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z"/>
+<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z"/>
+<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z"/>
+<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z"/>
+<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z"/>
+<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z"/>
+<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z"/>
+<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z"/>
+<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z"/>
+<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z"/>
+<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z"/>
+<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z"/>
+<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z"/>
+<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z"/>
+<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z"/>
+<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z"/>
+<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z"/>
+<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z"/>
+<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z"/>
+<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z"/>
+<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z"/>
+<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z"/>
+<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z"/>
+<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z"/>
+<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z"/>
+<glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z"/>
+<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z"/>
+<glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z"/>
+<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z"/>
+<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z"/>
+<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z"/>
+<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z"/>
+<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z"/>
+<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z"/>
+<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z"/>
+<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z"/>
+<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z"/>
+<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z"/>
+<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z"/>
+<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z"/>
+<glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z"/>
+<glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z"/>
+<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z"/>
+<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z"/>
+<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z"/>
+<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z"/>
+<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z"/>
+<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z"/>
+<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z"/>
+<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z"/>
+<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z"/>
+<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z"/>
+<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z"/>
+<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z"/>
+<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z"/>
+<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z"/>
+<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z"/>
+<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z"/>
+<glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z"/>
+<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z "/>
+<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z"/>
+<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z"/>
+<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z"/>
+<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z"/>
+<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z"/>
+<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z"/>
+<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z"/>
+<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z"/>
+<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z"/>
+<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z"/>
+<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z"/>
+<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z"/>
+<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z"/>
+<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z"/>
+<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z"/>
+<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z"/>
+<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z"/>
+<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z"/>
+<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z"/>
+<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z"/>
+<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z"/>
+<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z"/>
+<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z"/>
+<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z"/>
+<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z"/>
+<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z"/>
+<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z"/>
+<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z"/>
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.ttf b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..67fa00b
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.woff b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..8c54182
--- /dev/null
+++ b/chimere_example_project/chimere_example_static/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/chimere_example_project/fixtures/first_data.json b/chimere_example_project/fixtures/first_data.json
new file mode 100644
index 0000000..814e8e0
--- /dev/null
+++ b/chimere_example_project/fixtures/first_data.json
@@ -0,0 +1,853 @@
+[
+ {
+ "pk": 20,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "area",
+ "name": "Area",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 14,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "category",
+ "name": "Category",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 13,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "color",
+ "name": "Color",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 12,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "colortheme",
+ "name": "Color theme",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 6,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "contenttype",
+ "name": "content type",
+ "app_label": "contenttypes"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "group",
+ "name": "group",
+ "app_label": "auth"
+ }
+ },
+ {
+ "pk": 15,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "icon",
+ "name": "Icon",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 5,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "logentry",
+ "name": "log entry",
+ "app_label": "admin"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "message",
+ "name": "message",
+ "app_label": "auth"
+ }
+ },
+ {
+ "pk": 9,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "migrationhistory",
+ "name": "migration history",
+ "app_label": "south"
+ }
+ },
+ {
+ "pk": 10,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "news",
+ "name": "News",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 1,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "permission",
+ "name": "permission",
+ "app_label": "auth"
+ }
+ },
+ {
+ "pk": 17,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "marker",
+ "name": "Point of interest",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 22,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "property",
+ "name": "Property",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 21,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "propertymodel",
+ "name": "Property model",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 19,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "route",
+ "name": "Route",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 18,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "routefile",
+ "name": "Route file",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 7,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "session",
+ "name": "session",
+ "app_label": "sessions"
+ }
+ },
+ {
+ "pk": 8,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "site",
+ "name": "site",
+ "app_label": "sites"
+ }
+ },
+ {
+ "pk": 16,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "subcategory",
+ "name": "Subcategory",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 11,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "tinyurl",
+ "name": "TinyUrl",
+ "app_label": "chimere"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "contenttypes.contenttype",
+ "fields": {
+ "model": "user",
+ "name": "user",
+ "app_label": "auth"
+ }
+ },
+ {
+ "pk": 1,
+ "model": "sites.site",
+ "fields": {
+ "domain": "example.com",
+ "name": "example.com"
+ }
+ },
+ {
+ "pk": 13,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_logentry",
+ "name": "Can add log entry",
+ "content_type": 5
+ }
+ },
+ {
+ "pk": 14,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_logentry",
+ "name": "Can change log entry",
+ "content_type": 5
+ }
+ },
+ {
+ "pk": 15,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_logentry",
+ "name": "Can delete log entry",
+ "content_type": 5
+ }
+ },
+ {
+ "pk": 4,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_group",
+ "name": "Can add group",
+ "content_type": 2
+ }
+ },
+ {
+ "pk": 5,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_group",
+ "name": "Can change group",
+ "content_type": 2
+ }
+ },
+ {
+ "pk": 6,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_group",
+ "name": "Can delete group",
+ "content_type": 2
+ }
+ },
+ {
+ "pk": 10,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_message",
+ "name": "Can add message",
+ "content_type": 4
+ }
+ },
+ {
+ "pk": 11,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_message",
+ "name": "Can change message",
+ "content_type": 4
+ }
+ },
+ {
+ "pk": 12,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_message",
+ "name": "Can delete message",
+ "content_type": 4
+ }
+ },
+ {
+ "pk": 1,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_permission",
+ "name": "Can add permission",
+ "content_type": 1
+ }
+ },
+ {
+ "pk": 2,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_permission",
+ "name": "Can change permission",
+ "content_type": 1
+ }
+ },
+ {
+ "pk": 3,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_permission",
+ "name": "Can delete permission",
+ "content_type": 1
+ }
+ },
+ {
+ "pk": 7,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_user",
+ "name": "Can add user",
+ "content_type": 3
+ }
+ },
+ {
+ "pk": 8,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_user",
+ "name": "Can change user",
+ "content_type": 3
+ }
+ },
+ {
+ "pk": 9,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_user",
+ "name": "Can delete user",
+ "content_type": 3
+ }
+ },
+ {
+ "pk": 58,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_area",
+ "name": "Can add Area",
+ "content_type": 20
+ }
+ },
+ {
+ "pk": 59,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_area",
+ "name": "Can change Area",
+ "content_type": 20
+ }
+ },
+ {
+ "pk": 60,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_area",
+ "name": "Can delete Area",
+ "content_type": 20
+ }
+ },
+ {
+ "pk": 40,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_route",
+ "name": "Can add Route",
+ "content_type": 14
+ }
+ },
+ {
+ "pk": 41,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_route",
+ "name": "Can change Route",
+ "content_type": 14
+ }
+ },
+ {
+ "pk": 42,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_route",
+ "name": "Can delete Route",
+ "content_type": 14
+ }
+ },
+ {
+ "pk": 37,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_marker",
+ "name": "Can add Point of interest",
+ "content_type": 13
+ }
+ },
+ {
+ "pk": 38,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_marker",
+ "name": "Can change Point of interest",
+ "content_type": 13
+ }
+ },
+ {
+ "pk": 39,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_marker",
+ "name": "Can delete Point of interest",
+ "content_type": 13
+ }
+ },
+ {
+ "pk": 34,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_subcategory",
+ "name": "Can add Subcategory",
+ "content_type": 12
+ }
+ },
+ {
+ "pk": 35,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_subcategory",
+ "name": "Can change Subcategory",
+ "content_type": 12
+ }
+ },
+ {
+ "pk": 36,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_subcategory",
+ "name": "Can delete Subcategory",
+ "content_type": 12
+ }
+ },
+ {
+ "pk": 43,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_area",
+ "name": "Can add Area",
+ "content_type": 15
+ }
+ },
+ {
+ "pk": 44,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_area",
+ "name": "Can change Area",
+ "content_type": 15
+ }
+ },
+ {
+ "pk": 45,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_area",
+ "name": "Can delete Area",
+ "content_type": 15
+ }
+ },
+ {
+ "pk": 49,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_property",
+ "name": "Can add Property",
+ "content_type": 17
+ }
+ },
+ {
+ "pk": 50,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_property",
+ "name": "Can change Property",
+ "content_type": 17
+ }
+ },
+ {
+ "pk": 51,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_property",
+ "name": "Can delete Property",
+ "content_type": 17
+ }
+ },
+ {
+ "pk": 28,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_category",
+ "name": "Can add Category",
+ "content_type": 10
+ }
+ },
+ {
+ "pk": 29,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_category",
+ "name": "Can change Category",
+ "content_type": 10
+ }
+ },
+ {
+ "pk": 30,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_category",
+ "name": "Can delete Category",
+ "content_type": 10
+ }
+ },
+ {
+ "pk": 64,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_property",
+ "name": "Can add Property",
+ "content_type": 22
+ }
+ },
+ {
+ "pk": 65,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_property",
+ "name": "Can change Property",
+ "content_type": 22
+ }
+ },
+ {
+ "pk": 66,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_property",
+ "name": "Can delete Property",
+ "content_type": 22
+ }
+ },
+ {
+ "pk": 61,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_propertymodel",
+ "name": "Can add Property model",
+ "content_type": 21
+ }
+ },
+ {
+ "pk": 62,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_propertymodel",
+ "name": "Can change Property model",
+ "content_type": 21
+ }
+ },
+ {
+ "pk": 63,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_propertymodel",
+ "name": "Can delete Property model",
+ "content_type": 21
+ }
+ },
+ {
+ "pk": 55,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_route",
+ "name": "Can add Route",
+ "content_type": 19
+ }
+ },
+ {
+ "pk": 56,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_route",
+ "name": "Can change Route",
+ "content_type": 19
+ }
+ },
+ {
+ "pk": 57,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_route",
+ "name": "Can delete Route",
+ "content_type": 19
+ }
+ },
+ {
+ "pk": 52,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_routefile",
+ "name": "Can add Route file",
+ "content_type": 18
+ }
+ },
+ {
+ "pk": 53,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_routefile",
+ "name": "Can change Route file",
+ "content_type": 18
+ }
+ },
+ {
+ "pk": 54,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_routefile",
+ "name": "Can delete Route file",
+ "content_type": 18
+ }
+ },
+ {
+ "pk": 46,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_propertymodel",
+ "name": "Can add Property model",
+ "content_type": 16
+ }
+ },
+ {
+ "pk": 47,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_propertymodel",
+ "name": "Can change Property model",
+ "content_type": 16
+ }
+ },
+ {
+ "pk": 48,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_propertymodel",
+ "name": "Can delete Property model",
+ "content_type": 16
+ }
+ },
+ {
+ "pk": 31,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_icon",
+ "name": "Can add Icon",
+ "content_type": 11
+ }
+ },
+ {
+ "pk": 32,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_icon",
+ "name": "Can change Icon",
+ "content_type": 11
+ }
+ },
+ {
+ "pk": 33,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_icon",
+ "name": "Can delete Icon",
+ "content_type": 11
+ }
+ },
+ {
+ "pk": 16,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_contenttype",
+ "name": "Can add content type",
+ "content_type": 6
+ }
+ },
+ {
+ "pk": 17,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_contenttype",
+ "name": "Can change content type",
+ "content_type": 6
+ }
+ },
+ {
+ "pk": 18,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_contenttype",
+ "name": "Can delete content type",
+ "content_type": 6
+ }
+ },
+ {
+ "pk": 19,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_session",
+ "name": "Can add session",
+ "content_type": 7
+ }
+ },
+ {
+ "pk": 20,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_session",
+ "name": "Can change session",
+ "content_type": 7
+ }
+ },
+ {
+ "pk": 21,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_session",
+ "name": "Can delete session",
+ "content_type": 7
+ }
+ },
+ {
+ "pk": 22,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_site",
+ "name": "Can add site",
+ "content_type": 8
+ }
+ },
+ {
+ "pk": 23,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_site",
+ "name": "Can change site",
+ "content_type": 8
+ }
+ },
+ {
+ "pk": 24,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_site",
+ "name": "Can delete site",
+ "content_type": 8
+ }
+ },
+ {
+ "pk": 25,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "add_news",
+ "name": "Can add News",
+ "content_type": 9
+ }
+ },
+ {
+ "pk": 26,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "change_news",
+ "name": "Can change News",
+ "content_type": 9
+ }
+ },
+ {
+ "pk": 27,
+ "model": "auth.permission",
+ "fields": {
+ "codename": "delete_news",
+ "name": "Can delete News",
+ "content_type": 9
+ }
+ },
+ {
+ "pk": 1,
+ "model": "auth.group",
+ "fields": {
+ "name": "Moderator",
+ "permissions": [
+ 40,
+ 41,
+ 42,
+ 37,
+ 38,
+ 39,
+ 49,
+ 50,
+ 51
+ ]
+ }
+ },
+ {
+ "pk": 2,
+ "model": "auth.group",
+ "fields": {
+ "name": "Application administrator",
+ "permissions": [
+ 40,
+ 41,
+ 42,
+ 37,
+ 38,
+ 39,
+ 34,
+ 35,
+ 36,
+ 43,
+ 44,
+ 45,
+ 49,
+ 50,
+ 51,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 25,
+ 26,
+ 27
+ ]
+ }
+ }
+]
diff --git a/chimere_example_project/local_settings.py.pip.sample b/chimere_example_project/local_settings.py.pip.sample
new file mode 100644
index 0000000..747427f
--- /dev/null
+++ b/chimere_example_project/local_settings.py.pip.sample
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# rename this file to local_settings.py and overload settings in this file
+
+
+ROOT_URLCONF = 'chimere_example_project.urls'
+
+STATIC_URL = '/static/'
+
+CHIMERE_OSM_API_URL = 'api06.dev.openstreetmap.org' # test URL
+CHIMERE_OSM_USER = 'osm_user'
+CHIMERE_OSM_PASSWORD = 'osm_pass'
+
+# Make this string unique, and don't share it with anybody.
+SECRET_KEY = ''
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'NAME': 'chimere',
+ 'ENGINE': 'django.contrib.gis.db.backends.postgis',
+ 'HOST': 'localhost',
+ 'PORT': '5432',
+ 'USER': 'postgres',
+ 'PASSWORD': '',
+ },
+}
+
+# if you want to use tinymce provide an URL or a relative path to find it
+TINYMCE_URL = ''
+JQUERY_JS_URLS = (
+ '%sjquery/jquery.js' % STATIC_URL,
+ 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js')
+JQUERY_CSS_URLS = (
+ 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/'
+ 'base/jquery-ui.css',)
diff --git a/chimere_example_project/local_settings.py.sample b/chimere_example_project/local_settings.py.sample
new file mode 100644
index 0000000..33a4989
--- /dev/null
+++ b/chimere_example_project/local_settings.py.sample
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# rename this file to local_settings.py and overload settings in this file
+
+
+ROOT_URLCONF = 'chimere_example_project.urls'
+
+STATIC_URL = '/static/'
+
+CHIMERE_OSM_API_URL = 'api06.dev.openstreetmap.org' # test URL
+CHIMERE_OSM_USER = 'osm_user'
+CHIMERE_OSM_PASSWORD = 'osm_pass'
+
+# if you want to use tinymce provide an URL or a relative path to find it
+TINYMCE_URL = ''
+
+# Make this string unique, and don't share it with anybody.
+SECRET_KEY = ''
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'NAME': 'chimere',
+ 'ENGINE': 'django.contrib.gis.db.backends.postgis',
+ 'HOST': 'localhost',
+ 'PORT': '5432',
+ 'USER': 'postgres',
+ 'PASSWORD': '',
+ },
+}
diff --git a/chimere_example_project/locale/fr/LC_MESSAGES/django.po b/chimere_example_project/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 0000000..e0db26e
--- /dev/null
+++ b/chimere_example_project/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,165 @@
+# Chimère
+# Copyright (C) 2014
+# This file is distributed under the same license as the Chimère package.
+# Étienne Loks <etienne.loks@peacefrogs.net>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 2.2\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2016-05-15 19:11+0200\n"
+"PO-Revision-Date: 2014-12-10 19:23+0100\n"
+"Last-Translator: Étienne Loks <etienne.loks@peacefrogs.net>\n"
+"Language-Team: Iggdrasil\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+
+#: settings.py:97
+msgid "Foot"
+msgstr "À pied"
+
+#: settings.py:98
+msgid "Bicycle"
+msgstr "En vélo"
+
+#: settings.py:99
+msgid "Motorcar"
+msgstr "En autobus"
+
+#: settings.py:103
+msgid "You are walking slowly"
+msgstr "Vous marchez lentement"
+
+#: settings.py:104
+msgid "You are walking pretty quickly"
+msgstr "Vous marchez plutôt rapidement"
+
+#: settings.py:105
+msgid "You are riding pretty slowly"
+msgstr "Vous conduisez plutôt lentement"
+
+#: settings.py:106
+msgid "You are riding pretty quickly"
+msgstr "Vous conduisez plutôt vite"
+
+#: settings.py:151
+msgid "Hello, I would like to propose you a modification about this item: "
+msgstr "Bonjour, je voudrais proposer une modification pour cet élément :"
+
+#: templates/chimere/base.html:24
+msgid "You must enable JavaScript in your browser to display Chimère."
+msgstr ""
+"Vous devez activer le JavaScript sur votre navigateur pour utiliser Chimère."
+
+#: templates/chimere/detail.html:18
+msgid "Date:"
+msgstr "Date :"
+
+#: templates/chimere/detail.html:25
+msgid ":"
+msgstr " :"
+
+#: templates/chimere/detail.html:27
+msgid "Source:"
+msgstr "Source :"
+
+#: templates/chimere/detail.html:28
+msgid "License:"
+msgstr "Licence :"
+
+#: templates/chimere/detail.html:30
+msgid "Show the gallery"
+msgstr "Montrer la gallerie"
+
+#: templates/chimere/detail.html:35
+msgid "Submit an amendment"
+msgstr "Proposer une modification"
+
+#: templates/chimere/detail.html:38 templates/chimere/detail.html.py:39
+msgid "Propose amendment"
+msgstr "Proposer une modification"
+
+#: templates/chimere/detail.html:38
+msgid "I would like to propose an amendment for this item:"
+msgstr "Je voudrais proposer une modification pour cet élément :"
+
+#: templates/chimere/detail.html:52
+msgid "Gallery"
+msgstr "Galerie"
+
+#: templates/chimere/blocks/actions.html:24
+msgid "Categories "
+msgstr "Catégories"
+
+#: templates/chimere/blocks/actions.html:26
+msgid "Search"
+msgstr "Recherche"
+
+#: templates/chimere/blocks/actions.html:35
+msgid "News"
+msgstr "Actualités"
+
+#: templates/chimere/blocks/actions.html:37
+msgid "Simple map"
+msgstr "Carte simple"
+
+#: templates/chimere/blocks/categories.html:21
+msgid "Tell me more..."
+msgstr "En savoir plus..."
+
+#: templates/chimere/blocks/categories.html:28
+msgid "Display markers and routes waiting for validation"
+msgstr "Afficher les pointeurs et les trajets en cours de validation"
+
+#: templates/chimere/blocks/map.html:6
+msgid "Close"
+msgstr "Fermer"
+
+#: templates/chimere/blocks/map.html:28
+msgid "Loading of the map in progress"
+msgstr "Chargement de la carte en cours"
+
+#: templates/chimere/blocks/map.html:32
+msgid "Display options"
+msgstr "Afficher les options"
+
+#: templates/chimere/blocks/map.html:34
+msgid "Map type"
+msgstr "Type de carte"
+
+#: templates/chimere/blocks/map.html:49
+msgid "Permalink"
+msgstr "Lien permanent"
+
+#: templates/chimere/blocks/news.html:17
+#: templates/chimere/blocks/welcome.html:17
+msgid "Upcoming events"
+msgstr "Événements à venir"
+
+#: templates/chimere/blocks/news.html:51
+#: templates/chimere/blocks/welcome.html:50
+msgid "See it on the map"
+msgstr "Voir sur la carte"
+
+#: templates/chimere/blocks/share_bar.html:3
+msgid "Share on"
+msgstr "Partager sur"
+
+#: templates/chimere/blocks/share_bar.html:7
+msgid "Share"
+msgstr "Partager"
+
+#~ msgid "No results found."
+#~ msgstr "Pas de résultats."
+
+#~ msgid "Previous"
+#~ msgstr "Précedent"
+
+#~ msgid "More results..."
+#~ msgstr "Plus de résultats..."
+
+#~ msgid "No exact match."
+#~ msgstr "Pas de terme correspondant exactement."
diff --git a/chimere_example_project/manage.py b/chimere_example_project/manage.py
new file mode 100755
index 0000000..20f85bc
--- /dev/null
+++ b/chimere_example_project/manage.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+import os, sys
+from django.core.management import execute_manager
+sys.path.insert(0, os.path.abspath('./..'))
+
+try:
+ import settings # Assumed to be in the same directory.
+ if settings.DEBUG:
+ sys.path.insert(0, os.path.abspath('./../chimere'))
+ sys.path.insert(0, os.path.abspath('./../../geo-django-fla/'))
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ execute_manager(settings)
diff --git a/chimere_example_project/project_static/.project_static b/chimere_example_project/project_static/.project_static
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chimere_example_project/project_static/.project_static
diff --git a/chimere_example_project/settings.py b/chimere_example_project/settings.py
new file mode 100644
index 0000000..187d4ba
--- /dev/null
+++ b/chimere_example_project/settings.py
@@ -0,0 +1,352 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Don't edit this file:
+# overload all theses settings in your local_settings.py file
+
+import os
+import sys
+_ = lambda s: s
+
+DEBUG = False
+TEMPLATE_DEBUG = DEBUG
+MOBILE_TEST = False
+
+# Django settings for chimere project.
+PROJECT_NAME = 'Chimere'
+ROOT_PATH = os.path.realpath(os.path.dirname(__file__)) + "/"
+
+EMAIL_HOST = 'localhost'
+CONTACT_EMAIL = ''
+STATIC_URL = '/static/'
+STATIC_ROOT = ROOT_PATH + 'static/'
+
+STATICFILES_DIRS = (
+ os.path.join(ROOT_PATH, "chimere_example_static"),
+)
+
+TINYMCE_URL = ''
+JQUERY_JS_URLS = ('/javascript/jquery/jquery.js',
+ '/javascript/jquery-ui/jquery-ui.js',)
+JQUERY_CSS_URLS = ('/javascript/jquery-ui/css/smoothness/jquery-ui.css',
+ '/javascript/jquery-ui/themes/base/jquery.ui.all.css')
+
+GPSBABEL = '/usr/bin/gpsbabel'
+# simplify with an error of 5 meters
+GPSBABEL_OPTIONS = 'simplify,crosstrack,error=0.005k'
+# GPSBABEL_OPTIONS = 'simplify,count=100'
+
+# # chimere specific ##
+CHIMERE_DEFAULT_ZOOM = 10
+# center of the map
+CHIMERE_DEFAULT_CENTER = (-1.679444, 48.114722)
+# projection used by the main map
+# most public map providers use spherical mercator : 900913
+CHIMERE_EPSG_PROJECTION = 900913
+# projection displayed to the end user by openlayers
+# chimere use the same projection to save its data in the database
+CHIMERE_EPSG_DISPLAY_PROJECTION = 4326
+# display of shortcuts for areas
+CHIMERE_DISPLAY_AREAS = True
+# number of day before an event to display
+# if equal to 0: disable event management
+# if you change this value from 0 to a value in a production environnement
+# don't forget to run the upgrade.py script to create appropriate fields in
+# the database
+CHIMERE_DAYS_BEFORE_EVENT = 30
+# allow feeds
+CHIMERE_FEEDS = True
+# display a directory of items
+CHIMERE_DIRECTORY = True
+
+CHIMERE_ICON_WIDTH = 21
+CHIMERE_ICON_HEIGHT = 25
+CHIMERE_ICON_OFFSET_X = 10
+CHIMERE_ICON_OFFSET_Y = 25
+
+# display picture inside the description by default or inside a galery?
+CHIMERE_MINIATURE_BY_DEFAULT = False
+
+# JS definition of the default map (for admin and when no map are defined in
+# the application)
+# cf. OpenLayers documentation for more details
+# OSM mapnik map
+CHIMERE_DEFAULT_MAP_LAYER = """new ol.layer.Tile({
+ style: 'Road',
+ source: new ol.source.OSM()
+})"""
+
+CHIMERE_XAPI_URL = 'http://open.mapquestapi.com/xapi/api/0.6/'
+CHIMERE_OSM_API_URL = 'api06.dev.openstreetmap.org' # test URL
+CHIMERE_OSM_USER = 'test'
+CHIMERE_OSM_PASSWORD = 'test'
+
+# encoding for shapefile import
+CHIMERE_SHAPEFILE_ENCODING = 'ISO-8859-1'
+
+# as the web server need to be reloaded when property models are changed
+# it could be a good idea to hide it to an admin who could'nt do that
+CHIMERE_HIDE_PROPERTYMODEL = False
+
+# clustering of markers
+CHIMERE_ENABLE_CLUSTERING = False
+
+# enable routing in Chimere
+CHIMERE_ENABLE_ROUTING = False
+
+CHIMERE_ROUTING_TRANSPORT = (('foot', _(u"Foot")),
+ ('bicycle', _(u"Bicycle")),
+ ('motorcar', _(u"Motorcar")),
+ )
+
+CHIMERE_ROUTING_SPEEDS = {
+ 'foot': ((3, _(u"You are walking slowly")),
+ (6, _(u"You are walking pretty quickly")),),
+ 'bicycle': ((16, _(u"You are riding pretty slowly")),
+ (22, _(u"You are riding pretty quickly")),)
+}
+
+# available routing engine: 'routino'
+CHIMERE_ROUTING_ENGINE = {
+ 'ENGINE': 'routino',
+ 'PATH': '/usr/local/src/web/bin/router',
+ 'DB_PATH': '/var/local/routino/',
+}
+
+CHIMERE_ROUTING_FAIL_MESSAGE = u"""<h3 class='warn'>Attention</h3>
+<p>Le moteur de routage a echoue dans sa recherche de trajet. Les points de
+depart ou d'arrivee sont peut-etre trop loin d'une voie existante ou le trajet
+est trop dangereux.</p>"""
+
+NOMINATIM_URL = 'http://nominatim.openstreetmap.org/search'
+
+# Fields used to geolocate with nominatim
+# (http://wiki.openstreetmap.org/wiki/Nominatim#Search)
+# from external sources. Key must be a valid parameters for Nominatim. If given
+# value are property slugs use the corresponding value otherwise use it as a
+# fixed value
+# e.g : {'street':'address', 'city':'city', 'country':u'France'}
+
+CHIMERE_NOMINATIM_FIELDS = {'street': 'address', 'city': 'city',
+ 'country': u'France'}
+MOBILE_TEST = False
+MOBILE_DOMAINS = []
+
+# thumbnail
+CHIMERE_THUMBS_SCALE_HEIGHT = 250
+CHIMERE_THUMBS_SCALE_WIDTH = None
+
+# search engine
+CHIMERE_SEARCH_ENGINE = False
+HAYSTACK_CONNECTIONS = {
+ 'default': {
+ 'ENGINE': 'haystack.backends.solr_backend.SolrEngine',
+ 'URL': 'http://127.0.0.1:8080/solr',
+ 'INCLUDE_SPELLING': True,
+ },
+}
+HAYSTACK_SEARCH_RESULTS_PER_PAGE = 12
+HAYSTACK_AUTOCOMPLETE = False
+
+CHIMERE_MODIF_EMAIL = _(u"Hello, I would like to propose you a modification "
+ u"about this item: ")
+
+CHIMERE_CSV_ENCODING = 'ISO-8859-1'
+
+CHIMERE_DEFAULT_ACTIONS = ['view', 'contribute']
+CHIMERE_DEFAULT_ACTION_LABEL = [u"Cartes", u"Ajouter un element"]
+# generic contact email
+CONTACT_EMAIL = ''
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'NAME': 'chimere',
+ 'ENGINE': 'django.contrib.gis.db.backends.postgis',
+ 'HOST': 'postgres',
+ 'PORT': '5432',
+ 'USER': 'chimere',
+ 'PASSWORD': 'chimere',
+ },
+}
+
+# if 'test' in sys.argv:
+# SOUTH_TESTS_MIGRATE = False
+
+# Local time zone for this installation. Choices can be found here:
+# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html
+# #DATETIME-TIMEZONE-SET-TABLE
+# although not all variations may be possible on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'Europe/Paris'
+
+# Language code for this installation. All choices can be found here:
+# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
+# http://blogs.law.harvard.edu/tech/stories/storyReader$15
+LANGUAGE_CODE = 'fr-fr'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+USE_L10N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ROOT_PATH + 'media/'
+
+# URL that handles the media served from MEDIA_ROOT.
+# Example: "http://media.lawrence.com"
+MEDIA_URL = '/media/'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.middleware.doc.XViewMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware'
+)
+
+ROOT_URLCONF = 'chimere_example_project.urls'
+
+TEMPLATE_DIRS = [
+ ROOT_PATH + 'templates',
+]
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ "django.contrib.auth.context_processors.auth",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.i18n",
+ "django.core.context_processors.media",
+ "django.core.context_processors.static",
+ "django.contrib.messages.context_processors.messages",
+ "django.core.context_processors.request",
+)
+
+INSTALLED_APPS = [
+ 'django.contrib.auth',
+ 'django.contrib.admin',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.gis',
+ 'django.contrib.staticfiles',
+]
+
+# celery
+try:
+ import djcelery
+ djcelery.setup_loader()
+ BROKER_URL = 'django://'
+ INSTALLED_APPS += ['kombu.transport.django',
+ 'djcelery']
+except ImportError:
+ # some import and export will not be available
+ pass
+
+INSTALLED_APPS += [
+ 'south',
+ 'chimere',
+]
+
+LOG_PATH = '/var/log/django/'
+MOBILE_DOMAINS = [] # if you have specific domains for mobile access
+
+CHIMERE_VIEW_RENDERER = 'openlayers' # 'openlayers' or 'leaflet'
+CHIMERE_EDIT_RENDERER = 'openlayers' # 'openlayers'
+
+try:
+ from local_settings import *
+except ImportError, e:
+ print 'Unable to load local_settings.py:', e
+
+if CHIMERE_SEARCH_ENGINE:
+ INSTALLED_APPS.insert(INSTALLED_APPS.index('south'), 'haystack')
+
+if 'LOGGING' not in globals():
+ global LOGGING
+ LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'handlers': {
+ # Include the default Django email handler for errors
+ # This is what you'd get without configuring logging at all.
+ 'mail_admins': {
+ 'class': 'django.utils.log.AdminEmailHandler',
+ 'level': 'ERROR',
+ # But the emails are plain text by default - HTML is nicer
+ 'include_html': True,
+ },
+ # Log to a text file that can be rotated by logrotate
+ 'logfile': {
+ 'class': 'logging.handlers.WatchedFileHandler',
+ 'filename': LOG_PATH + 'chimere.log'
+ },
+ },
+ 'loggers': {
+ # Again, default Django configuration to email unhandled exceptions
+ 'django.request': {
+ 'handlers': ['mail_admins'],
+ 'level': 'ERROR',
+ 'propagate': True,
+ },
+ # Might as well log any errors anywhere else in Django
+ 'django': {
+ 'handlers': ['logfile'],
+ 'level': 'ERROR',
+ 'propagate': False,
+ },
+ # Your own app
+ # this assumes all your logger names start with "myapp."
+ 'chimere': {
+ 'handlers': ['logfile'],
+ 'level': 'WARNING', # Or maybe INFO or DEBUG
+ 'propogate': False
+ },
+ },
+ }
+
+
+if 'CHIMERE_SHARE_NETWORKS' not in globals():
+ # after the locals to get the right STATIC_URL
+
+ # share with
+ global CHIMERE_SHARE_NETWORKS
+ CHIMERE_SHARE_NETWORKS = (
+ ("Email", 'mailto:?subject=%(text)s&body=%(url)s',
+ STATIC_URL + 'chimere/img/email.png'),
+ ("Facebook", 'http://www.facebook.com/sharer.php?t=%(text)s&u=%(url)s',
+ STATIC_URL + 'chimere/img/facebook.png'),
+ ("Twitter", 'http://twitter.com/home?status=%(text)s %(url)s',
+ STATIC_URL + 'chimere/img/twitter.png'),
+ )
+
+if 'MAP_CSS_URLS' not in globals():
+ global MAP_CSS_URLS
+ MAP_CSS_URLS = [STATIC_URL + "ol3/ol.css"]
+
+if 'MAP_JS_URLS' not in globals():
+ global MAP_JS_URLS
+ if DEBUG:
+ MAP_JS_URLS = [STATIC_URL + "ol3/ol-debug.js"]
+ else:
+ MAP_JS_URLS = [STATIC_URL + "ol3/ol.js"]
+if 'OSM_MOBILE_JS_URLS' not in globals():
+ global OSM_MOBILE_URLS
+ OSM_JS_MOBILE_URLS = [
+ STATIC_URL + "openlayers/OpenLayers.mobile.js",
+ STATIC_URL + "openlayers/SimplePanZoom.js",
+ "http://www.openstreetmap.org/openlayers/OpenStreetMap.js"]
diff --git a/chimere_example_project/templates/chimere/base.html b/chimere_example_project/templates/chimere/base.html
new file mode 100644
index 0000000..70b5929
--- /dev/null
+++ b/chimere_example_project/templates/chimere/base.html
@@ -0,0 +1,41 @@
+{% extends "base.html" %}
+{% load chimere_tags i18n %}
+{% block extra_head %}
+<link rel="stylesheet" href="{{ STATIC_URL }}chimere/css/styles.css" />
+<link rel="stylesheet" href="{{ STATIC_URL }}chimere/css/print.css" media='print'/>
+{% if css_area %}
+<link rel="stylesheet" href="{{ css_area }}" />{% endif %}
+{% if MOBILE %}
+<link rel="stylesheet" href="{{ STATIC_URL }}chimere/css/mobile.css" />
+<script src="{{ STATIC_URL }}chimere/js/mobile.chimere.js" type="text/javascript"></script>{%endif%}
+<link rel="stylesheet" href="{{ STATIC_URL }}font-awesome/css/font-awesome.min.css" />
+<link rel="stylesheet" href="{{ STATIC_URL }}bootstrap/bootstrap.min.css" />
+<link rel="stylesheet" href="{{ STATIC_URL }}chimere/css/form-compat.css" />
+<link rel="stylesheet" href="{{ STATIC_URL }}chimere/css/extra-styles.css" />
+<script src="{{ STATIC_URL }}bootstrap/bootstrap.min.js" type="text/javascript"></script>
+ <script type='text/javascript'>
+ var has_search = {% if has_search %}true{% else %}false{% endif %};
+ </script>
+<script src="{{ STATIC_URL }}chimere/js/interface.js" type="text/javascript"></script>
+{% endblock %}
+{% block header %}
+<noscript>
+ <div id="no-js-message">
+ <p id='no-js' class='warning'>{% trans "You must enable JavaScript in your browser to display Chimère."%}</p>
+ </div>
+</noscript>
+ {% block page_title %}{% endblock %}
+ {% block actions %}
+ {% include "chimere/blocks/actions.html" %}
+ {% endblock %}
+{% endblock %}
+{% block content %}
+ {% block top %}{% endblock %}
+ {% block message_map %}{% endblock %}
+ {% block message_edit %}{% endblock %}
+ {% block bottom %}{% endblock %}
+{% endblock %}
+{% block footer %}
+ {% include "chimere/blocks/footer.html" %}
+{% endblock %}
+
diff --git a/chimere_example_project/templates/chimere/blocks/actions.html b/chimere_example_project/templates/chimere/blocks/actions.html
new file mode 100644
index 0000000..e31e1cc
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/actions.html
@@ -0,0 +1,61 @@
+{% load i18n chimere_tags %}<div class="navbar navbar-default navbar-fixed-top">
+ <div class="container">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ </div>
+ <div class="navbar-collapse collapse">
+
+ <div class='navbar-left'>
+ <ul class="nav nav-pills">
+ {% for action, subactions in actions %}
+ {% ifequal action.id action_selected.0 %}{% if subactions %}
+ {% for subaction in subactions %}
+ <li{% ifequal subaction.id action_selected.1 %} class='active'{% endifequal %}>
+ <a href='{{ subaction.url }}' onclick='saveExtent();'>{{ subaction.label }}</a>
+ </li>
+ {% endfor %}
+ {% endif %}{% endifequal %}
+ {% endfor %}
+ {% if is_map %}
+ <li id='categories-lnk'{% if not has_search %} class='active'{%endif%}><a href='#categories' data-toggle='panel'><span class='fa fa-chimere-action fa-check-circle-o'></span> {% trans "Categories "%}</a></li>
+ {% if has_search %}
+ <li id='search-lnk' class='active'><a href='#search-box' data-toggle='panel'><span class="glyphicon glyphicon-search"></span> {% trans "Search" %}</a></li>
+ {% endif %}
+ {% if areas_visible %}
+ <li id='maps-lnk'><span class='fa fa-chimere-action fa-chimere-maps'></span>{% display_areas %}</li>
+ {% endif %}
+ {% comment %}OL3-TODO<li id='permalink-lnk'><span class='fa fa-chimere-action fa-bookmark'></span><span id='permalink'></span></li>{% endcomment %}
+ <li>{% routing %}</li>
+ <li id='news-lnk'>
+ <a data-toggle='modal' data-target="#news" href='#' id='news_button'><span class='fa fa-chimere-action fa-newspaper-o'></span><span class='lbl'>{% trans "News"%}</span></a>
+ </li>
+ <!-- <li id="simple_button-lnk"><a id='simple_button' href='{% url chimere:simple_index area_name_slash %}'><span class='fa fa-chimere-action fa-simplybuilt'></span><span class='lbl'> {% trans "Simple map" %}</span></a></li> -->
+ <li class='selection-sep'> </li>
+ {% endif %}
+ </ul>
+ </div>
+
+ <div class='navbar-right'>
+
+ <ul class="nav navbar-nav">
+ <li class='selection-sep'> </li>
+ {% for action, subactions in actions %}
+ <li id='{{action.id}}-lnk'{% ifequal action.id action_selected.0 %} class="active"{% endifequal %}>
+ <a href='{{ action.url }}' onclick='jQuery("#map").chimere("saveExtent");'>
+ <span class='fa fa-chimere-action fa-chimere-{{action.id}}'></span>
+ <span class='lbl'>{{ action.label }}</span>
+ </a>
+ </li>
+ {% endfor %}
+ </ul>
+
+ </div>
+
+ </div>
+ </div>
+</div>
+
diff --git a/chimere_example_project/templates/chimere/blocks/categories.html b/chimere_example_project/templates/chimere/blocks/categories.html
new file mode 100644
index 0000000..9ef4e29
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/categories.html
@@ -0,0 +1,32 @@
+{% load i18n %}
+<ul id='ul_categories'>
+ {% for category, lst_sub_categories in sub_categories %}
+ <li class='main_category'>
+ <img class="control_image toggle_category" id="maincategory_img_{{category.id}}" alt="control" src="{{ STATIC_URL }}chimere/img/{% if category.selected %}minus.png{% else %}plus.png{% endif %}" />
+ <input type="checkbox" id='checkall_{{category.id}}'>
+ <span class='category_name'>{% trans category.name %}</span>
+ <span class="glyphicon glyphicon-zoom-in zoom_image zoom_to_category" id="zoom_to_category_{{category.id}}"></span>
+ <ul class='subcategories' id='maincategory_{{category.id}}'{% if not category.selected %} style='display:None'{% endif %}>
+ {% for sub_category in lst_sub_categories %}
+ <li id='li_sub_{{sub_category.id}}' class='subcategory'>
+ <input type='checkbox' name='category_{{sub_category.id}}' id='category_{{sub_category.id}}'{% if sub_category.selected %} checked='checked'{% endif %}/>
+ <label for='category_{{sub_category.id}}'>
+ <span class='cat_image'><img alt='{{ sub_category.name }}' src='{{ MEDIA_URL }}{{sub_category.icon.image}}'/></span>
+ {% trans sub_category.name %}
+ </label>
+ <span class="glyphicon glyphicon-zoom-in zoom_image zoom_to_subcategory" id="zoom_to_subcategory_{{sub_category.id}}"></span>
+ </li>
+ {% endfor %}
+ {% if category.description %}
+ <li><a href="#" onclick="$('#map').chimere('category_detail', {{category.id}});">{% trans "Tell me more..." %}</a></li>
+ {% endif %}
+ </ul>
+ </li>
+ {% endfor %}
+ {% if sub_categories %}
+ <li id='display_submited'>
+ <input type='checkbox' name='display_submited' id='display_submited_check'/> {% trans "Display markers and routes waiting for validation"%}
+ </li>
+ {% endif %}
+</ul>
+
diff --git a/chimere_example_project/templates/chimere/blocks/map.html b/chimere_example_project/templates/chimere/blocks/map.html
new file mode 100644
index 0000000..aec1e9a
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/map.html
@@ -0,0 +1,122 @@
+{% load i18n %}
+<div id='category_description' class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="{% trans "Close" %}"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="category_description-label"></h4>
+ </div>
+ <div class="modal-body" id="category_description-content">
+ </div>
+ </div>
+ </div>
+</div>
+
+<div id='{{map_id}}'></div>
+<script type="text/javascript">
+$("#{{map_id}}").show();
+$(function(){
+ $('#cluster_list').dialog({'autoOpen':false,
+ 'resizable':false,
+ 'width':340,
+ 'dialogClass':'no-titlebar'});
+});
+</script>
+<div id="waiting">
+ <div id="waiting-content">
+ <img alt='Ajax loader' src='{{STATIC_URL}}chimere/img/ajax-loader.gif'/>
+ </div>
+</div>
+<div id="layer_selection">
+ <h4>{% trans "Display options" %}</h4>
+ <ul id='layer_list'>
+ <li class='head layer_map_type'>{% trans "Map type"%}</li>
+ </ul>
+</div>
+<script type="text/javascript">
+ {% if not display_category_menu %}
+ $(function() {
+ $('#panel').hide();
+ $(".show-hide-panel").hide();
+ $("#categories-lnk").hide();
+ });{% endif %}
+ {{extra_js|safe}}
+ var chimere_init_options = {};
+ {% if MOBILE %}chimere_init_options["mobile"] = true;{% endif %}
+ {% if enable_clustering %}chimere_init_options["enable_clustering"] = true;{% endif %}
+ chimere_init_options["default_icon"] = '{{STATIC_URL}}img/marker-green.png';
+ {% if js_map_layers %}chimere_init_options["map_layers"] = [{{js_map_layers|safe|escape}}];{% endif %}
+ chimere_init_options['permalink_label'] = '{%trans "Permalink"%}';
+ chimere_init_options['permalink_element'] = document.getElementById('permalink');
+ chimere_init_options['routing'] = {{routing}};
+ {% if dynamic_categories %}chimere_init_options['dynamic_categories'] = true;{% endif %}
+ {% if default_area %}
+ chimere_init_options["default_area"] = new Array({{default_area.upper_left_corner.x}}, {{default_area.upper_left_corner.y}}, {{default_area.lower_right_corner.x}}, {{default_area.lower_right_corner.y}});
+ {% endif %}
+ {% if p_zoom %}chimere_init_options["zoom"] = {{ p_zoom }};{% endif %}
+ {% if p_lat %}chimere_init_options["lat"] = {{ p_lat }};{% endif %}
+ {% if p_lon %}chimere_init_options["lon"] = {{ p_lon }};{% endif %}
+ {% if p_routing_start_lon %}chimere_init_options["routing_start_lon"] = {{ p_routing_start_lon }};{% endif %}
+ {% if p_routing_start_lat %}chimere_init_options["routing_start_lat"] = {{ p_routing_start_lat }};{% endif %}
+ {% if p_routing_end_lon %}chimere_init_options["routing_end_lon"] = {{ p_routing_end_lon }};{% endif %}
+ {% if p_routing_end_lat %}chimere_init_options["routing_end_lat"] = {{ p_routing_end_lat }};{% endif %}
+ {% if p_routing_steps %}chimere_init_options["routing_steps_lonlat"] = [{{ p_routing_steps }}];{% endif %}
+ //chimere_init_options["icon_offset"] = new OpenLayers.Pixel({{icon_offset_x}},
+ // {{icon_offset_y}});
+ chimere_init_options["icon_offset"] = ({{icon_offset_x}}, {{icon_offset_y}});
+ chimere_init_options["dynamic_categories"] = {{ dynamic_categories }};
+ {% if p_display_submited %}chimere_init_options["display_submited"] = {{ p_display_submited }};{% endif %}
+ chimere_init_options["checked_categories"] = [{% for cc in checked_categories %}{% if forloop.counter0 > 0 %}, {% endif %}{{cc}}{% endfor %}];
+ {% if area_id %}chimere_init_options['area_id'] = "{{area_id}}";{% endif %}
+ {% if p_current_feature %}
+ chimere_init_options["display_feature"] = {{ p_current_feature }};{% endif %}
+ {% if p_current_route %}
+ chimere_init_options["display_route"] = {{ p_current_route }};{% endif %}
+ {% if restricted_extent %}{{ restricted_extent }}
+ chimere_init_options["restricted_extent"] = bounds;
+ {% endif %}
+ {% if selected_map_layer %}
+ chimere_init_options["selected_map_layer"] = {{selected_map_layer}};
+ {% endif %}
+
+ $('#category_description').modal({show:false});
+ chimere_init_options["open_dialog_fx"] = function (title, content){
+ $('#category_description-content').html(content);
+ $('#category_description-label').html(title);
+ $('#category_description').modal('show');
+ }
+ $("#main-map").chimere(chimere_init_options);
+ {% if zoom %}
+ $('#maps').chimere('zoom', {'area':{{zoom}} });
+ {% endif %}
+
+ {{extra_map_def|safe}}
+
+ // init layer selection
+ /* $(function() {
+ {% for layer_name, js, def in map_layers %}
+ $('#layer_list').append("<li><input type='radio' value='{{forloop.counter0}}' name='layer_type' id='layer_{{forloop.counter}}'{% if def %} checked='checked'{% endif %}><label for='layer_{{forloop.counter}}'>{{layer_name}}</li>");{% endfor %}
+ {% for subcat in subcat_layer %}
+ {% if not subcat.category %}
+ $('#layer_list').append("<li class='head layer_category'>{{subcat.name}}</li>");{% else %}
+ $('#layer_list').append("<li><input type='checkbox' name='layer_cat' value='category_{{subcat.pk}}' id='layer_cat_{{subcat.pk}}'{% if subcat.pk in checked_categories %} checked='checked'{% endif %}><label for='layer_cat_{{subcat.pk}}'>{{subcat.name}}</li>");{%endif%}{% endfor %}
+ $('#layer_selection h4').click(function(){
+ $('#layer_list').toggle();
+ });
+ $('#layer_list input[name=layer_type]').change(function(){
+ $('#{{map_id}}').chimere('changeMapLayer', $(this).val());
+ });
+ $('#layer_list input[name=layer_cat]').change(function(){
+ // the prop has to be called twice not to mess up with the triggered
+ // click
+ $('#'+$(this).val()).prop("checked", this.checked);
+ $('#'+$(this).val()).trigger('click');
+ $('#'+$(this).val()).prop("checked", this.checked);
+ });
+ highlight_selected_categories();
+ });
+ */
+</script>
+<div id='marker_hover'><div id='marker_hover_content'></div></div>
+<div id='cluster_list'></div>
+
diff --git a/chimere_example_project/templates/chimere/blocks/news.html b/chimere_example_project/templates/chimere/blocks/news.html
new file mode 100644
index 0000000..3f4d9ae
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/news.html
@@ -0,0 +1,62 @@
+{% load i18n sanitize chimere_tags %}
+{% if news_lst %}
+<script type='text/javascript'>
+$(function(){
+ // $('#news div.media-player').jmeEmbedControls();
+ $('#news video').each(function(index){$(this).pause()});
+ $('#news audio').each(function(index){$(this).pause()});
+ {% if display %}$('#news').modal('show');{%endif%}
+});
+</script>
+
+<div class="modal fade" id="news" tabindex="-1" role="dialog" aria-labelledby="news-label" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="news-label">{% trans "Upcoming events" %}</h4>
+ </div>
+ <div class="modal-body">
+ <div id='news_content'>
+ {% if welcome_message %}
+ <div id='welcome_message'>
+ {{welcome_message|safe}}
+ </div>
+ {% endif %}
+ <div class='news'>
+ {% if news_lst %}
+ {% for news in news_lst %}
+ <div class='info'>
+ {% if news.title %}
+ <h3>{{news.title}} &ndash; {{ news.date }}</h3>
+ <p>{{news.content|safe}}</p>
+ {% else %}
+ <h3>{{news.name}} &ndash; {{ news.start_date }}{% if news.end_date and news.end_date != news.start_date %} &ndash; {{ news.end_date }}{% endif %}</h3>
+ {% if news.default_pictures or news.default_pictures or news.default_multimedia_items%}
+ <div class='small-gallery'>
+ {% for picture in news.default_pictures %}
+ {% multimedia_render picture %}
+ {%endfor%}
+ {% for multimedia_item in news.default_multimedia_items %}
+ {% multimedia_render multimedia_item %}
+ {%endfor%}
+ </div>
+ {%endif%}
+ {% if news.description %}
+ <p class='description'>{{news.description|sanitize:"p b i br hr strong em span:style a:href:target ul li ol h1 h2 h3 h4 table td th tr"|safe}}</p>
+ {% endif %}
+ {% for property in news.getProperties %}
+ <p class='{{news.propertymodel.getNamedId}}'>{{ property.value|sanitize:"p b i br hr strong em span:style a:href:target ul li ol h1 h2 h3 h4 table td th tr"|safe }}</p>
+ {% endfor %}
+ <p class='marker_link'><a href='{% get_tinyfied_url news area_name %}'>{% trans "See it on the map"%}</a></p>
+ {% endif %}
+ </div>
+ {%endfor%}
+ {% endif %}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{% endif %}
diff --git a/chimere_example_project/templates/chimere/blocks/overload_templates_here b/chimere_example_project/templates/chimere/blocks/overload_templates_here
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/overload_templates_here
diff --git a/chimere_example_project/templates/chimere/blocks/share_bar.html b/chimere_example_project/templates/chimere/blocks/share_bar.html
new file mode 100644
index 0000000..5367628
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/share_bar.html
@@ -0,0 +1,39 @@
+{% load i18n %}
+ {% if share_networks %}
+ {% if simple %}{% trans "Share on"%}{% for share_network in share_networks %}
+ <a href='{{share_network.1}}'>{{share_network.0}}</a>
+ {% endfor %}{%else%}
+ <ul class='share'>
+ <li>{% trans "Share"%}</li>{% for share_network in share_networks %}
+ <li><a class='share_link share_id_{{share_network.0}}' href='{{share_network.1}}'><span class='fa fa-chimere fa-chimere-{{share_network.0}}'></span></a></li>
+ {% endfor %}</ul>{% endif %}
+ <script language='text/javascript'>
+ $(function(){
+ $('.share_link').click(function(){
+ var href = $(this).attr('href');
+ var url = '{% url chimere:get-share-url %}';
+ var classes = $(this).attr('class').split(' ');
+ prefix = 'share_id_';
+ var share_id;
+ for (idx=0;idx<classes.length;idx++){
+ if(classes[idx].substring(0, prefix.length) == prefix){
+ var share_id = classes[idx].substring(prefix.length);
+ }
+ }
+ var params = $('#permalink a').attr('href').split('/');
+ url += share_id + params[params.length-1];
+ $.ajax({url: url,
+ dataType: "html",
+ success: function (url) {
+ window.open(url);
+ return false;
+ },
+ error: function(){
+ return false;
+ }
+ });
+ return false;
+ });
+ });
+ </script>
+ {% endif %}
diff --git a/chimere_example_project/templates/chimere/blocks/welcome.html b/chimere_example_project/templates/chimere/blocks/welcome.html
new file mode 100644
index 0000000..a1dfb56
--- /dev/null
+++ b/chimere_example_project/templates/chimere/blocks/welcome.html
@@ -0,0 +1,62 @@
+{% load i18n sanitize chimere_tags %}
+{% if news_lst or welcome_message %}
+<script type='text/javascript'>
+$(function(){
+ //$('#welcome div.media-player').jmeEmbedControls();
+ $('#welcome video').each(function(index){$(this).pause()});
+ $('#welcome audio').each(function(index){$(this).pause()});
+ {% if display %}$('#welcome').modal('show');{%endif%}
+});
+</script>
+
+<div class="modal fade" id="welcome" tabindex="-1" role="dialog" aria-labelledby="welcome-label" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="welcome-label">{% trans "Upcoming events" %}</h4>
+ </div>
+ <div class="modal-body">
+ <div id='news_content'>
+ {% if welcome_message %}
+ <div id='welcome_message'>
+ {{welcome_message|safe}}
+ </div>
+ {% endif %}
+ <div class='news'>
+ {% if news_lst %}{% for news in news_lst %}
+ <div class='info'>
+ {% if news.title %}
+ <h3>{{news.title}} &ndash; {{ news.date }}</h3>
+ <p>{{news.content|safe}}</p>
+ {% else %}
+ <h3>{{news.name}} &ndash; {{ news.start_date }}{% if news.end_date %} - {{ news.end_date }}{% endif %}</h3>
+ {% if news.default_pictures or news.default_pictures or news.default_multimedia_items%}
+ <div class='small-gallery'>
+ {% for picture in news.default_pictures %}
+ {% multimedia_render picture %}
+ {%endfor%}
+ {% for multimedia_item in news.default_multimedia_items %}
+ {% multimedia_render multimedia_item %}
+ {%endfor%}
+ </div>
+ {%endif%}
+ {% if news.description %}
+ <p class='description'>{{news.description|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td th tr"|safe}}</p>
+ {% endif %}
+ {% for property in news.getProperties %}
+ <p class='{{news.propertymodel.getNamedId}}'>{{ property.value|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td th tr"|safe }}</p>
+ {% endfor %}
+ <p class='marker_link'><a href='{% get_tinyfied_url news area_name %}'>{% trans "See it on the map"%}</a></p>
+ {% endif %}
+ </div>
+ {%endfor%}{% endif %}
+ <div class='info'>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{% endif %}
diff --git a/chimere_example_project/templates/chimere/detail.html b/chimere_example_project/templates/chimere/detail.html
new file mode 100644
index 0000000..91b8e49
--- /dev/null
+++ b/chimere_example_project/templates/chimere/detail.html
@@ -0,0 +1,150 @@
+{% load i18n sanitize chimere_tags %}
+<div id='detail-wrapper'>
+<button onclick='$("#detail").fadeOut();return false;' type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
+<h2>{{ marker.name }}</h2>
+<div class='detail_content'>
+ {% if marker.default_pictures or marker.default_pictures or marker.default_multimedia_items%}
+ <div class='small-gallery'>
+ {% for picture in marker.default_pictures %}
+ {% multimedia_render picture %}
+ {%endfor%}
+ {% for multimedia_item in marker.default_multimedia_items %}
+ {% multimedia_render multimedia_item %}
+ {%endfor%}
+ </div>
+ {%endif%}
+<div>
+ {% if dated %}
+ <p class='detail_start_date'><label>{% trans "Date:" %}</label> <span>{{marker.start_date|date:"D d M Y"}}
+ {% if marker.end_date %} - {{marker.end_date|date:"D d M Y"}}</p>{% endif %}</span>
+ {% endif %}
+ {% if marker.description %}
+ <p class='description'>{{ marker.description|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td tr th"|safe}}</p>
+ {% endif %}
+ {% for property in properties %}
+ <p class='{{property.propertymodel.getNamedId}}'><strong>{{property.propertymodel}}</strong>{% trans ":" %} {{ property.value|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td tr th"|safe}}</p>
+ {% endfor %}
+ {% if marker.origin %}<p class='detail_source'><strong>{% trans "Source:" %}</strong> <span>{{marker.origin}}</span></p>{% endif %}
+ {% if marker.license %}<p class='detail_license'><strong>{% trans "License:" %}</strong> <span>{{marker.license}}</span></p>{% endif %}
+ {% if marker.multimedia_items %}<p class='detail_multimedia'>
+ <a data-toggle='modal' data-target="#multimedia-gallery-{{time_now}}" href='#' id='multimedia-gallery-button'><span class='fa fa-chimere-action fa-camera'></span> <span class='lbl'>{% trans "Show the gallery"%}</span></a>
+ </p>{% endif %}
+ </div>
+ {% share_bar marker.name %}
+ <p class='detail_amendment'><a href='{% if marker.polygon %}{% url chimere:editpolygon-item area_name_slash|default_if_none:"" marker.pk "" %}{% else %}{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{% else %}{% url chimere:editmarker-item area_name_slash|default_if_none:"" marker.pk "" %}{% endif %}{% endif %}'>
+ {% trans "Submit an amendment" %}
+ </a>
+ {% if moderator_emails %}
+ <a href="mailto:?from={{moderator_emails}}&subject={% trans "Propose amendment" %}&body={% trans "I would like to propose an amendment for this item:"%} {{share_url}}">
+ {% trans "Propose amendment" %}
+ </a>{%endif%}
+ </p>
+</div>
+</div>
+
+
+{% if marker.multimedia_items %}
+<div class="modal fade" id="multimedia-gallery-{{time_now}}" tabindex="-1" role="dialog" aria-labelledby='multimedia-gallery-label' aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="multimedia-gallery-label">{% trans "Gallery" %}</h4>
+ </div>
+ <div class="modal-body">
+
+<div role="tabpanel">
+
+ <ul class="nav nav-pills" role="tablist" id="pills-{{time_now}}">
+ {% for item in marker.multimedia_items %}
+ <li role="presentation"{% if forloop.counter0 == 0%} class="active"{% endif %}>
+ <a href="#tab-{{time_now}}-{{ forloop.counter }}" aria-controls="tab-{{time_now}}-{{ forloop.counter }}" role="tab" data-toggle="pill">
+ {{ item.name }}
+ </a>
+ </li>{% endfor %}
+ </ul>
+
+ <div class="tab-content">
+ {% for multimedia_item in marker.multimedia_items %}
+ <div id="tab-{{time_now}}-{{ forloop.counter }}" role="tabpanel" class="tab-pane{% if forloop.counter0 == 0%} active{% endif %} {% ifequal multimedia_item.multimedia_type.media_type 'V' %}video{% else %}other{% endifequal %}" id="home">
+ {% multimedia_render multimedia_item %}
+ </div>
+ {% endfor %}
+ </div>
+
+</div>
+
+ </div>
+ </div>
+ </div>
+</div>
+
+
+
+<div id='gallery-{{time_now}}' class='gallery'>
+</div>
+{% endif %}
+
+<script language='javascript' type='text/javascript'>
+$('html').addClass('js-on');
+
+
+function manage_tab_opening (event, ui) {
+ //pause all medias
+ $('video').each(function(index){$(this).pause()});
+ $('audio').each(function(index){$(this).pause()});
+ //start current tabvideo
+ $('ui.panel video').each(function(index){
+ //prevents a Flash-Bug in IE with newest Flash-Player
+ $(this).reinitMedia({queue: true})
+ .play()
+ ;});
+ $('ui.panel audio').each(function(index){
+ //prevents a Flash-Bug in IE with newest Flash-Player
+ $(this).reinitMedia({queue: true})
+ .play()
+ ;});
+}
+
+function manage_gallery_opening (event) {
+ // $('div.media-player').jmeEmbedControls();
+ $('.video div.media-player').bind('useractive', function(){
+ $('div.media-controls', this).stop().animate({opacity: 1});
+ }).bind('userinactive', function(){
+ $('div.media-controls', this).stop().animate({opacity: 0});
+ });
+ //$("#gallery-{{time_now}}").dialog("option", "height", 'auto');
+ //$("#gallery-{{time_now}}").dialog("option", "width", 'auto');
+ //$("#gallery-{{time_now}}").dialog("option", "position",
+ // ['center', 'center']);
+}
+
+function manage_gallery_close (event){
+ //pause all medias
+ $('video').each(function(index){$(this).pause()});
+ $('audio').each(function(index){$(this).pause()});
+}
+
+$(document).ready(function(){
+
+ $('#multimedia-gallery-{{time_now}}').on('shown.bs.modal', function (e) {
+ manage_gallery_opening();
+ manage_tab_opening(e);
+ })
+
+ $('#multimedia-gallery-{{time_now}}').on('hide.bs.modal', function (e) {
+ manage_gallery_close();
+ })
+
+ $('a[data-toggle="pill"]').on('shown.bs.tab', function (e) {
+ manage_tab_opening(e);
+ })
+
+ // $('div.media-player').jmeEmbedControls();
+ $("a[rel^='prettyPhoto']").prettyPhoto({
+ show_title: false,
+ social_tools: ''
+ });
+
+});
+</script>
diff --git a/chimere_example_project/templates/chimere/main_map.html b/chimere_example_project/templates/chimere/main_map.html
new file mode 100644
index 0000000..856bcdc
--- /dev/null
+++ b/chimere_example_project/templates/chimere/main_map.html
@@ -0,0 +1,54 @@
+{% extends "chimere/base.html" %}
+{% load i18n unlocalize_point chimere_tags %}
+{% block extra_head %}
+{% head_jquery %}
+{% head_chimere %}
+{% head_jme %}
+<script src="{{ STATIC_URL }}chimere/js/jquery.chimere.js" type="text/javascript"></script>
+{% if has_search %}
+<script src="{{ STATIC_URL }}chimere/js/search.js" type="text/javascript"></script>
+<script src="{{ STATIC_URL }}chimere/js/search-autocomplete.js" type="text/javascript"></script>{% endif %}
+{{ block.super }}
+{% endblock %}
+{% block message_edit %}{% endblock %}
+{% block sidebar %}
+{% display_news %}
+ <div class='show-hide-panel' id='hide-panel'><span class='fa fa-arrow-circle-left'></span></div>
+ <div class='show-hide-panel' id='show-panel'><span class='fa fa-arrow-circle-right'></span></div>
+ <div id='panel' class='navbar-default'>
+ <form id="frm_categories"><div id='categories'></div></form>
+ <div id='search-box' class='ui-widget ui-corner-all'></div>
+ </div>
+ <div id='category_description'>
+ </div>
+ <script type='text/javascript'>
+ $(function(){$('#category_description').dialog({'autoOpen':false});});
+ </script>
+ <div id='detail'></div>
+{% endblock %}
+{% block search_box %} {% endblock %}
+{% block content %}
+ {{block.super}}
+ <div id='popup'></div>
+ <div id='layerSwitcher'></div>
+ <div id='main-map'></div>
+<script type="text/javascript">
+ $("#main-map").show();
+</script>
+ {% map_menu %}
+ {% map 'main-map' %}
+ <script type='text/javascript'>
+ // array to keep trace of already displayed items
+ var search_result = new Array();
+ var search_url = "/search/";
+ $(function(){
+ if (has_search){
+ load_search_box();
+ }
+ {%if news_visible %}$('#news').modal();{% endif %}
+ });
+ </script>
+{% endblock %}
+{% block footer %}
+ <p class='map-footer'>{% include "chimere/blocks/footer.html" %}</p>
+{% endblock %}
diff --git a/chimere_example_project/templates/chimere/overload_templates_here b/chimere_example_project/templates/chimere/overload_templates_here
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chimere_example_project/templates/chimere/overload_templates_here
diff --git a/chimere_example_project/templates/overload_templates_here b/chimere_example_project/templates/overload_templates_here
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chimere_example_project/templates/overload_templates_here
diff --git a/chimere_example_project/urls.py b/chimere_example_project/urls.py
new file mode 100644
index 0000000..fff1366
--- /dev/null
+++ b/chimere_example_project/urls.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2012-2013 Etienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# See the file COPYING for details.
+
+from django.conf import settings
+from django.conf.urls.defaults import *
+
+from django.contrib import admin
+from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+
+admin.autodiscover()
+urlpatterns = patterns('django.views.static',
+ (r'^%s(?P<path>.*)' % settings.MEDIA_URL[1:], 'serve',
+ {'document_root': settings.MEDIA_ROOT}),
+)
+
+if "tinymce" in settings.INSTALLED_APPS:
+ urlpatterns += patterns('django.views.static',
+ (r'^tinymce/', include('tinymce.urls')),)
+
+urlpatterns += staticfiles_urlpatterns()
+
+urlpatterns += patterns('',
+ (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+ (r'^admin/', include(admin.site.urls)),
+ url(r'^', include('chimere.urls', namespace="chimere")),
+)
+
+
diff --git a/chimere_example_project/wsgi.py b/chimere_example_project/wsgi.py
new file mode 100644
index 0000000..093cc8a
--- /dev/null
+++ b/chimere_example_project/wsgi.py
@@ -0,0 +1,11 @@
+import os, sys
+
+MAIN_PATH = os.path.realpath(os.path.dirname(__file__)) + "/.."
+sys.path.append(MAIN_PATH)
+if not "DJANGO_SETTINGS_MODULE" in os.environ or \
+ not os.environ['DJANGO_SETTINGS_MODULE']:
+ # change with your project name
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'mychimere_project.settings'
+import django.core.handlers.wsgi
+application = django.core.handlers.wsgi.WSGIHandler()
+